diff --git a/BTCPayServer.Client/BTCPayServerClient.Users.cs b/BTCPayServer.Client/BTCPayServerClient.Users.cs index 567945958..ee6aa18a2 100644 --- a/BTCPayServer.Client/BTCPayServerClient.Users.cs +++ b/BTCPayServer.Client/BTCPayServerClient.Users.cs @@ -33,11 +33,12 @@ namespace BTCPayServer.Client return await HandleResponse(response); } - public virtual async Task LockUser(string idOrEmail, bool locked, CancellationToken token = default) + public virtual async Task LockUser(string idOrEmail, bool locked, CancellationToken token = default) { var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/users/{idOrEmail}/lock", null, - new LockUserRequest() {Locked = locked}, HttpMethod.Post), token); + new LockUserRequest {Locked = locked}, HttpMethod.Post), token); await HandleResponse(response); + return response.IsSuccessStatusCode; } public virtual async Task GetUsers( CancellationToken token = default) diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs index 828a69085..81567503c 100644 --- a/BTCPayServer.Tests/GreenfieldAPITests.cs +++ b/BTCPayServer.Tests/GreenfieldAPITests.cs @@ -2920,8 +2920,7 @@ namespace BTCPayServer.Tests var newUserClient = await newUser.CreateClient(Policies.Unrestricted); Assert.False((await newUserClient.GetCurrentUser()).Disabled); - await adminClient.LockUser(newUser.UserId, true, CancellationToken.None); - + Assert.True(await adminClient.LockUser(newUser.UserId, true, CancellationToken.None)); Assert.True((await adminClient.GetUserByIdOrEmail(newUser.UserId)).Disabled); await AssertAPIError("unauthenticated",async () => { @@ -2934,12 +2933,12 @@ namespace BTCPayServer.Tests await newUserBasicClient.GetCurrentUser(); }); - await adminClient.LockUser(newUser.UserId, false, CancellationToken.None); + Assert.True(await adminClient.LockUser(newUser.UserId, false, CancellationToken.None)); Assert.False((await adminClient.GetUserByIdOrEmail(newUser.UserId)).Disabled); await newUserClient.GetCurrentUser(); await newUserBasicClient.GetCurrentUser(); // Twice for good measure - await adminClient.LockUser(newUser.UserId, false, CancellationToken.None); + Assert.True(await adminClient.LockUser(newUser.UserId, false, CancellationToken.None)); Assert.False((await adminClient.GetUserByIdOrEmail(newUser.UserId)).Disabled); await newUserClient.GetCurrentUser(); await newUserBasicClient.GetCurrentUser(); diff --git a/BTCPayServer/Controllers/GreenField/GreenfieldUsersController.cs b/BTCPayServer/Controllers/GreenField/GreenfieldUsersController.cs index 7dc5c1c78..6336f0e66 100644 --- a/BTCPayServer/Controllers/GreenField/GreenfieldUsersController.cs +++ b/BTCPayServer/Controllers/GreenField/GreenfieldUsersController.cs @@ -76,18 +76,20 @@ namespace BTCPayServer.Controllers.Greenfield } return UserNotFound(); } + [Authorize(Policy = Policies.CanModifyServerSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] [HttpPost("~/api/v1/users/{idOrEmail}/lock")] - public async Task LockUser(string idOrEmail, LockUserRequest request ) + public async Task LockUser(string idOrEmail, LockUserRequest request) { - var user = (await _userManager.FindByIdAsync(idOrEmail) ) ?? await _userManager.FindByEmailAsync(idOrEmail); + var user = await _userManager.FindByIdAsync(idOrEmail) ?? await _userManager.FindByEmailAsync(idOrEmail); if (user is null) { return UserNotFound(); } - await _userService.ToggleUser(user.Id, request.Locked ? DateTimeOffset.MaxValue : null); - return Ok(); + var success = await _userService.ToggleUser(user.Id, request.Locked ? DateTimeOffset.MaxValue : null); + return success.HasValue && success.Value ? Ok() : this.CreateAPIError("invalid-state", + $"{(request.Locked ? "Locking" : "Unlocking")} user failed"); } [Authorize(Policy = Policies.CanViewUsers, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] diff --git a/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs b/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs index f9c917a7a..6863e988b 100644 --- a/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs +++ b/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs @@ -1047,9 +1047,11 @@ namespace BTCPayServer.Controllers.Greenfield return GetFromActionResult(await GetController().GetUser(idOrEmail)); } - public override async Task LockUser(string idOrEmail, bool disabled, CancellationToken token = default) + public override async Task LockUser(string idOrEmail, bool disabled, CancellationToken token = default) { - HandleActionResult(await GetController().LockUser(idOrEmail, new LockUserRequest() {Locked = disabled})); + return GetFromActionResult( + await GetController().LockUser(idOrEmail, + new LockUserRequest { Locked = disabled })); } public override async Task PatchOnChainWalletTransaction(string storeId, diff --git a/BTCPayServer/Services/UserService.cs b/BTCPayServer/Services/UserService.cs index 6c1096ece..8d490c66e 100644 --- a/BTCPayServer/Services/UserService.cs +++ b/BTCPayServer/Services/UserService.cs @@ -65,12 +65,12 @@ namespace BTCPayServer.Services return user.LockoutEnabled && user.LockoutEnd is not null && DateTimeOffset.UtcNow < user.LockoutEnd.Value.UtcDateTime; } - public async Task ToggleUser(string userId, DateTimeOffset? lockedOutDeadline) + public async Task ToggleUser(string userId, DateTimeOffset? lockedOutDeadline) { var user = await _userManager.FindByIdAsync(userId); if (user is null) { - return; + return null; } if (lockedOutDeadline is not null) { @@ -86,7 +86,8 @@ namespace BTCPayServer.Services { _logger.LogError($"Failed to set lockout for user {user.Id}"); } - + + return res.Succeeded; } public async Task IsAdminUser(string userId) diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.users.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.users.json index 860270f21..6ceb4a155 100644 --- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.users.json +++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.users.json @@ -249,7 +249,7 @@ } }, "/api/v1/users/{idOrEmail}/lock": { - "delete": { + "post": { "operationId": "Users_ToggleUserLock", "tags": [ "Users"