diff --git a/BTCPayServer.Client/Models/ApiHealthData.cs b/BTCPayServer.Client/Models/ApiHealthData.cs index 1f9f50663..bc0f44588 100644 --- a/BTCPayServer.Client/Models/ApiHealthData.cs +++ b/BTCPayServer.Client/Models/ApiHealthData.cs @@ -1,6 +1,3 @@ -using BTCPayServer.Client.JsonConverters; -using Newtonsoft.Json; - namespace BTCPayServer.Client.Models { public class ApiHealthData diff --git a/BTCPayServer.Client/Models/ApiKeyData.cs b/BTCPayServer.Client/Models/ApiKeyData.cs index d9145b68a..9bdbc1c9c 100644 --- a/BTCPayServer.Client/Models/ApiKeyData.cs +++ b/BTCPayServer.Client/Models/ApiKeyData.cs @@ -7,6 +7,7 @@ namespace BTCPayServer.Client.Models { public string ApiKey { get; set; } public string Label { get; set; } + [JsonProperty(ItemConverterType = typeof(PermissionJsonConverter))] public Permission[] Permissions { get; set; } } diff --git a/BTCPayServer.Client/Models/ApplicationUserData.cs b/BTCPayServer.Client/Models/ApplicationUserData.cs index 7c7dd142c..2ef97a166 100644 --- a/BTCPayServer.Client/Models/ApplicationUserData.cs +++ b/BTCPayServer.Client/Models/ApplicationUserData.cs @@ -6,33 +6,20 @@ namespace BTCPayServer.Client.Models /// the id of the user /// public string Id { get; set; } + /// /// the email AND username of the user /// public string Email { get; set; } + /// /// Whether the user has verified their email /// public bool EmailConfirmed { get; set; } + /// /// whether the user needed to verify their email on account creation /// public bool RequiresEmailConfirmation { get; set; } } - - public class CreateApplicationUserRequest - { - /// - /// the email AND username of the new user - /// - public string Email { get; set; } - /// - /// password of the new user - /// - public string Password { get; set; } - /// - /// Whether this user is an administrator. If left null and there are no admins in the system, the user will be created as an admin. - /// - public bool? IsAdministrator { get; set; } - } } diff --git a/BTCPayServer.Client/Models/CreateApiKeyRequest.cs b/BTCPayServer.Client/Models/CreateApiKeyRequest.cs index e79576402..2f535da61 100644 --- a/BTCPayServer.Client/Models/CreateApiKeyRequest.cs +++ b/BTCPayServer.Client/Models/CreateApiKeyRequest.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using BTCPayServer.Client.JsonConverters; +using BTCPayServer.Client.JsonConverters; using Newtonsoft.Json; namespace BTCPayServer.Client.Models @@ -9,6 +6,7 @@ namespace BTCPayServer.Client.Models public class CreateApiKeyRequest { public string Label { get; set; } + [JsonProperty(ItemConverterType = typeof(PermissionJsonConverter))] public Permission[] Permissions { get; set; } } diff --git a/BTCPayServer.Client/Models/CreateApplicationUserRequest.cs b/BTCPayServer.Client/Models/CreateApplicationUserRequest.cs new file mode 100644 index 000000000..b348d179f --- /dev/null +++ b/BTCPayServer.Client/Models/CreateApplicationUserRequest.cs @@ -0,0 +1,20 @@ +namespace BTCPayServer.Client.Models +{ + public class CreateApplicationUserRequest + { + /// + /// the email AND username of the new user + /// + public string Email { get; set; } + + /// + /// password of the new user + /// + public string Password { get; set; } + + /// + /// Whether this user is an administrator. If left null and there are no admins in the system, the user will be created as an admin. + /// + public bool? IsAdministrator { get; set; } + } +} diff --git a/BTCPayServer.Client/Models/CreateStoreRequest.cs b/BTCPayServer.Client/Models/CreateStoreRequest.cs index e6e3babc1..cbba444f8 100644 --- a/BTCPayServer.Client/Models/CreateStoreRequest.cs +++ b/BTCPayServer.Client/Models/CreateStoreRequest.cs @@ -1,7 +1,6 @@ namespace BTCPayServer.Client.Models { - public class CreateStoreRequest + public class CreateStoreRequest : StoreBaseData { - public string Name { get; set; } } } diff --git a/BTCPayServer.Client/Models/StoreData.cs b/BTCPayServer.Client/Models/StoreData.cs index ef51574dc..779fc1978 100644 --- a/BTCPayServer.Client/Models/StoreData.cs +++ b/BTCPayServer.Client/Models/StoreData.cs @@ -1,11 +1,10 @@ namespace BTCPayServer.Client.Models { - public class StoreData: StoreBaseData + public class StoreData : StoreBaseData { /// /// the id of the store /// public string Id { get; set; } - } } diff --git a/BTCPayServer.Client/Models/UpdateStoreRequest.cs b/BTCPayServer.Client/Models/UpdateStoreRequest.cs index 9430533ad..27267c7e1 100644 --- a/BTCPayServer.Client/Models/UpdateStoreRequest.cs +++ b/BTCPayServer.Client/Models/UpdateStoreRequest.cs @@ -1,6 +1,6 @@ namespace BTCPayServer.Client.Models { - public class UpdateStoreRequest: StoreBaseData + public class UpdateStoreRequest : StoreBaseData { } } diff --git a/BTCPayServer.Data/Data/StoreData.cs b/BTCPayServer.Data/Data/StoreData.cs index a00a0f640..b5fe2097f 100644 --- a/BTCPayServer.Data/Data/StoreData.cs +++ b/BTCPayServer.Data/Data/StoreData.cs @@ -1,10 +1,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Text; -using Newtonsoft.Json.Linq; -using System.Security.Claims; namespace BTCPayServer.Data { @@ -15,76 +11,39 @@ namespace BTCPayServer.Data LowSpeed = 2, LowMediumSpeed = 3 } + public class StoreData { - public string Id - { - get; - set; - } + public string Id { get; set; } + public List UserStores { get; set; } - public List UserStores - { - get; set; - } - public List Apps - { - get; set; - } - - public List PaymentRequests - { - get; set; - } + public List Apps { get; set; } + + public List PaymentRequests { get; set; } public List Invoices { get; set; } [Obsolete("Use GetDerivationStrategies instead")] - public string DerivationStrategy - { - get; set; - } + public string DerivationStrategy { get; set; } [Obsolete("Use GetDerivationStrategies instead")] - public string DerivationStrategies - { - get; - set; - } + public string DerivationStrategies { get; set; } - public string StoreName - { - get; set; - } + public string StoreName { get; set; } - public SpeedPolicy SpeedPolicy - { - get; set; - } + public SpeedPolicy SpeedPolicy { get; set; } = SpeedPolicy.MediumSpeed; - public string StoreWebsite - { - get; set; - } + public string StoreWebsite { get; set; } - public byte[] StoreCertificate - { - get; set; - } + public byte[] StoreCertificate { get; set; } - [NotMapped] - public string Role - { - get; set; - } + [NotMapped] public string Role { get; set; } + + public byte[] StoreBlob { get; set; } - public byte[] StoreBlob - { - get; - set; - } [Obsolete("Use GetDefaultPaymentId instead")] public string DefaultCrypto { get; set; } + public List PairedSINs { get; set; } public IEnumerable APIKeys { get; set; } } diff --git a/BTCPayServer/Controllers/GreenField/StoresController.cs b/BTCPayServer/Controllers/GreenField/StoresController.cs index 1b77b02f4..240812e25 100644 --- a/BTCPayServer/Controllers/GreenField/StoresController.cs +++ b/BTCPayServer/Controllers/GreenField/StoresController.cs @@ -9,7 +9,6 @@ using BTCPayServer.Services.Stores; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.ModelBinding; namespace BTCPayServer.Controllers.GreenField { @@ -66,27 +65,36 @@ namespace BTCPayServer.Controllers.GreenField [HttpPost("~/api/v1/stores")] [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] - public async Task> CreateStore(CreateStoreRequest request) + public async Task CreateStore(CreateStoreRequest request) { - if (request?.Name is null) - return BadRequest(CreateValidationProblem(nameof(request.Name), "Name is missing")); - var store = await _storeRepository.CreateStore(_userManager.GetUserId(User), request.Name); + var validationResult = Validate(request); + if (validationResult != null) + { + return validationResult; + } + + var store = new Data.StoreData(); + ToModel(request, store); + await _storeRepository.CreateStore(_userManager.GetUserId(User), store); return Ok(FromModel(store)); } [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] [HttpPut("~/api/v1/stores/{storeId}")] - public async Task UpdateStore(string storeId, UpdateStoreRequest request) + public async Task UpdateStore(string storeId, UpdateStoreRequest request) { var store = HttpContext.GetStoreData(); if (store == null) { return NotFound(); } + var validationResult = Validate(request); + if (validationResult != null) + { + return validationResult; + } - if (request?.Name is null) - return BadRequest(CreateValidationProblem(nameof(request.Name), "Name is missing")); - store.StoreName = request.Name; + ToModel(request, store); await _storeRepository.UpdateStore(store); return Ok(FromModel(store)); } @@ -100,11 +108,16 @@ namespace BTCPayServer.Controllers.GreenField }; } - private ValidationProblemDetails CreateValidationProblem(string propertyName, string errorMessage) + private static void ToModel(StoreBaseData restModel,Data.StoreData model) { - var modelState = new ModelStateDictionary(); - modelState.AddModelError(propertyName, errorMessage); - return new ValidationProblemDetails(modelState); + model.StoreName = restModel.Name; + } + + private IActionResult Validate(StoreBaseData request) + { + if (request?.Name is null) + ModelState.AddModelError(nameof(request.Name), "Name is missing"); + return !ModelState.IsValid ? BadRequest(new ValidationProblemDetails(ModelState)) : null; } } } diff --git a/BTCPayServer/Services/Stores/StoreRepository.cs b/BTCPayServer/Services/Stores/StoreRepository.cs index 09c1e6cac..d51070b5f 100644 --- a/BTCPayServer/Services/Stores/StoreRepository.cs +++ b/BTCPayServer/Services/Stores/StoreRepository.cs @@ -158,33 +158,36 @@ namespace BTCPayServer.Services.Stores } } - public async Task CreateStore(string ownerId, string name) + public async Task CreateStore(string ownerId, StoreData storeData) { - if (string.IsNullOrEmpty(name)) - throw new ArgumentException("name should not be empty", nameof(name)); + if (!string.IsNullOrEmpty(storeData.Id)) + throw new ArgumentException("id should be empty", nameof(storeData.StoreName)); + if (string.IsNullOrEmpty(storeData.StoreName)) + throw new ArgumentException("name should not be empty", nameof(storeData.StoreName)); if (ownerId == null) throw new ArgumentNullException(nameof(ownerId)); using (var ctx = _ContextFactory.CreateContext()) { - StoreData store = new StoreData - { - Id = Encoders.Base58.EncodeData(RandomUtils.GetBytes(32)), - StoreName = name, - SpeedPolicy = SpeedPolicy.MediumSpeed - }; + storeData.Id = Encoders.Base58.EncodeData(RandomUtils.GetBytes(32)); var userStore = new UserStore { - StoreDataId = store.Id, + StoreDataId = storeData.Id, ApplicationUserId = ownerId, - Role = "Owner" + Role = StoreRoles.Owner }; - ctx.Add(store); + ctx.Add(storeData); ctx.Add(userStore); - await ctx.SaveChangesAsync().ConfigureAwait(false); - return store; + await ctx.SaveChangesAsync(); } } + public async Task CreateStore(string ownerId, string name) + { + var store = new StoreData() {StoreName = name}; + await CreateStore(ownerId,store); + return store; + } + public async Task RemoveStore(string storeId, string userId) { using (var ctx = _ContextFactory.CreateContext())