mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2024-11-19 01:43:50 +01:00
[Greenfield] Allow passing email instead of user id in API (#4732)
This commit is contained in:
parent
0406b420c8
commit
5caa0e0722
@ -7,6 +7,10 @@ namespace BTCPayServer.Abstractions.Extensions;
|
||||
|
||||
public static class GreenfieldExtensions
|
||||
{
|
||||
public static IActionResult UserNotFound(this ControllerBase ctrl)
|
||||
{
|
||||
return ctrl.CreateAPIError(404, "user-not-found", "The user was not found");
|
||||
}
|
||||
public static IActionResult CreateValidationError(this ControllerBase controller, ModelStateDictionary modelState)
|
||||
{
|
||||
return controller.UnprocessableEntity(modelState.ToGreenfieldValidationError());
|
||||
|
@ -212,7 +212,7 @@ namespace BTCPayServer.Tests
|
||||
var store = await unrestricted.CreateStore(new CreateStoreRequest() { Name = "Pouet lol" });
|
||||
|
||||
// Grant right to another user
|
||||
newUserAPIKey = await unrestricted.CreateAPIKey(newUser.Id, new CreateApiKeyRequest()
|
||||
newUserAPIKey = await unrestricted.CreateAPIKey(newUser.Email, new CreateApiKeyRequest()
|
||||
{
|
||||
Label = "Hello world",
|
||||
Permissions = new Permission[] { Permission.Create(Policies.CanViewInvoices, store.Id) },
|
||||
|
@ -50,12 +50,16 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
return CreateUserAPIKey(_userManager.GetUserId(User), request);
|
||||
}
|
||||
|
||||
[HttpPost("~/api/v1/users/{userId}/api-keys")]
|
||||
[HttpPost("~/api/v1/users/{idOrEmail}/api-keys")]
|
||||
[Authorize(Policy = Policies.CanManageUsers, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
public async Task<IActionResult> CreateUserAPIKey(string userId, CreateApiKeyRequest request)
|
||||
public async Task<IActionResult> CreateUserAPIKey(string idOrEmail, CreateApiKeyRequest request)
|
||||
{
|
||||
request ??= new CreateApiKeyRequest();
|
||||
request.Permissions ??= System.Array.Empty<Permission>();
|
||||
|
||||
var userId = (await _userManager.FindByIdOrEmail(idOrEmail))?.Id;
|
||||
if (userId is null)
|
||||
return this.UserNotFound();
|
||||
var key = new APIKeyData()
|
||||
{
|
||||
Id = Encoders.Hex.EncodeData(RandomUtils.GetBytes(20)),
|
||||
@ -67,14 +71,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
{
|
||||
Permissions = request.Permissions.Select(p => p.ToString()).Distinct().ToArray()
|
||||
});
|
||||
try
|
||||
{
|
||||
await _apiKeyRepository.CreateKey(key);
|
||||
}
|
||||
catch (DbUpdateException)
|
||||
{
|
||||
return this.CreateAPIError("user-not-found", "This user does not exists");
|
||||
}
|
||||
await _apiKeyRepository.CreateKey(key);
|
||||
return Ok(FromModel(key));
|
||||
}
|
||||
|
||||
@ -96,10 +93,13 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
return RevokeAPIKey(_userManager.GetUserId(User), apikey);
|
||||
}
|
||||
|
||||
[HttpDelete("~/api/v1/users/{userId}/api-keys/{apikey}", Order = 1)]
|
||||
[HttpDelete("~/api/v1/users/{idOrEmail}/api-keys/{apikey}", Order = 1)]
|
||||
[Authorize(Policy = Policies.CanManageUsers, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
public async Task<IActionResult> RevokeAPIKey(string userId, string apikey)
|
||||
public async Task<IActionResult> RevokeAPIKey(string idOrEmail, string apikey)
|
||||
{
|
||||
var userId = (await _userManager.FindByIdOrEmail(idOrEmail))?.Id;
|
||||
if (userId is null)
|
||||
return this.UserNotFound();
|
||||
if (!string.IsNullOrEmpty(apikey) &&
|
||||
await _apiKeyRepository.Remove(apikey, userId))
|
||||
return Ok();
|
||||
|
@ -20,10 +20,12 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
public class GreenfieldStoreUsersController : ControllerBase
|
||||
{
|
||||
private readonly StoreRepository _storeRepository;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
|
||||
public GreenfieldStoreUsersController(StoreRepository storeRepository, UserManager<ApplicationUser> userManager)
|
||||
{
|
||||
_storeRepository = storeRepository;
|
||||
_userManager = userManager;
|
||||
}
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
[HttpGet("~/api/v1/stores/{storeId}/users")]
|
||||
@ -34,8 +36,8 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
return store == null ? StoreNotFound() : Ok(FromModel(store));
|
||||
}
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
[HttpDelete("~/api/v1/stores/{storeId}/users/{userId}")]
|
||||
public async Task<IActionResult> RemoveStoreUser(string storeId, string userId)
|
||||
[HttpDelete("~/api/v1/stores/{storeId}/users/{idOrEmail}")]
|
||||
public async Task<IActionResult> RemoveStoreUser(string storeId, string idOrEmail)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
if (store == null)
|
||||
@ -43,9 +45,9 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
return StoreNotFound();
|
||||
}
|
||||
|
||||
if (await _storeRepository.RemoveStoreUser(storeId, userId))
|
||||
var userId = await _userManager.FindByIdOrEmail(idOrEmail);
|
||||
if (userId != null && await _storeRepository.RemoveStoreUser(storeId, idOrEmail))
|
||||
{
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
@ -69,22 +69,22 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
[HttpGet("~/api/v1/users/{idOrEmail}")]
|
||||
public async Task<IActionResult> GetUser(string idOrEmail)
|
||||
{
|
||||
var user = (await _userManager.FindByIdAsync(idOrEmail)) ?? await _userManager.FindByEmailAsync(idOrEmail);
|
||||
var user = await _userManager.FindByIdOrEmail(idOrEmail);
|
||||
if (user != null)
|
||||
{
|
||||
return Ok(await FromModel(user));
|
||||
}
|
||||
return UserNotFound();
|
||||
return this.UserNotFound();
|
||||
}
|
||||
|
||||
[Authorize(Policy = Policies.CanModifyServerSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
[HttpPost("~/api/v1/users/{idOrEmail}/lock")]
|
||||
public async Task<IActionResult> LockUser(string idOrEmail, LockUserRequest request)
|
||||
{
|
||||
var user = await _userManager.FindByIdAsync(idOrEmail) ?? await _userManager.FindByEmailAsync(idOrEmail);
|
||||
var user = await _userManager.FindByIdOrEmail(idOrEmail);
|
||||
if (user is null)
|
||||
{
|
||||
return UserNotFound();
|
||||
return this.UserNotFound();
|
||||
}
|
||||
|
||||
var success = await _userService.ToggleUser(user.Id, request.Locked ? DateTimeOffset.MaxValue : null);
|
||||
@ -223,7 +223,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
var user = await _userManager.FindByIdAsync(userId);
|
||||
if (user == null)
|
||||
{
|
||||
return UserNotFound();
|
||||
return this.UserNotFound();
|
||||
}
|
||||
|
||||
// We can safely delete the user if it's not an admin user
|
||||
@ -251,12 +251,5 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
var roles = (await _userManager.GetRolesAsync(data)).ToArray();
|
||||
return UserService.FromModel(data, roles);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private IActionResult UserNotFound()
|
||||
{
|
||||
return this.CreateAPIError(404, "user-not-found", "The user was not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
19
BTCPayServer/UserManagerExtensions.cs
Normal file
19
BTCPayServer/UserManagerExtensions.cs
Normal file
@ -0,0 +1,19 @@
|
||||
#nullable enable
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public static class UserManagerExtensions
|
||||
{
|
||||
public async static Task<TUser?> FindByIdOrEmail<TUser>(this UserManager<TUser> userManager, string? idOrEmail) where TUser : class
|
||||
{
|
||||
if (string.IsNullOrEmpty(idOrEmail))
|
||||
return null;
|
||||
if (idOrEmail.Contains('@'))
|
||||
return await userManager.FindByEmailAsync(idOrEmail);
|
||||
else
|
||||
return await userManager.FindByIdAsync(idOrEmail);
|
||||
}
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/users/{userId}/api-keys/{apikey}": {
|
||||
"/api/v1/users/{idOrEmail}/api-keys/{apikey}": {
|
||||
"delete": {
|
||||
"operationId": "ApiKeys_DeleteUserApiKey",
|
||||
"tags": [
|
||||
@ -43,10 +43,10 @@
|
||||
"description": "Revoke the API key of a target user so that it cannot be used anymore",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "userId",
|
||||
"name": "idOrEmail",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"description": "The target user",
|
||||
"description": "The target user's id or email",
|
||||
"schema": { "type": "string" }
|
||||
},
|
||||
{
|
||||
@ -220,7 +220,7 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/users/{userId}/api-keys": {
|
||||
"/api/v1/users/{idOrEmail}/api-keys": {
|
||||
"post": {
|
||||
"operationId": "ApiKeys_CreateUserApiKey",
|
||||
"tags": [
|
||||
@ -230,10 +230,10 @@
|
||||
"description": "Create a new API Key for a user",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "userId",
|
||||
"name": "idOrEmail",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"description": "The target user",
|
||||
"description": "The target user's id or email",
|
||||
"schema": { "type": "string" }
|
||||
}
|
||||
],
|
||||
|
@ -114,7 +114,7 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/stores/{storeId}/users/{userId}": {
|
||||
"/api/v1/stores/{storeId}/users/{idOrEmail}": {
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Stores (Users)"
|
||||
@ -136,7 +136,7 @@
|
||||
"name": "userId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"description": "The user",
|
||||
"description": "The user's id or email",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
* Remove superflous punctuation in some translations
|
||||
* Update Polski translation
|
||||
* Greenfield: Routes accepting a userId can now also accept userEmail (#4732)
|
||||
|
||||
## 1.8.0
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user