mirror of
https://github.com/Govor-team/Govor.git
synced 2026-07-21 19:54:55 +00:00
Refactor user context handling with CurrentUserService
Introduced ICurrentUserService and its implementation to centralize retrieval of the current user's ID from claims. Updated FriendsController to use this service instead of direct claim access. Registered the service and IHttpContextAccessor in DI. Added integration tests for FriendsController. Moved UsernameValidator to Infrastructure/Validators.
This commit is contained in:
@@ -86,9 +86,9 @@ public class AuthControllerTests
|
|||||||
var result = await _controller.Register(request);
|
var result = await _controller.Register(request);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.That(result, Is.InstanceOf<BadRequestObjectResult>());
|
Assert.That(result, Is.InstanceOf<NotFoundObjectResult>());
|
||||||
var badRequestResult = result as BadRequestObjectResult;
|
var notFoundObjectResult = result as NotFoundObjectResult;
|
||||||
Assert.That(badRequestResult.Value, Is.EqualTo("Invite link invalid."));
|
Assert.That(notFoundObjectResult.Value, Is.EqualTo("Invite link invalid."));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|||||||
@@ -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<ILogger<FriendsController>> _loggerMock;
|
||||||
|
private Mock<IFriendsService> _friendsServiceMock;
|
||||||
|
private Mock<ICurrentUserService> _currentUserServiceMock;
|
||||||
|
private FriendsController _controller;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp()
|
||||||
|
{
|
||||||
|
_fixture = new Fixture();
|
||||||
|
_fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList().ForEach(b => _fixture.Behaviors.Remove(b));
|
||||||
|
_fixture.Behaviors.Add(new OmitOnRecursionBehavior());
|
||||||
|
|
||||||
|
_loggerMock = new Mock<ILogger<FriendsController>>();
|
||||||
|
_friendsServiceMock = new Mock<IFriendsService>();
|
||||||
|
_currentUserServiceMock = new Mock<ICurrentUserService>();
|
||||||
|
|
||||||
|
_controller = new FriendsController(
|
||||||
|
_loggerMock.Object,
|
||||||
|
_friendsServiceMock.Object,
|
||||||
|
_currentUserServiceMock.Object
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests for Search action
|
||||||
|
[Test]
|
||||||
|
public async Task Search_ValidRequest_ReturnsOkResult()
|
||||||
|
{
|
||||||
|
var users = _fixture.CreateMany<User>().ToList();
|
||||||
|
var userId = _fixture.Create<Guid>();
|
||||||
|
var query = _fixture.Create<string>();
|
||||||
|
|
||||||
|
_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<UserDto> userDtos = value as List<UserDto>;
|
||||||
|
|
||||||
|
// 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<BadRequestObjectResult>());
|
||||||
|
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<string>(), It.IsAny<Guid>()))
|
||||||
|
.ThrowsAsync(new SearchUsersException(_fixture.Create<string>()));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _controller.Search(_fixture.Create<string>());
|
||||||
|
// Assert
|
||||||
|
Assert.That(result, Is.InstanceOf<NotFoundObjectResult>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Search_StatusCode500_IfThrowsSomeException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_friendsServiceMock.Setup(f => f.SearchUsersAsync(It.IsAny<string>(), It.IsAny<Guid>()))
|
||||||
|
.ThrowsAsync(new Exception(_fixture.Create<string>()));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _controller.Search(_fixture.Create<string>());
|
||||||
|
// Assert
|
||||||
|
Assert.That(result, Is.InstanceOf<ObjectResult>());
|
||||||
|
var objectResult = result as ObjectResult;
|
||||||
|
Assert.That(objectResult.StatusCode, Is.EqualTo(500));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public void TearDown()
|
||||||
|
{
|
||||||
|
_controller.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Govor.Application.Exceptions.FriendsService;
|
using Govor.Application.Exceptions.FriendsService;
|
||||||
using Govor.Application.Interfaces;
|
using Govor.Application.Interfaces;
|
||||||
|
using Govor.Application.Interfaces.Infrastructure.Extensions;
|
||||||
using Govor.Contracts.DTOs;
|
using Govor.Contracts.DTOs;
|
||||||
using Govor.Core.Models;
|
using Govor.Core.Models;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@@ -14,11 +15,15 @@ public class FriendsController : Controller
|
|||||||
{
|
{
|
||||||
private readonly ILogger<FriendsController> _logger;
|
private readonly ILogger<FriendsController> _logger;
|
||||||
private readonly IFriendsService _friendsService;
|
private readonly IFriendsService _friendsService;
|
||||||
|
private readonly ICurrentUserService _currentUserService;
|
||||||
|
|
||||||
public FriendsController(ILogger<FriendsController> logger, IFriendsService friendsService)
|
public FriendsController(ILogger<FriendsController> logger,
|
||||||
|
IFriendsService friendsService,
|
||||||
|
ICurrentUserService currentUserService)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_friendsService = friendsService;
|
_friendsService = friendsService;
|
||||||
|
_currentUserService = currentUserService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("search")]
|
[HttpGet("search")]
|
||||||
@@ -29,7 +34,7 @@ public class FriendsController : Controller
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await _friendsService.SearchUsersAsync(query, GetCurrentUserId());
|
var result = await _friendsService.SearchUsersAsync(query, _currentUserService.GetCurrentUserId());
|
||||||
return Ok(BuildUserDtos(result));
|
return Ok(BuildUserDtos(result));
|
||||||
}
|
}
|
||||||
catch (SearchUsersException ex)
|
catch (SearchUsersException ex)
|
||||||
@@ -52,7 +57,7 @@ public class FriendsController : Controller
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _friendsService.SendFriendRequestAsync(targetUserId, GetCurrentUserId());
|
await _friendsService.SendFriendRequestAsync(targetUserId, _currentUserService.GetCurrentUserId());
|
||||||
return Ok(new { message = "Friend request sent successfully." });
|
return Ok(new { message = "Friend request sent successfully." });
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException ex)
|
catch (InvalidOperationException ex)
|
||||||
@@ -77,7 +82,7 @@ public class FriendsController : Controller
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await _friendsService.GetIncomingRequestsAsync(GetCurrentUserId());
|
var result = await _friendsService.GetIncomingRequestsAsync(_currentUserService.GetCurrentUserId());
|
||||||
return Ok(BuildFriendshipDtos(result));
|
return Ok(BuildFriendshipDtos(result));
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException ex)
|
catch (InvalidOperationException ex)
|
||||||
@@ -100,7 +105,7 @@ public class FriendsController : Controller
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _friendsService.AcceptFriendRequestAsync(requesterId, GetCurrentUserId());
|
await _friendsService.AcceptFriendRequestAsync(requesterId, _currentUserService.GetCurrentUserId());
|
||||||
return Ok(new { message = "Friend request accepted." });
|
return Ok(new { message = "Friend request accepted." });
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException ex)
|
catch (InvalidOperationException ex)
|
||||||
@@ -125,7 +130,7 @@ public class FriendsController : Controller
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await _friendsService.GetFriendsAsync(GetCurrentUserId());
|
var result = await _friendsService.GetFriendsAsync(_currentUserService.GetCurrentUserId());
|
||||||
return Ok(BuildUserDtos(result));
|
return Ok(BuildUserDtos(result));
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException ex)
|
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<UserDto> BuildUserDtos(IEnumerable<User> users) => users.Select(user => new UserDto
|
private List<UserDto> BuildUserDtos(IEnumerable<User> users) => users.Select(user => new UserDto
|
||||||
{
|
{
|
||||||
Id = user.Id,
|
Id = user.Id,
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using Govor.API.Services.AdminsStuff.Interfaces;
|
using Govor.API.Services.AdminsStuff.Interfaces;
|
||||||
using Govor.API.Services.Authentication.Interfaces;
|
using Govor.API.Services.Authentication.Interfaces;
|
||||||
|
using Govor.Application.Infrastructure.Extensions;
|
||||||
using Govor.Application.Interfaces;
|
using Govor.Application.Interfaces;
|
||||||
using Govor.Application.Interfaces.AdminsStuff;
|
using Govor.Application.Interfaces.AdminsStuff;
|
||||||
using Govor.Application.Interfaces.Authentication;
|
using Govor.Application.Interfaces.Authentication;
|
||||||
|
using Govor.Application.Interfaces.Infrastructure.Extensions;
|
||||||
using Govor.Application.Services;
|
using Govor.Application.Services;
|
||||||
using Govor.Application.Validators;
|
using Govor.Application.Validators;
|
||||||
using Govor.Core.Infrastructure.Extensions;
|
using Govor.Core.Infrastructure.Extensions;
|
||||||
@@ -38,6 +40,9 @@ public static class ConfigurationProgramExtensions
|
|||||||
var env = sp.GetRequiredService<IWebHostEnvironment>();
|
var env = sp.GetRequiredService<IWebHostEnvironment>();
|
||||||
return new LocalStorageService(env.ContentRootPath);
|
return new LocalStorageService(env.ContentRootPath);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
services.AddHttpContextAccessor(); // it's very important for CurrentUserService
|
||||||
|
services.AddScoped<ICurrentUserService, CurrentUserService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddRepositories(this IServiceCollection services)
|
public static void AddRepositories(this IServiceCollection services)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Govor.Application.Interfaces.Infrastructure.Extensions;
|
||||||
|
|
||||||
|
public interface ICurrentUserService
|
||||||
|
{
|
||||||
|
Guid GetCurrentUserId();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user