diff --git a/Api.SeaHavenIndustries.Tests/UserControllerTests.cs b/Api.SeaHavenIndustries.Tests/UserControllerTests.cs index 620e461..777b12b 100644 --- a/Api.SeaHavenIndustries.Tests/UserControllerTests.cs +++ b/Api.SeaHavenIndustries.Tests/UserControllerTests.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Moq; using SeaHaven.Services.DTOs; +using SeaHaven.Services.Helpers; using SeaHaven.Services.Interfaces; using System.Security.Claims; using System.Text.Json; @@ -19,22 +20,25 @@ public class UserControllerTests private static string Json(object? value) => JsonSerializer.Serialize(value, value?.GetType() ?? typeof(object)); - private static UserController NewController(Mock service, string? userId = null) + private static UserController NewController( + Mock service, + string? userId = null, + string? role = null) { var controller = new UserController(service.Object, Mock.Of>()); + var claims = new List(); if (userId != null) + claims.Add(new Claim(ClaimTypes.NameIdentifier, userId)); + if (role != null) + claims.Add(new Claim(ClaimTypes.Role, role)); + + controller.ControllerContext = new ControllerContext { - controller.ControllerContext = new ControllerContext + HttpContext = new DefaultHttpContext { - HttpContext = new DefaultHttpContext - { - User = new ClaimsPrincipal(new ClaimsIdentity(new[] - { - new Claim(ClaimTypes.NameIdentifier, userId) - }, "Test")) - } - }; - } + User = new ClaimsPrincipal(new ClaimsIdentity(claims, "Test")) + } + }; return controller; } @@ -60,10 +64,13 @@ public class UserControllerTests public async Task AddUser_Success_ReturnsUpdatedSuccessfully() { var service = new Mock(); - service.Setup(s => s.AddUserAsync(It.IsAny(), It.IsAny())) + service.Setup(s => s.AddUserAsync( + It.IsAny(), + It.IsAny(), + It.IsAny())) .ReturnsAsync(new AddUserOutcomeDTO { Success = true }); - var controller = NewController(service); + var controller = NewController(service, "admin-1", "Admin"); var result = await controller.AddUser(new User_DTO { Name = "N", Email = "n@x.com", Role = "Admin" }, CancellationToken.None); @@ -71,16 +78,23 @@ public class UserControllerTests var response = ok.Value.Should().BeOfType().Subject; response.Status.Should().Be("200"); response.Message.Should().Be("Updated Successfully"); + service.Verify(s => s.AddUserAsync( + It.IsAny(), + It.Is(p => p.IsInRole("Admin")), + It.IsAny()), Times.Once); } [Fact] public async Task AddUser_Failure_ReturnsBadRequestWithServiceError() { var service = new Mock(); - service.Setup(s => s.AddUserAsync(It.IsAny(), It.IsAny())) + service.Setup(s => s.AddUserAsync( + It.IsAny(), + It.IsAny(), + It.IsAny())) .ReturnsAsync(new AddUserOutcomeDTO { Success = false, Error = "boom" }); - var controller = NewController(service); + var controller = NewController(service, "admin-1", "Admin"); var result = await controller.AddUser(new User_DTO(), CancellationToken.None); @@ -90,30 +104,55 @@ public class UserControllerTests response.Message.Should().Be("boom"); } + [Fact] + public async Task AddUser_ServiceForbidden_ReturnsForbid() + { + var service = new Mock(); + service.Setup(s => s.AddUserAsync( + It.IsAny(), + It.IsAny(), + It.IsAny())) + .ReturnsAsync(new AddUserOutcomeDTO { Success = false, Error = UserMutationErrors.Forbidden }); + + var controller = NewController(service, "tech-1", "User"); + + var result = await controller.AddUser( + new User_DTO { Name = "N", Email = "n@x.com", Role = "User", AccountId = 99 }, + CancellationToken.None); + + result.Should().BeOfType(); + } + [Fact] public async Task EditUser_NotFound_ReturnsUserNotFoundMessage() { var service = new Mock(); - service.Setup(s => s.EditUserAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(false); + service.Setup(s => s.EditUserAsync( + It.IsAny(), + It.IsAny(), + It.IsAny())) + .ReturnsAsync(new AddUserOutcomeDTO { Success = false, Error = UserMutationErrors.UserNotFound }); - var controller = NewController(service); + var controller = NewController(service, "admin-1", "Admin"); var result = await controller.EditUser(new EditUser_DTO { Id = "9" }, CancellationToken.None); var bad = result.Should().BeOfType().Subject; var response = bad.Value.Should().BeOfType().Subject; - response.Message.Should().Be("User not found"); + response.Message.Should().Be(UserMutationErrors.UserNotFound); } [Fact] public async Task EditUser_Found_ReturnsUpdatedSuccessfully() { var service = new Mock(); - service.Setup(s => s.EditUserAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(true); + service.Setup(s => s.EditUserAsync( + It.IsAny(), + It.IsAny(), + It.IsAny())) + .ReturnsAsync(new AddUserOutcomeDTO { Success = true }); - var controller = NewController(service); + var controller = NewController(service, "admin-1", "Admin"); var result = await controller.EditUser(new EditUser_DTO { Id = "9" }, CancellationToken.None); @@ -121,6 +160,25 @@ public class UserControllerTests ok.Value.Should().BeOfType(); } + [Fact] + public async Task EditUser_ServiceForbidden_ReturnsForbid() + { + var service = new Mock(); + service.Setup(s => s.EditUserAsync( + It.IsAny(), + It.IsAny(), + It.IsAny())) + .ReturnsAsync(new AddUserOutcomeDTO { Success = false, Error = UserMutationErrors.Forbidden }); + + var controller = NewController(service, "tech-1", "User"); + + var result = await controller.EditUser( + new EditUser_DTO { Id = "tech-1", AccountId = 42, Email = "me@x.com", Role = "User" }, + CancellationToken.None); + + result.Should().BeOfType(); + } + [Fact] public async Task DeleteUser_NotFound_ReturnsIdNotMatchedMessage() { diff --git a/Api.SeaHavenIndustries.Tests/UserServiceTests.cs b/Api.SeaHavenIndustries.Tests/UserServiceTests.cs index 8047ad7..2e88fd1 100644 --- a/Api.SeaHavenIndustries.Tests/UserServiceTests.cs +++ b/Api.SeaHavenIndustries.Tests/UserServiceTests.cs @@ -5,22 +5,36 @@ using Moq; using SeaHaven.DataServices.Dto; using SeaHaven.DataServices.Interfaces; using SeaHaven.Services.DTOs; +using SeaHaven.Services.Helpers; using SeaHaven.Services.Implementation; using SeaHaven.Services.Interfaces; +using System.Security.Claims; using Xunit; namespace Api.SeaHavenIndustries.Tests; public class UserServiceTests { + private static ClaimsPrincipal Principal(params string[] roles) + { + var claims = roles.Select(r => new Claim(ClaimTypes.Role, r)).ToList(); + claims.Add(new Claim(ClaimTypes.NameIdentifier, "caller-1")); + return new ClaimsPrincipal(new ClaimsIdentity(claims, "Test")); + } + private static UserService NewService( Mock userData, Mock email, - out Mock> store) + out Mock> store, + Mock? accounts = null) { var (manager, s, _) = IdentityTestHelpers.CreateUserManager(); store = s; - return new UserService(manager, userData.Object, email.Object); + return new UserService( + manager, + userData.Object, + (accounts ?? new Mock()).Object, + email.Object); } [Fact] @@ -39,7 +53,7 @@ public class UserServiceTests var users = (await service.GetUsersAsync(CancellationToken.None)).ToList(); users.Should().HaveCount(2); - users[0].Date.Should().Be("Jan 05 2026"); + users[0].Date.Should().Be(new DateTime(2026, 1, 5).ToString("MMM dd yyyy")); users[0].RoleName.Should().Be("Admin"); users[0].Status.Should().Be("Active"); users[1].Date.Should().Be(""); @@ -91,16 +105,20 @@ public class UserServiceTests } [Fact] - public async Task EditUser_NotFound_ReturnsFalse() + public async Task EditUser_NotFound_ReturnsUserNotFound() { var userData = new Mock(); userData.Setup(u => u.GetForEditAsync("x", It.IsAny())).ReturnsAsync((ApplicationUser?)null); var service = NewService(userData, new Mock(), out _); - var succeeded = await service.EditUserAsync(new EditUserRequestDTO { Id = "x", Email = "e@x.com", Name = "n", Role = "Admin" }, CancellationToken.None); + var outcome = await service.EditUserAsync( + new EditUserRequestDTO { Id = "x", Email = "e@x.com", Name = "n", Role = "Admin" }, + Principal("Admin"), + CancellationToken.None); - succeeded.Should().BeFalse(); + outcome.Success.Should().BeFalse(); + outcome.Error.Should().Be(UserMutationErrors.UserNotFound); } [Fact] @@ -140,7 +158,10 @@ public class UserServiceTests store.Setup(s => s.AddToRoleAsync(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(Task.CompletedTask); - var outcome = await service.AddUserAsync(new AddUserRequestDTO { Name = "N", Email = "n@x.com", Role = "Admin" }, CancellationToken.None); + var outcome = await service.AddUserAsync( + new AddUserRequestDTO { Name = "N", Email = "n@x.com", Role = "Admin" }, + Principal("Admin"), + CancellationToken.None); outcome.Success.Should().BeTrue(); store.Verify(s => s.CreateAsync(It.IsAny(), It.IsAny()), Times.Once); @@ -166,12 +187,174 @@ public class UserServiceTests store.Setup(s => s.CreateAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(IdentityResult.Failed(new IdentityError { Description = "duplicate" })); - var outcome = await service.AddUserAsync(new AddUserRequestDTO { Name = "N", Email = "n@x.com", Role = "Admin" }, CancellationToken.None); + var outcome = await service.AddUserAsync( + new AddUserRequestDTO { Name = "N", Email = "n@x.com", Role = "Admin" }, + Principal("Admin"), + CancellationToken.None); outcome.Success.Should().BeFalse(); outcome.Error.Should().Be("duplicate"); } + [Fact] + public async Task AddUser_NonAdmin_CannotSetAccountId_OnSelfOrOthers() + { + var userData = new Mock(); + var accounts = new Mock(); + accounts.Setup(a => a.ExistsAsync(99)).ReturnsAsync(true); + + var service = NewService(userData, new Mock(), out _, accounts); + + var selfOutcome = await service.AddUserAsync( + new AddUserRequestDTO { Name = "Me", Email = "me@x.com", Role = "User", AccountId = 99 }, + Principal("User"), + CancellationToken.None); + + var otherOutcome = await service.EditUserAsync( + new EditUserRequestDTO { Id = "other-1", Name = "Other", Email = "o@x.com", Role = "Dispatcher", AccountId = 99 }, + Principal("Dispatcher"), + CancellationToken.None); + + selfOutcome.Success.Should().BeFalse(); + selfOutcome.Error.Should().Be(UserMutationErrors.Forbidden); + otherOutcome.Success.Should().BeFalse(); + otherOutcome.Error.Should().Be(UserMutationErrors.Forbidden); + + userData.Verify(u => u.UpdateUserAsync(It.IsAny(), It.IsAny()), Times.Never); + accounts.Verify(a => a.ExistsAsync(It.IsAny()), Times.Never); + } + + [Fact] + public async Task EditUser_NonAdmin_CannotChangeOwnAccountScope() + { + var existing = IdentityTestHelpers.User("caller-1"); + existing.AccountId = 1; + var userData = new Mock(); + userData.Setup(u => u.GetForEditAsync("caller-1", It.IsAny())).ReturnsAsync(existing); + var accounts = new Mock(); + accounts.Setup(a => a.ExistsAsync(2)).ReturnsAsync(true); + + var service = NewService(userData, new Mock(), out _, accounts); + + var outcome = await service.EditUserAsync( + new EditUserRequestDTO + { + Id = "caller-1", + Name = "Alice", + Email = "alice@example.com", + Role = "User", + AccountId = 2 + }, + Principal("User"), + CancellationToken.None); + + outcome.Success.Should().BeFalse(); + outcome.Error.Should().Be(UserMutationErrors.Forbidden); + existing.AccountId.Should().Be(1); + userData.Verify(u => u.UpdateUserAsync(It.IsAny(), It.IsAny()), Times.Never); + } + + [Fact] + public async Task AddUser_Admin_InvalidAccountId_RejectsWithoutCreate() + { + var userData = new Mock(); + var accounts = new Mock(); + accounts.Setup(a => a.ExistsAsync(404)).ReturnsAsync(false); + + var service = NewService(userData, new Mock(), out var store, accounts); + + var outcome = await service.AddUserAsync( + new AddUserRequestDTO { Name = "N", Email = "n@x.com", Role = "User", AccountId = 404 }, + Principal("Admin"), + CancellationToken.None); + + outcome.Success.Should().BeFalse(); + outcome.Error.Should().Be(UserMutationErrors.AccountNotFound); + store.Verify(s => s.CreateAsync(It.IsAny(), It.IsAny()), Times.Never); + userData.Verify(u => u.GetByIdAsync(It.IsAny()), Times.Never); + } + + [Fact] + public async Task EditUser_Admin_InvalidAccountId_RejectsWithoutSave() + { + var existing = IdentityTestHelpers.User("u9"); + existing.AccountId = 1; + var userData = new Mock(); + userData.Setup(u => u.GetForEditAsync("u9", It.IsAny())).ReturnsAsync(existing); + var accounts = new Mock(); + accounts.Setup(a => a.ExistsAsync(404)).ReturnsAsync(false); + + var service = NewService(userData, new Mock(), out _, accounts); + + var outcome = await service.EditUserAsync( + new EditUserRequestDTO { Id = "u9", Name = "N", Email = "n@x.com", Role = "User", AccountId = 404 }, + Principal("Admin"), + CancellationToken.None); + + outcome.Success.Should().BeFalse(); + outcome.Error.Should().Be(UserMutationErrors.AccountNotFound); + existing.AccountId.Should().Be(1); + userData.Verify(u => u.UpdateUserAsync(It.IsAny(), It.IsAny()), Times.Never); + } + + [Fact] + public async Task AddUser_Admin_ValidAccountId_PersistsOnCreate() + { + var userData = new Mock(); + userData.Setup(u => u.GetByIdAsync(It.IsAny())).ReturnsAsync((ApplicationUser?)null); + var accounts = new Mock(); + accounts.Setup(a => a.ExistsAsync(10)).ReturnsAsync(true); + + var service = NewService(userData, new Mock(), out var store, accounts); + store.As>() + .Setup(s => s.SetPasswordHashAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(Task.CompletedTask); + ApplicationUser? created = null; + store.Setup(s => s.CreateAsync(It.IsAny(), It.IsAny())) + .Callback((u, _) => created = u) + .ReturnsAsync(IdentityResult.Success); + store.Setup(s => s.AddToRoleAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(Task.CompletedTask); + + var outcome = await service.AddUserAsync( + new AddUserRequestDTO { Name = "N", Email = "n@x.com", Role = "User", AccountId = 10 }, + Principal("Admin"), + CancellationToken.None); + + outcome.Success.Should().BeTrue(); + created.Should().NotBeNull(); + created!.AccountId.Should().Be(10); + accounts.Verify(a => a.ExistsAsync(10), Times.Once); + } + + [Fact] + public async Task EditUser_Admin_ValidAccountId_PersistsOnEdit() + { + var existing = IdentityTestHelpers.User("u9"); + existing.AccountId = 1; + var userData = new Mock(); + userData.Setup(u => u.GetForEditAsync("u9", It.IsAny())).ReturnsAsync(existing); + var accounts = new Mock(); + accounts.Setup(a => a.ExistsAsync(10)).ReturnsAsync(true); + + var service = NewService(userData, new Mock(), out var store, accounts); + store.Setup(s => s.GetRolesAsync(existing, It.IsAny())) + .ReturnsAsync(new List { "User" }); + store.Setup(s => s.RemoveFromRoleAsync(existing, "User", It.IsAny())) + .Returns(Task.CompletedTask); + store.Setup(s => s.AddToRoleAsync(existing, "User", It.IsAny())) + .Returns(Task.CompletedTask); + + var outcome = await service.EditUserAsync( + new EditUserRequestDTO { Id = "u9", Name = "N", Email = "n@x.com", Role = "User", AccountId = 10 }, + Principal("Admin"), + CancellationToken.None); + + outcome.Success.Should().BeTrue(); + existing.AccountId.Should().Be(10); + userData.Verify(u => u.UpdateUserAsync(existing, It.IsAny()), Times.Once); + } + private static bool ContainsStrongGeneratedPassword(string body) { const string marker = "Your password is: "; diff --git a/Api.SeaHavenIndustries/Controllers/UserController.cs b/Api.SeaHavenIndustries/Controllers/UserController.cs index 144896b..e92c7cc 100644 --- a/Api.SeaHavenIndustries/Controllers/UserController.cs +++ b/Api.SeaHavenIndustries/Controllers/UserController.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using SeaHaven.Services.DTOs; +using SeaHaven.Services.Helpers; using SeaHaven.Services.Interfaces; using System.Security.Claims; @@ -32,6 +33,7 @@ namespace Api.SeaHavenIndustries.Controllers } [HttpPost] [Route("AddUser")] + [Authorize(Roles = "Admin")] public async Task AddUser(User_DTO user, CancellationToken cancellationToken) { try @@ -44,9 +46,11 @@ namespace Api.SeaHavenIndustries.Controllers Role = user.Role, AccountId = user.AccountId }; - var outcome = await _userService.AddUserAsync(dto, cancellationToken); + var outcome = await _userService.AddUserAsync(dto, User, cancellationToken); if (!outcome.Success) { + if (string.Equals(outcome.Error, UserMutationErrors.Forbidden, StringComparison.Ordinal)) + return Forbid(); return BadRequest(new Response { Status = "Error", Message = outcome.Error }); } return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); @@ -60,6 +64,7 @@ namespace Api.SeaHavenIndustries.Controllers } [HttpPut] [Route("EditUser")] + [Authorize(Roles = "Admin")] public async Task EditUser(EditUser_DTO user, CancellationToken cancellationToken) { try @@ -72,9 +77,13 @@ namespace Api.SeaHavenIndustries.Controllers Role = user.Role, AccountId = user.AccountId }; - var succeeded = await _userService.EditUserAsync(dto, cancellationToken); - if (!succeeded) - return BadRequest(new Response { Status = "Error", Message = "User not found" }); + var outcome = await _userService.EditUserAsync(dto, User, cancellationToken); + if (!outcome.Success) + { + if (string.Equals(outcome.Error, UserMutationErrors.Forbidden, StringComparison.Ordinal)) + return Forbid(); + return BadRequest(new Response { Status = "Error", Message = outcome.Error }); + } return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); } catch (Exception ex) diff --git a/SeaHaven.Services/Helpers/UserMutationErrors.cs b/SeaHaven.Services/Helpers/UserMutationErrors.cs new file mode 100644 index 0000000..fd16f43 --- /dev/null +++ b/SeaHaven.Services/Helpers/UserMutationErrors.cs @@ -0,0 +1,10 @@ +namespace SeaHaven.Services.Helpers +{ + /// Stable user-mutation outcome messages (no internal detail). + public static class UserMutationErrors + { + public const string Forbidden = "Forbidden"; + public const string AccountNotFound = "Account not found"; + public const string UserNotFound = "User not found"; + } +} diff --git a/SeaHaven.Services/Implementation/UserService.cs b/SeaHaven.Services/Implementation/UserService.cs index 61a2e58..2d1f1ba 100644 --- a/SeaHaven.Services/Implementation/UserService.cs +++ b/SeaHaven.Services/Implementation/UserService.cs @@ -2,7 +2,9 @@ using Data.SeaHavenIndustries; using Microsoft.AspNetCore.Identity; using SeaHaven.DataServices.Interfaces; using SeaHaven.Services.DTOs; +using SeaHaven.Services.Helpers; using SeaHaven.Services.Interfaces; +using System.Security.Claims; using System.Security.Cryptography; namespace SeaHaven.Services.Implementation @@ -11,15 +13,18 @@ namespace SeaHaven.Services.Implementation { private readonly UserManager _userManager; private readonly IUserDataService _userDataService; + private readonly IAccountDataService _accountDataService; private readonly IEmailSender _emailSender; public UserService( UserManager userManager, IUserDataService userDataService, + IAccountDataService accountDataService, IEmailSender emailSender) { _userManager = userManager; _userDataService = userDataService; + _accountDataService = accountDataService; _emailSender = emailSender; } @@ -37,8 +42,19 @@ namespace SeaHaven.Services.Implementation }); } - public async Task AddUserAsync(AddUserRequestDTO dto, CancellationToken cancellationToken) + public async Task AddUserAsync( + AddUserRequestDTO dto, + ClaimsPrincipal caller, + CancellationToken cancellationToken) { + var authFailure = EnsureAdminCaller(caller); + if (authFailure != null) + return authFailure; + + var accountFailure = await EnsureAccountValidAsync(dto.AccountId); + if (accountFailure != null) + return accountFailure; + var model = new ApplicationUser { UserName = dto.Email, @@ -80,7 +96,7 @@ namespace SeaHaven.Services.Implementation { var exist1 = await _userDataService.GetForEditAsync(model.Id, cancellationToken); if (exist1 == null) - return new AddUserOutcomeDTO { Success = false, Error = "User not found" }; + return new AddUserOutcomeDTO { Success = false, Error = UserMutationErrors.UserNotFound }; var existingRole = await _userManager.GetRolesAsync(exist1); @@ -103,11 +119,22 @@ namespace SeaHaven.Services.Implementation } } - public async Task EditUserAsync(EditUserRequestDTO dto, CancellationToken cancellationToken) + public async Task EditUserAsync( + EditUserRequestDTO dto, + ClaimsPrincipal caller, + CancellationToken cancellationToken) { + var authFailure = EnsureAdminCaller(caller); + if (authFailure != null) + return authFailure; + + var accountFailure = await EnsureAccountValidAsync(dto.AccountId); + if (accountFailure != null) + return accountFailure; + var exist = await _userDataService.GetForEditAsync(dto.Id ?? "", cancellationToken); if (exist == null) - return false; + return new AddUserOutcomeDTO { Success = false, Error = UserMutationErrors.UserNotFound }; exist.FirstName = dto.Name; if (string.IsNullOrWhiteSpace(dto.Email)) @@ -131,7 +158,7 @@ namespace SeaHaven.Services.Implementation await _userManager.AddToRoleAsync(exist, dto.Role ?? ""); await _userDataService.UpdateUserAsync(exist, cancellationToken); - return true; + return new AddUserOutcomeDTO { Success = true }; } public async Task DeleteUserAsync(string id, CancellationToken cancellationToken) @@ -173,6 +200,29 @@ namespace SeaHaven.Services.Implementation }; } + private static AddUserOutcomeDTO? EnsureAdminCaller(ClaimsPrincipal caller) + { + if (caller is null || !caller.IsInRole("Admin")) + { + return new AddUserOutcomeDTO { Success = false, Error = UserMutationErrors.Forbidden }; + } + + return null; + } + + private async Task EnsureAccountValidAsync(int? accountId) + { + if (!accountId.HasValue) + return null; + + if (accountId.Value <= 0 || !await _accountDataService.ExistsAsync(accountId.Value)) + { + return new AddUserOutcomeDTO { Success = false, Error = UserMutationErrors.AccountNotFound }; + } + + return null; + } + private static string GenerateRandomPassword(int length = 8) { const string validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_-+=<>?"; diff --git a/SeaHaven.Services/Interfaces/IUserService.cs b/SeaHaven.Services/Interfaces/IUserService.cs index 9f47410..a4a7a7c 100644 --- a/SeaHaven.Services/Interfaces/IUserService.cs +++ b/SeaHaven.Services/Interfaces/IUserService.cs @@ -1,3 +1,4 @@ +using System.Security.Claims; using SeaHaven.Services.DTOs; namespace SeaHaven.Services.Interfaces @@ -5,8 +6,8 @@ namespace SeaHaven.Services.Interfaces public interface IUserService { Task> GetUsersAsync(CancellationToken cancellationToken); - Task AddUserAsync(AddUserRequestDTO dto, CancellationToken cancellationToken); - Task EditUserAsync(EditUserRequestDTO dto, CancellationToken cancellationToken); + Task AddUserAsync(AddUserRequestDTO dto, ClaimsPrincipal caller, CancellationToken cancellationToken); + Task EditUserAsync(EditUserRequestDTO dto, ClaimsPrincipal caller, CancellationToken cancellationToken); Task DeleteUserAsync(string id, CancellationToken cancellationToken); Task DeleteCurrentUserAsync(string userId, CancellationToken cancellationToken); Task> GetUserProfileAsync(string userId, CancellationToken cancellationToken);