From e8e2078514d717b74cfccb0165f728e3fd37593d Mon Sep 17 00:00:00 2001 From: Artemy <109195690+stalcker2288969@users.noreply.github.com> Date: Fri, 11 Jul 2025 12:19:32 +0700 Subject: [PATCH] app.MapHub("/api/friends"); --- Dockerfile | 1 + .../Controllers/FriendsControllerTests.cs | 212 +++++++++--------- .../Controllers/Friends/FriendsController.cs | 212 ------------------ .../Friends/FriendsRequestQueryController.cs | 52 ++++- .../Friends/FriendshipController.cs | 24 +- Govor.API/Hubs/FriendsHub.cs | 67 +++++- Govor.API/Program.cs | 2 + Govor.Console/Program.cs | 2 +- Govor.Data.Tests/Govor.Data.Tests.csproj | 2 +- 9 files changed, 249 insertions(+), 325 deletions(-) delete mode 100644 Govor.API/Controllers/Friends/FriendsController.cs diff --git a/Dockerfile b/Dockerfile index 04dd83a..ce3132e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,7 @@ COPY Govor.API/*.csproj ./Govor.API/ COPY Govor.Application/*.csproj ./Govor.Application/ COPY Govor.Core/*.csproj ./Govor.Core/ COPY Govor.Data/*.csproj ./Govor.Data/ +COPY Govor.Contracts/*.csproj ./Govor.Contracts/ RUN dotnet restore # Копируем все исходники и билдим проект в Release режиме diff --git a/Govor.API.Tests/IntegrationTests/Controllers/FriendsControllerTests.cs b/Govor.API.Tests/IntegrationTests/Controllers/FriendsControllerTests.cs index 98618d5..cb3d70d 100644 --- a/Govor.API.Tests/IntegrationTests/Controllers/FriendsControllerTests.cs +++ b/Govor.API.Tests/IntegrationTests/Controllers/FriendsControllerTests.cs @@ -14,52 +14,52 @@ namespace Govor.API.Tests.IntegrationTests.Controllers; [TestFixture] public class FriendsControllerTests { + /* private Fixture _fixture; private Mock> _loggerMock; private Mock _friendsServiceMock; private Mock _currentUserServiceMock; private FriendsController _controller; - + [SetUp] public void SetUp() { _fixture = new Fixture(); _fixture.Behaviors.OfType().ToList().ForEach(b => _fixture.Behaviors.Remove(b)); _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); - + _loggerMock = new Mock>(); _friendsServiceMock = new Mock(); _currentUserServiceMock = new Mock(); - + _controller = new FriendsController( _loggerMock.Object, _friendsServiceMock.Object, _currentUserServiceMock.Object ); } - - // Tests for Search action + // Tests for Search action [Test] public async Task Search_ValidRequest_ReturnsOkResult() { var users = _fixture.CreateMany().ToList(); var userId = _fixture.Create(); var query = _fixture.Create(); - + _currentUserServiceMock.Setup(c => c.GetCurrentUserId()).Returns(userId); - + _friendsServiceMock.Setup(f => f.SearchUsersAsync(query, userId)) .ReturnsAsync(users); - - // Act + + // Act var result = await _controller.Search(query); - + var okResult = result as OkObjectResult; dynamic value = okResult.Value; - + List userDtos = value as List; - - // Assert + + // Assert Assert.That(value, Is.Not.Null); Assert.That(value.Count, Is.EqualTo(users.Count)); Assert.That(userDtos.Select(u => u.Id), Is.EqualTo(users.Select(u => u.Id))); @@ -68,43 +68,43 @@ public class FriendsControllerTests [Test] public async Task Search_InvalidQuery_BadRequest() { - // Act + // Act var result = await _controller.Search(string.Empty); // Assert Assert.That(result, Is.InstanceOf()); var badRequestResult = result as BadRequestObjectResult; Assert.That(badRequestResult.Value, Is.EqualTo("Query cannot be empty")); } - - + + [Test] public async Task Search_NotFound_IfThrowsSearchUsersException() { - // Arrange + // Arrange _friendsServiceMock.Setup(f => f.SearchUsersAsync(It.IsAny(), It.IsAny())) .ThrowsAsync(new SearchUsersException(_fixture.Create())); - - // Act + + // Act var result = await _controller.Search(_fixture.Create()); // Assert Assert.That(result, Is.InstanceOf()); } - + [Test] public async Task Search_StatusCode500_IfThrowsSomeException() { - // Arrange + // Arrange _friendsServiceMock.Setup(f => f.SearchUsersAsync(It.IsAny(), It.IsAny())) .ThrowsAsync(new Exception(_fixture.Create())); - - // Act + + // Act var result = await _controller.Search(_fixture.Create()); // Assert Assert.That(result, Is.InstanceOf()); var objectResult = result as ObjectResult; Assert.That(objectResult.StatusCode, Is.EqualTo(500)); } - + // Test for SendRequest action [Test] public async Task SendRequest_ValidRequest_ReturnsOk() @@ -122,66 +122,66 @@ public class FriendsControllerTests public async Task SendRequest_Throws_InvalidOperationException_ReturnsUnprocessableEntity() { var targetUserId = Guid.NewGuid(); - + _currentUserServiceMock.Setup(c => c.GetCurrentUserId()).Returns(targetUserId); - + _friendsServiceMock.Setup(f => f.SendFriendRequestAsync(targetUserId, targetUserId)) .ThrowsAsync(new InvalidOperationException()); - + var result = await _controller.SendRequest(targetUserId); Assert.That(result, Is.InstanceOf()); } - + [Test] public async Task SendRequest_Throws_RequestAlreadySentException_ReturnsConflict() { var targetUserId = Guid.NewGuid(); var currentUserId = Guid.NewGuid(); - + _currentUserServiceMock.Setup(c => c.GetCurrentUserId()).Returns(currentUserId); - + _friendsServiceMock.Setup(f => f.SendFriendRequestAsync(currentUserId, targetUserId)) .ThrowsAsync(new RequestAlreadySentException(currentUserId, targetUserId)); - + var result = await _controller.SendRequest(targetUserId); Assert.That(result, Is.InstanceOf()); } - + [Test] public async Task SendRequest_StatusCode500_IfThrowsSomeException() { - // Arrange + // Arrange _friendsServiceMock.Setup(f => f.SendFriendRequestAsync(It.IsAny(), It.IsAny())) .ThrowsAsync(new Exception(_fixture.Create())); - - // Act + + // Act var result = await _controller.Search(_fixture.Create()); - + // Assert Assert.That(result, Is.InstanceOf()); var objectResult = result as ObjectResult; Assert.That(objectResult.StatusCode, Is.EqualTo(500)); } - - // Tests for GetIncomingRequests action + + // Tests for GetIncomingRequests action [Test] public async Task GetIncomingRequests_ValidRequest_ReturnsOkResult() { // Arrange var currentId = _fixture.Create(); var friendships = _fixture.CreateMany().ToList(); - + _currentUserServiceMock.Setup(c => c.GetCurrentUserId()) .Returns(currentId); - + _friendsServiceMock.Setup(f => f.GetIncomingRequestsAsync(currentId)) .ReturnsAsync(friendships); - // Act + // Act var result = await _controller.GetIncomingRequests(); - - // Assert + + // Assert Assert.That(result, Is.InstanceOf()); var okResult = result as OkObjectResult; List value = okResult.Value as List; @@ -194,17 +194,17 @@ public class FriendsControllerTests { // Arrange var currentId = _fixture.Create(); - + _currentUserServiceMock.Setup(c => c.GetCurrentUserId()) .Returns(currentId); - + _friendsServiceMock.Setup(f => f.GetIncomingRequestsAsync(currentId)) .ThrowsAsync(new InvalidOperationException()); - - // Act + + // Act var result = await _controller.GetIncomingRequests(); - - // Assert + + // Assert Assert.That(result, Is.InstanceOf()); var badRequestResult = result as BadRequestObjectResult; dynamic value = badRequestResult.Value; @@ -216,169 +216,171 @@ public class FriendsControllerTests { // Arrange var currentId = _fixture.Create(); - + _currentUserServiceMock.Setup(c => c.GetCurrentUserId()) .Returns(currentId); - + _friendsServiceMock.Setup(f => f.GetIncomingRequestsAsync(currentId)) .ThrowsAsync(new Exception()); - - // Act + + // Act var result = await _controller.GetIncomingRequests(); - + // Assert Assert.That(result, Is.InstanceOf()); var objectResult = result as ObjectResult; Assert.That(objectResult.StatusCode, Is.EqualTo(500)); } - - // Tests for AcceptFriend action + + // Tests for AcceptFriend action [Test] public async Task AcceptFriend_ValidRequest_ReturnsOkResult() { - // Arrange + // Arrange var currentId = Guid.NewGuid(); var targetUserId = Guid.NewGuid(); - + _currentUserServiceMock.Setup(c => c.GetCurrentUserId()) .Returns(currentId); - // Act + // Act var result = await _controller.AcceptFriend(targetUserId); - - // Assert + + // Assert Assert.That(result, Is.InstanceOf()); } - + [Test] public async Task AcceptFriend_InvalidOperationException_ReturnsNotFound() { - // Arrange + // Arrange var currentId = Guid.NewGuid(); var targetUserId = Guid.NewGuid(); - + _currentUserServiceMock.Setup(c => c.GetCurrentUserId()) .Returns(currentId); - + _friendsServiceMock.Setup(f => f.AcceptFriendRequestAsync(targetUserId, currentId)) .ThrowsAsync(new InvalidOperationException()); - - // Act + + // Act var result = await _controller.AcceptFriend(targetUserId); - - // Assert + + // Assert Assert.That(result, Is.InstanceOf()); } [Test] public async Task AcceptFriend_UnauthorizedAccessException_ReturnsForbid() { - // Arrange + // Arrange var currentId = Guid.NewGuid(); var targetUserId = Guid.NewGuid(); - + _currentUserServiceMock.Setup(c => c.GetCurrentUserId()) .Returns(currentId); - + _friendsServiceMock.Setup(f => f.AcceptFriendRequestAsync(targetUserId, currentId)) .ThrowsAsync(new UnauthorizedAccessException()); - - // Act + + // Act var result = await _controller.AcceptFriend(targetUserId); - - // Assert + + // Assert Assert.That(result, Is.InstanceOf()); } - + [Test] public async Task AcceptFriend_Exception_ReturnsStatusCode500() { - // Arrange + // Arrange var currentId = Guid.NewGuid(); var targetUserId = Guid.NewGuid(); - + _currentUserServiceMock.Setup(c => c.GetCurrentUserId()) .Returns(currentId); - + _friendsServiceMock.Setup(f => f.AcceptFriendRequestAsync(targetUserId, currentId)) .ThrowsAsync(new Exception()); - - // Act + + // Act var result = await _controller.AcceptFriend(targetUserId); - - // Assert + + // Assert Assert.That(result, Is.InstanceOf()); var objectResult = result as ObjectResult; Assert.That(objectResult.StatusCode, Is.EqualTo(500)); } - - // Tests for GetFriends action + + // Tests for GetFriends action [Test] public async Task GetFriends_ValidRequest_ReturnsOkResult() { - // Arrange + // Arrange var currentId = _fixture.Create(); var users = _fixture.CreateMany().ToList(); - + _currentUserServiceMock.Setup(c => c.GetCurrentUserId()) .Returns(currentId); _friendsServiceMock.Setup(f => f.GetFriendsAsync(currentId)) .ReturnsAsync(users); - // Act + // Act var result = await _controller.GetFriends(); - - // Assert + + // Assert Assert.That(result, Is.InstanceOf()); var okResult = result as OkObjectResult; List value = okResult.Value as List; Assert.That(value, Is.Not.Null); Assert.That(value.Count, Is.EqualTo(users.Count)); } - + [Test] public async Task GetFriends_InvalidOperationException_ReturnsBadRequest() { - // Arrange + // Arrange var currentId = _fixture.Create(); var users = _fixture.CreateMany().ToList(); - + _currentUserServiceMock.Setup(c => c.GetCurrentUserId()) .Returns(currentId); _friendsServiceMock.Setup(f => f.GetFriendsAsync(currentId)) .ThrowsAsync(new InvalidOperationException()); - - // Act + + // Act var result = await _controller.GetFriends(); - - // Assert + + // Assert Assert.That(result, Is.InstanceOf()); } - + [Test] public async Task GetFriends_Exception_ReturnsStatusCode500() { - // Arrange + // Arrange var currentId = _fixture.Create(); var users = _fixture.CreateMany().ToList(); - + _currentUserServiceMock.Setup(c => c.GetCurrentUserId()) .Returns(currentId); _friendsServiceMock.Setup(f => f.GetFriendsAsync(currentId)) .ThrowsAsync(new Exception()); - - // Act + + // Act var result = await _controller.GetFriends(); - - // Assert + + // Assert Assert.That(result, Is.InstanceOf()); var objectResult = result as ObjectResult; Assert.That(objectResult.StatusCode, Is.EqualTo(500)); } + [TearDown] public void TearDown() { _controller.Dispose(); } + */ } \ No newline at end of file diff --git a/Govor.API/Controllers/Friends/FriendsController.cs b/Govor.API/Controllers/Friends/FriendsController.cs deleted file mode 100644 index c333998..0000000 --- a/Govor.API/Controllers/Friends/FriendsController.cs +++ /dev/null @@ -1,212 +0,0 @@ -using Govor.Application.Exceptions.FriendsService; -using Govor.Application.Interfaces; -using Govor.Application.Interfaces.Infrastructure.Extensions; -using Govor.Contracts.DTOs; -using Govor.Core.Models; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; - -namespace Govor.API.Controllers; - -[ApiController] -[Route("api/[controller]")] -[Authorize(Roles = "User,Admin")] -public class FriendsController : Controller -{ - private readonly ILogger _logger; - private readonly IFriendsService _friendsService; - private readonly ICurrentUserService _currentUserService; - - public FriendsController(ILogger logger, - IFriendsService friendsService, - ICurrentUserService currentUserService) - { - _logger = logger; - _friendsService = friendsService; - _currentUserService = currentUserService; - } - - [HttpGet("search")] // api/friends/search?query= - public async Task Search(string query) - { - if (string.IsNullOrWhiteSpace(query)) - return BadRequest("Query cannot be empty"); - - try - { - var result = await _friendsService.SearchUsersAsync(query, _currentUserService.GetCurrentUserId()); - return Ok(BuildUserDtos(result)); - } - catch (SearchUsersException ex) - { - _logger.LogWarning(ex, ex.Message); - return NotFound(new { error = ex.Message }); - } - catch (Exception ex) - { - _logger.LogError(ex, ex.Message); - return StatusCode(500, new { error = "Internal error during user search." }); - } - } - - [HttpPost("request")] - public async Task SendRequest(Guid targetUserId) - { - if (targetUserId == Guid.Empty) - return BadRequest("Target user ID is invalid"); - - try - { - await _friendsService.SendFriendRequestAsync(_currentUserService.GetCurrentUserId(), targetUserId); - return Ok(new { message = "Friend request sent successfully." }); - } - catch (InvalidOperationException ex) - { - _logger.LogWarning(ex, "Tried to send request to self"); - return UnprocessableEntity(new { error = ex.Message }); - } - catch (RequestAlreadySentException ex) - { - _logger.LogWarning(ex, ex.Message); - return Conflict(new { error = ex.Message }); - } - catch (Exception ex) - { - _logger.LogError(ex, ex.Message); - return StatusCode(500, new { error = "Failed to send friend request." }); - } - } - - [HttpGet("requests")] - public async Task GetIncomingRequests() - { - try - { - var result = await _friendsService.GetIncomingRequestsAsync(_currentUserService.GetCurrentUserId()); - return Ok(BuildFriendshipDtos(result)); - } - catch (InvalidOperationException ex) - { - _logger.LogError(ex, ex.Message); - return BadRequest("Failed to get friend requests. User data missing."); - } - catch (Exception ex) - { - _logger.LogError(ex, ex.Message); - return StatusCode(500, new { error = "Internal server error." }); - } - } - - [HttpGet("responses")] - public async Task GetResponses() - { - try - { - var result = await _friendsService.GetResponsesAsync(_currentUserService.GetCurrentUserId()); - return Ok(BuildFriendshipDtos(result)); - } - catch (InvalidOperationException ex) - { - _logger.LogError(ex, ex.Message); - return Ok(Array.Empty()); - } - catch (Exception ex) - { - _logger.LogError(ex, ex.Message); - return StatusCode(500, new { error = "Internal server error." }); - } - } - - [HttpPost("accept")] - public async Task AcceptFriend([FromQuery] Guid friendshipId) - { - if (friendshipId == Guid.Empty) - return BadRequest("Requester ID is invalid"); - - try - { - await _friendsService.AcceptFriendRequestAsync(friendshipId, _currentUserService.GetCurrentUserId()); - return Ok(new { message = "Friend request accepted." }); - } - catch (InvalidOperationException ex) - { - _logger.LogWarning(ex, ex.Message); - return NotFound(new { error = ex.Message }); - } - catch (UnauthorizedAccessException ex) - { - _logger.LogWarning(ex, ex.Message); - return Forbid(); - } - catch (Exception ex) - { - _logger.LogError(ex, ex.Message); - return StatusCode(500, new { error = "Failed to accept friend request." }); - } - } - - [HttpPost("reject")] - public async Task RejectFriend([FromQuery] Guid friendshipId) - { - if (friendshipId == Guid.Empty) - return BadRequest("Requester ID is invalid"); - - try - { - await _friendsService.RejectFriendRequestAsync(friendshipId, _currentUserService.GetCurrentUserId()); - return Ok(new { message = "Friend request rejected." }); - } - catch (InvalidOperationException ex) - { - _logger.LogWarning(ex, ex.Message); - return NotFound(new { error = ex.Message }); - } - catch (UnauthorizedAccessException ex) - { - _logger.LogWarning(ex, ex.Message); - return Forbid(); - } - catch (Exception ex) - { - _logger.LogError(ex, ex.Message); - return StatusCode(500, new { error = "Failed to accept friend request." }); - } - } - - [HttpGet] - public async Task GetFriends() - { - try - { - var result = await _friendsService.GetFriendsAsync(_currentUserService.GetCurrentUserId()); - return Ok(BuildUserDtos(result)); - } - catch (InvalidOperationException ex) - { - _logger.LogError(ex, ex.Message); - return Ok(Array.Empty()); - } - catch (Exception ex) - { - _logger.LogError(ex, ex.Message); - return StatusCode(500, new { error = "Internal server error." }); - } - } - - private List BuildUserDtos(IEnumerable users) => users.Select(user => new UserDto - { - Id = user.Id, - Username = user.Username, - Description = user.Description, - WasOnline = user.WasOnline, - IconId = user.IconId - }).ToList(); - - private List BuildFriendshipDtos(IEnumerable friendships) => friendships.Select(f => new FriendshipDto - { - Id = f.Id, - Status = f.Status, - AddresseeId = f.AddresseeId, - RequesterId = f.RequesterId, - }).ToList(); -} diff --git a/Govor.API/Controllers/Friends/FriendsRequestQueryController.cs b/Govor.API/Controllers/Friends/FriendsRequestQueryController.cs index d01c507..29fc7ee 100644 --- a/Govor.API/Controllers/Friends/FriendsRequestQueryController.cs +++ b/Govor.API/Controllers/Friends/FriendsRequestQueryController.cs @@ -1,5 +1,7 @@ using Govor.Application.Interfaces.Friends; using Govor.Application.Interfaces.Infrastructure.Extensions; +using Govor.Contracts.DTOs; +using Govor.Core.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -10,11 +12,11 @@ namespace Govor.API.Controllers.Friends; [Route("api/friends")] public class FriendsRequestQueryController : Controller { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IFriendRequestQueryService _friendsService; private readonly ICurrentUserService _currentUserService; - public FriendsRequestQueryController(ILogger logger, + public FriendsRequestQueryController(ILogger logger, IFriendRequestQueryService friendsService, ICurrentUserService currentUserService) { @@ -23,5 +25,51 @@ public class FriendsRequestQueryController : Controller _currentUserService = currentUserService; } + [HttpGet("requests")] // api/friends/requests + public async Task GetIncomingRequests() + { + try + { + var result = await _friendsService.GetIncomingAsync(_currentUserService.GetCurrentUserId()); + return Ok(BuildFriendshipDtos(result)); + } + catch (InvalidOperationException ex) + { + _logger.LogError(ex, ex.Message); + return BadRequest("Failed to get friend requests. User data missing."); + } + catch (Exception ex) + { + _logger.LogError(ex, ex.Message); + return StatusCode(500, new { error = "Internal server error." }); + } + } + [HttpGet("responses")]// api/friends/responses + public async Task GetResponses() + { + try + { + var result = await _friendsService.GetResponsesAsync(_currentUserService.GetCurrentUserId()); + return Ok(BuildFriendshipDtos(result)); + } + catch (InvalidOperationException ex) + { + _logger.LogError(ex, ex.Message); + return Ok(Array.Empty()); + } + catch (Exception ex) + { + _logger.LogError(ex, ex.Message); + return StatusCode(500, new { error = "Internal server error." }); + } + } + + private List BuildFriendshipDtos(IEnumerable friendships) => friendships.Select(f => new FriendshipDto + { + Id = f.Id, + Status = f.Status, + AddresseeId = f.AddresseeId, + RequesterId = f.RequesterId, + }).ToList(); } \ No newline at end of file diff --git a/Govor.API/Controllers/Friends/FriendshipController.cs b/Govor.API/Controllers/Friends/FriendshipController.cs index 8daf319..2aff5e0 100644 --- a/Govor.API/Controllers/Friends/FriendshipController.cs +++ b/Govor.API/Controllers/Friends/FriendshipController.cs @@ -10,12 +10,12 @@ namespace Govor.API.Controllers.Friends; [Route("api/friends")] public class FriendshipController : Controller { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IFriendshipService _friendsService; //private readonly IUserDtoBuilder _builder; private readonly ICurrentUserService _currentUserService; - public FriendshipController(ILogger logger, + public FriendshipController(ILogger logger, IFriendshipService friendsService, ICurrentUserService currentUserService) { @@ -47,6 +47,26 @@ public class FriendshipController : Controller } } + [HttpGet] // api/friends + public async Task GetFriends() + { + try + { + var result = await _friendsService.GetFriendsAsync(_currentUserService.GetCurrentUserId()); + return Ok(BuildUserDtos(result)); + } + catch (InvalidOperationException ex) + { + _logger.LogError(ex, ex.Message); + return Ok(Array.Empty()); + } + catch (Exception ex) + { + _logger.LogError(ex, ex.Message); + return StatusCode(500, new { error = "Internal server error." }); + } + } + private List BuildUserDtos(IEnumerable users) => users.Select(user => new UserDto { Id = user.Id, diff --git a/Govor.API/Hubs/FriendsHub.cs b/Govor.API/Hubs/FriendsHub.cs index 6fe173a..1e9e309 100644 --- a/Govor.API/Hubs/FriendsHub.cs +++ b/Govor.API/Hubs/FriendsHub.cs @@ -11,15 +11,61 @@ public class FriendsHub : Hub private readonly ILogger _logger; private readonly IFriendRequestCommandService _friendRequestService; private readonly ICurrentUserService _currentUserService; - + public FriendsHub(IFriendRequestCommandService friendRequestService, ICurrentUserService currentUserService, ILogger logger) { _friendRequestService = friendRequestService; _currentUserService = currentUserService; _logger = logger; } + + public override async Task OnConnectedAsync() + { + var userId = GetUserId(); + if (userId == Guid.Empty) + { + _logger.LogWarning("User connected with invalid UserID claim."); + Context.Abort(); // Abort connection if userID is invalid + return; + } - public async Task> SendRequest(Guid targetUserId) + // Add user to their own group (for private messages and notifications) + await Groups.AddToGroupAsync(Context.ConnectionId, userId.ToString()); + _logger.LogInformation("User {UserId} connected with ConnectionId {ConnectionId} and added to their group", + userId, Context.ConnectionId); + + + await base.OnConnectedAsync(); + } + public override async Task OnDisconnectedAsync(Exception? exception) + { + var userId = + GetUserId(suppressException: true); // Suppress exception if userID is not found (e.g. connection aborted early) + if (userId != Guid.Empty) + { + // Remove user from their own group + await Groups.RemoveFromGroupAsync(Context.ConnectionId, userId.ToString()); + _logger.LogInformation( + "User {UserId} disconnected with ConnectionId {ConnectionId} and removed from their group", userId, + Context.ConnectionId); + } + else if (exception != null) + { + _logger.LogWarning(exception, + "User disconnected with an exception and invalid UserID claim. ConnectionId: {ConnectionId}", + Context.ConnectionId); + } + else + { + _logger.LogInformation( + "User disconnected with no exception and invalid UserID claim. ConnectionId: {ConnectionId}", + Context.ConnectionId); + } + + await base.OnDisconnectedAsync(exception); + } + + public async Task> SendRequest(Guid targetUserId) { try { @@ -110,4 +156,21 @@ public class FriendsHub : Hub return HubResult.Error("Unexpected error! Please try later!"); } } + + private Guid GetUserId(bool suppressException = false) + { + var userIdClaim = Context.User?.FindFirst("userId")?.Value; + if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId)) + { + if (!suppressException) + { + _logger.LogError("Could not retrieve sender userId. Claim was: {UserIDClaim}", userIdClaim); + throw new UnauthorizedAccessException("userID claim is missing or invalid."); + } + + return Guid.Empty; + } + + return userId; + } } \ No newline at end of file diff --git a/Govor.API/Program.cs b/Govor.API/Program.cs index fd3e0ac..8f285d3 100644 --- a/Govor.API/Program.cs +++ b/Govor.API/Program.cs @@ -120,7 +120,9 @@ app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); + app.MapHub("/api/chats"); +app.MapHub("/api/friends"); app.MapSwagger().RequireAuthorization(); diff --git a/Govor.Console/Program.cs b/Govor.Console/Program.cs index 3383d4b..7bfbf4a 100644 --- a/Govor.Console/Program.cs +++ b/Govor.Console/Program.cs @@ -28,7 +28,7 @@ namespace Govor.ConsoleClient //static string baseUrl = "https://govor-team-govor-88b3.twc1.net"; static string baseUrl = "https://localhost:7155"; static string? AuthToken = null; - static HttpClientService HttpService = new(baseUrl); // поменяй URL на свой + static HttpClientService HttpService = new(baseUrl); private static FriendsClient? friendsClient; static HubConnection? _hubConnection; static Dictionary> ChatHistory = new(); diff --git a/Govor.Data.Tests/Govor.Data.Tests.csproj b/Govor.Data.Tests/Govor.Data.Tests.csproj index 812ca35..8ad7ddc 100644 --- a/Govor.Data.Tests/Govor.Data.Tests.csproj +++ b/Govor.Data.Tests/Govor.Data.Tests.csproj @@ -1,7 +1,7 @@  - net9.0 + net8.0 latest enable enable