diff --git a/Govor.API.Tests/IntegrationTests/Controllers/AuthControllerTests.cs b/Govor.API.Tests/IntegrationTests/Controllers/AuthControllerTests.cs index b449ffa..82808d2 100644 --- a/Govor.API.Tests/IntegrationTests/Controllers/AuthControllerTests.cs +++ b/Govor.API.Tests/IntegrationTests/Controllers/AuthControllerTests.cs @@ -86,9 +86,9 @@ public class AuthControllerTests var result = await _controller.Register(request); // Assert - Assert.That(result, Is.InstanceOf()); - var badRequestResult = result as BadRequestObjectResult; - Assert.That(badRequestResult.Value, Is.EqualTo("Invite link invalid.")); + Assert.That(result, Is.InstanceOf()); + var notFoundObjectResult = result as NotFoundObjectResult; + Assert.That(notFoundObjectResult.Value, Is.EqualTo("Invite link invalid.")); } [Test] diff --git a/Govor.API.Tests/IntegrationTests/Controllers/FriendsControllerTests.cs b/Govor.API.Tests/IntegrationTests/Controllers/FriendsControllerTests.cs new file mode 100644 index 0000000..124d67d --- /dev/null +++ b/Govor.API.Tests/IntegrationTests/Controllers/FriendsControllerTests.cs @@ -0,0 +1,115 @@ +using AutoFixture; +using Govor.API.Controllers; +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.Mvc; +using Microsoft.Extensions.Logging; +using Moq; + +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 + [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 + var result = await _controller.Search(query); + + var okResult = result as OkObjectResult; + dynamic value = okResult.Value; + + List userDtos = value as List; + + // 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))); + } + + [Test] + public async Task Search_InvalidQuery_BadRequest() + { + // 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 + _friendsServiceMock.Setup(f => f.SearchUsersAsync(It.IsAny(), It.IsAny())) + .ThrowsAsync(new SearchUsersException(_fixture.Create())); + + // Act + var result = await _controller.Search(_fixture.Create()); + // Assert + Assert.That(result, Is.InstanceOf()); + } + + [Test] + public async Task Search_StatusCode500_IfThrowsSomeException() + { + // Arrange + _friendsServiceMock.Setup(f => f.SearchUsersAsync(It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception(_fixture.Create())); + + // 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)); + } + + + + [TearDown] + public void TearDown() + { + _controller.Dispose(); + } +} \ No newline at end of file diff --git a/Govor.API/Controllers/FriendsController.cs b/Govor.API/Controllers/FriendsController.cs index 5f1e7c4..7000c2a 100644 --- a/Govor.API/Controllers/FriendsController.cs +++ b/Govor.API/Controllers/FriendsController.cs @@ -1,5 +1,6 @@ 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; @@ -14,11 +15,15 @@ public class FriendsController : Controller { private readonly ILogger _logger; private readonly IFriendsService _friendsService; - - public FriendsController(ILogger logger, IFriendsService friendsService) + private readonly ICurrentUserService _currentUserService; + + public FriendsController(ILogger logger, + IFriendsService friendsService, + ICurrentUserService currentUserService) { _logger = logger; _friendsService = friendsService; + _currentUserService = currentUserService; } [HttpGet("search")] @@ -29,7 +34,7 @@ public class FriendsController : Controller try { - var result = await _friendsService.SearchUsersAsync(query, GetCurrentUserId()); + var result = await _friendsService.SearchUsersAsync(query, _currentUserService.GetCurrentUserId()); return Ok(BuildUserDtos(result)); } catch (SearchUsersException ex) @@ -52,7 +57,7 @@ public class FriendsController : Controller try { - await _friendsService.SendFriendRequestAsync(targetUserId, GetCurrentUserId()); + await _friendsService.SendFriendRequestAsync(targetUserId, _currentUserService.GetCurrentUserId()); return Ok(new { message = "Friend request sent successfully." }); } catch (InvalidOperationException ex) @@ -77,7 +82,7 @@ public class FriendsController : Controller { try { - var result = await _friendsService.GetIncomingRequestsAsync(GetCurrentUserId()); + var result = await _friendsService.GetIncomingRequestsAsync(_currentUserService.GetCurrentUserId()); return Ok(BuildFriendshipDtos(result)); } catch (InvalidOperationException ex) @@ -100,7 +105,7 @@ public class FriendsController : Controller try { - await _friendsService.AcceptFriendRequestAsync(requesterId, GetCurrentUserId()); + await _friendsService.AcceptFriendRequestAsync(requesterId, _currentUserService.GetCurrentUserId()); return Ok(new { message = "Friend request accepted." }); } catch (InvalidOperationException ex) @@ -125,7 +130,7 @@ public class FriendsController : Controller { try { - var result = await _friendsService.GetFriendsAsync(GetCurrentUserId()); + var result = await _friendsService.GetFriendsAsync(_currentUserService.GetCurrentUserId()); return Ok(BuildUserDtos(result)); } catch (InvalidOperationException ex) @@ -140,16 +145,6 @@ public class FriendsController : Controller } } - private Guid GetCurrentUserId() - { - var userIdClaim = HttpContext.User?.FindFirst("userID")?.Value; - if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId)) - { - throw new UnauthorizedAccessException("userID claim is missing or invalid"); - } - return userId; - } - private List BuildUserDtos(IEnumerable users) => users.Select(user => new UserDto { Id = user.Id, diff --git a/Govor.API/Extensions/ConfigurationProgramExtensions.cs b/Govor.API/Extensions/ConfigurationProgramExtensions.cs index 3658265..76876ef 100644 --- a/Govor.API/Extensions/ConfigurationProgramExtensions.cs +++ b/Govor.API/Extensions/ConfigurationProgramExtensions.cs @@ -1,8 +1,10 @@ using Govor.API.Services.AdminsStuff.Interfaces; using Govor.API.Services.Authentication.Interfaces; +using Govor.Application.Infrastructure.Extensions; using Govor.Application.Interfaces; using Govor.Application.Interfaces.AdminsStuff; using Govor.Application.Interfaces.Authentication; +using Govor.Application.Interfaces.Infrastructure.Extensions; using Govor.Application.Services; using Govor.Application.Validators; using Govor.Core.Infrastructure.Extensions; @@ -38,6 +40,9 @@ public static class ConfigurationProgramExtensions var env = sp.GetRequiredService(); return new LocalStorageService(env.ContentRootPath); }); + + services.AddHttpContextAccessor(); // it's very important for CurrentUserService + services.AddScoped(); } public static void AddRepositories(this IServiceCollection services) diff --git a/Govor.Application/Infrastructure/Extensions/CurrentUserService.cs b/Govor.Application/Infrastructure/Extensions/CurrentUserService.cs new file mode 100644 index 0000000..3cb4b67 --- /dev/null +++ b/Govor.Application/Infrastructure/Extensions/CurrentUserService.cs @@ -0,0 +1,26 @@ +using System.Security.Claims; +using Govor.Application.Interfaces.Infrastructure.Extensions; +using Microsoft.AspNetCore.Http; + +namespace Govor.Application.Infrastructure.Extensions; + +public class CurrentUserService : ICurrentUserService +{ + private readonly ClaimsPrincipal _user; + + public CurrentUserService(IHttpContextAccessor httpContextAccessor) + { + _user = httpContextAccessor.HttpContext.User; + } + + public Guid GetCurrentUserId() + { + var userIdClaim = _user.FindFirst("userId")?.Value; + + if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId)) + { + throw new UnauthorizedAccessException("userID claim is missing or invalid"); + } + return userId; + } +} \ No newline at end of file diff --git a/Govor.Application/Validators/UsernameValidator.cs b/Govor.Application/Infrastructure/Validators/UsernameValidator.cs similarity index 100% rename from Govor.Application/Validators/UsernameValidator.cs rename to Govor.Application/Infrastructure/Validators/UsernameValidator.cs diff --git a/Govor.Application/Interfaces/Infrastructure/Extensions/ICurrentUserService.cs b/Govor.Application/Interfaces/Infrastructure/Extensions/ICurrentUserService.cs new file mode 100644 index 0000000..42e1156 --- /dev/null +++ b/Govor.Application/Interfaces/Infrastructure/Extensions/ICurrentUserService.cs @@ -0,0 +1,6 @@ +namespace Govor.Application.Interfaces.Infrastructure.Extensions; + +public interface ICurrentUserService +{ + Guid GetCurrentUserId(); +} \ No newline at end of file