mirror of
https://github.com/bitwarden/server.git
synced 2024-11-26 12:55:17 +01:00
create org with license file
This commit is contained in:
parent
e4ec09fd0c
commit
5259b07889
@ -395,35 +395,9 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
var valid = model.Validate(_globalSettings);
|
var valid = model.Validate(_globalSettings);
|
||||||
UserLicense license = null;
|
UserLicense license = null;
|
||||||
if(valid && _globalSettings.SelfHosted && model.License != null)
|
if(valid && _globalSettings.SelfHosted)
|
||||||
{
|
{
|
||||||
if(!HttpContext.Request.ContentLength.HasValue || HttpContext.Request.ContentLength.Value > 51200) // 50 KB
|
license = await ApiHelpers.ReadJsonFileFromBody<UserLicense>(HttpContext, model.License);
|
||||||
{
|
|
||||||
valid = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using(var stream = model.License.OpenReadStream())
|
|
||||||
using(var reader = new StreamReader(stream))
|
|
||||||
{
|
|
||||||
var s = await reader.ReadToEndAsync();
|
|
||||||
if(string.IsNullOrWhiteSpace(s))
|
|
||||||
{
|
|
||||||
valid = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
license = JsonConvert.DeserializeObject<UserLicense>(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
valid = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!valid || (_globalSettings.SelfHosted && license == null))
|
if(!valid || (_globalSettings.SelfHosted && license == null))
|
||||||
@ -488,7 +462,7 @@ namespace Bit.Api.Controllers
|
|||||||
[HttpPut("license")]
|
[HttpPut("license")]
|
||||||
[HttpPost("license")]
|
[HttpPost("license")]
|
||||||
[SelfHosted(SelfHostedOnly = true)]
|
[SelfHosted(SelfHostedOnly = true)]
|
||||||
public async Task PutLicense(UpdateLicenseRequestModel model)
|
public async Task PutLicense(LicenseRequestModel model)
|
||||||
{
|
{
|
||||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||||
if(user == null)
|
if(user == null)
|
||||||
@ -496,24 +470,7 @@ namespace Bit.Api.Controllers
|
|||||||
throw new UnauthorizedAccessException();
|
throw new UnauthorizedAccessException();
|
||||||
}
|
}
|
||||||
|
|
||||||
UserLicense license = null;
|
var license = await ApiHelpers.ReadJsonFileFromBody<UserLicense>(HttpContext, model.License);
|
||||||
if(HttpContext.Request.ContentLength.HasValue && HttpContext.Request.ContentLength.Value <= 51200) // 50 KB
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using(var stream = model.License.OpenReadStream())
|
|
||||||
using(var reader = new StreamReader(stream))
|
|
||||||
{
|
|
||||||
var s = await reader.ReadToEndAsync();
|
|
||||||
if(!string.IsNullOrWhiteSpace(s))
|
|
||||||
{
|
|
||||||
license = JsonConvert.DeserializeObject<UserLicense>(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
if(license == null)
|
if(license == null)
|
||||||
{
|
{
|
||||||
throw new BadRequestException("Invalid license");
|
throw new BadRequestException("Invalid license");
|
||||||
|
@ -11,6 +11,8 @@ using Bit.Core;
|
|||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Bit.Core.Models.Table;
|
using Bit.Core.Models.Table;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using Bit.Api.Utilities;
|
||||||
|
using Bit.Core.Models.Business;
|
||||||
|
|
||||||
namespace Bit.Api.Controllers
|
namespace Bit.Api.Controllers
|
||||||
{
|
{
|
||||||
@ -94,6 +96,7 @@ namespace Bit.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("")]
|
[HttpPost("")]
|
||||||
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task<OrganizationResponseModel> Post([FromBody]OrganizationCreateRequestModel model)
|
public async Task<OrganizationResponseModel> Post([FromBody]OrganizationCreateRequestModel model)
|
||||||
{
|
{
|
||||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||||
@ -107,6 +110,26 @@ namespace Bit.Api.Controllers
|
|||||||
return new OrganizationResponseModel(result.Item1);
|
return new OrganizationResponseModel(result.Item1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("license")]
|
||||||
|
[SelfHosted(SelfHostedOnly = true)]
|
||||||
|
public async Task<OrganizationResponseModel> PostLicense(OrganizationCreateLicenseRequestModel model)
|
||||||
|
{
|
||||||
|
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||||
|
if(user == null)
|
||||||
|
{
|
||||||
|
throw new UnauthorizedAccessException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var license = await ApiHelpers.ReadJsonFileFromBody<OrganizationLicense>(HttpContext, model.License);
|
||||||
|
if(license == null)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Invalid license");
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await _organizationService.SignUpAsync(license, user, model.Key);
|
||||||
|
return new OrganizationResponseModel(result.Item1);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPut("{id}")]
|
[HttpPut("{id}")]
|
||||||
[HttpPost("{id}")]
|
[HttpPost("{id}")]
|
||||||
public async Task<OrganizationResponseModel> Put(string id, [FromBody]OrganizationUpdateRequestModel model)
|
public async Task<OrganizationResponseModel> Put(string id, [FromBody]OrganizationUpdateRequestModel model)
|
||||||
@ -132,6 +155,7 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
[HttpPut("{id}/payment")]
|
[HttpPut("{id}/payment")]
|
||||||
[HttpPost("{id}/payment")]
|
[HttpPost("{id}/payment")]
|
||||||
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task PutPayment(string id, [FromBody]PaymentRequestModel model)
|
public async Task PutPayment(string id, [FromBody]PaymentRequestModel model)
|
||||||
{
|
{
|
||||||
var orgIdGuid = new Guid(id);
|
var orgIdGuid = new Guid(id);
|
||||||
@ -145,6 +169,7 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
[HttpPut("{id}/upgrade")]
|
[HttpPut("{id}/upgrade")]
|
||||||
[HttpPost("{id}/upgrade")]
|
[HttpPost("{id}/upgrade")]
|
||||||
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task PutUpgrade(string id, [FromBody]OrganizationUpgradeRequestModel model)
|
public async Task PutUpgrade(string id, [FromBody]OrganizationUpgradeRequestModel model)
|
||||||
{
|
{
|
||||||
var orgIdGuid = new Guid(id);
|
var orgIdGuid = new Guid(id);
|
||||||
@ -158,6 +183,7 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
[HttpPut("{id}/seat")]
|
[HttpPut("{id}/seat")]
|
||||||
[HttpPost("{id}/seat")]
|
[HttpPost("{id}/seat")]
|
||||||
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task PutSeat(string id, [FromBody]OrganizationSeatRequestModel model)
|
public async Task PutSeat(string id, [FromBody]OrganizationSeatRequestModel model)
|
||||||
{
|
{
|
||||||
var orgIdGuid = new Guid(id);
|
var orgIdGuid = new Guid(id);
|
||||||
@ -171,6 +197,7 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
[HttpPut("{id}/storage")]
|
[HttpPut("{id}/storage")]
|
||||||
[HttpPost("{id}/storage")]
|
[HttpPost("{id}/storage")]
|
||||||
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task PutStorage(string id, [FromBody]StorageRequestModel model)
|
public async Task PutStorage(string id, [FromBody]StorageRequestModel model)
|
||||||
{
|
{
|
||||||
var orgIdGuid = new Guid(id);
|
var orgIdGuid = new Guid(id);
|
||||||
@ -183,6 +210,7 @@ namespace Bit.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("{id}/verify-bank")]
|
[HttpPost("{id}/verify-bank")]
|
||||||
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task PostVerifyBank(string id, [FromBody]OrganizationVerifyBankRequestModel model)
|
public async Task PostVerifyBank(string id, [FromBody]OrganizationVerifyBankRequestModel model)
|
||||||
{
|
{
|
||||||
var orgIdGuid = new Guid(id);
|
var orgIdGuid = new Guid(id);
|
||||||
@ -196,6 +224,7 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
[HttpPut("{id}/cancel")]
|
[HttpPut("{id}/cancel")]
|
||||||
[HttpPost("{id}/cancel")]
|
[HttpPost("{id}/cancel")]
|
||||||
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task PutCancel(string id)
|
public async Task PutCancel(string id)
|
||||||
{
|
{
|
||||||
var orgIdGuid = new Guid(id);
|
var orgIdGuid = new Guid(id);
|
||||||
@ -209,6 +238,7 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
[HttpPut("{id}/reinstate")]
|
[HttpPut("{id}/reinstate")]
|
||||||
[HttpPost("{id}/reinstate")]
|
[HttpPost("{id}/reinstate")]
|
||||||
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task PutReinstate(string id)
|
public async Task PutReinstate(string id)
|
||||||
{
|
{
|
||||||
var orgIdGuid = new Guid(id);
|
var orgIdGuid = new Guid(id);
|
||||||
|
33
src/Api/Utilities/ApiHelpers.cs
Normal file
33
src/Api/Utilities/ApiHelpers.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bit.Api.Utilities
|
||||||
|
{
|
||||||
|
public static class ApiHelpers
|
||||||
|
{
|
||||||
|
public async static Task<T> ReadJsonFileFromBody<T>(HttpContext httpContext, IFormFile file, long maxSize = 51200)
|
||||||
|
{
|
||||||
|
T obj = default(T);
|
||||||
|
if(file != null && httpContext.Request.ContentLength.HasValue && httpContext.Request.ContentLength.Value <= maxSize)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using(var stream = file.OpenReadStream())
|
||||||
|
using(var reader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
var s = await reader.ReadToEndAsync();
|
||||||
|
if(!string.IsNullOrWhiteSpace(s))
|
||||||
|
{
|
||||||
|
obj = JsonConvert.DeserializeObject<T>(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -111,7 +111,7 @@ namespace Bit.Core
|
|||||||
|
|
||||||
public class InstallationSettings
|
public class InstallationSettings
|
||||||
{
|
{
|
||||||
public Guid? Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
public string IdentityUri { get; set; }
|
public string IdentityUri { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
|
|
||||||
namespace Bit.Core.Models.Api
|
namespace Bit.Core.Models.Api
|
||||||
{
|
{
|
||||||
public class UpdateLicenseRequestModel
|
public class LicenseRequestModel
|
||||||
{
|
{
|
||||||
[Required]
|
[Required]
|
||||||
public IFormFile License { get; set; }
|
public IFormFile License { get; set; }
|
@ -0,0 +1,10 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Api
|
||||||
|
{
|
||||||
|
public class OrganizationCreateLicenseRequestModel : LicenseRequestModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Key { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
using Bit.Core.Models.Table;
|
using Bit.Core.Models.Table;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Bit.Core.Models.Business
|
namespace Bit.Core.Models.Business
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,7 @@ namespace Bit.Core.Services
|
|||||||
Task AdjustSeatsAsync(Guid organizationId, int seatAdjustment);
|
Task AdjustSeatsAsync(Guid organizationId, int seatAdjustment);
|
||||||
Task VerifyBankAsync(Guid organizationId, int amount1, int amount2);
|
Task VerifyBankAsync(Guid organizationId, int amount1, int amount2);
|
||||||
Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationSignup organizationSignup);
|
Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationSignup organizationSignup);
|
||||||
|
Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationLicense license, User owner, string ownerKey);
|
||||||
Task DeleteAsync(Organization organization);
|
Task DeleteAsync(Organization organization);
|
||||||
Task DisableAsync(Guid organizationId, DateTime? expirationDate);
|
Task DisableAsync(Guid organizationId, DateTime? expirationDate);
|
||||||
Task UpdateExpirationDateAsync(Guid organizationId, DateTime? expirationDate);
|
Task UpdateExpirationDateAsync(Guid organizationId, DateTime? expirationDate);
|
||||||
|
@ -26,7 +26,9 @@ namespace Bit.Core.Services
|
|||||||
private readonly IPushNotificationService _pushNotificationService;
|
private readonly IPushNotificationService _pushNotificationService;
|
||||||
private readonly IPushRegistrationService _pushRegistrationService;
|
private readonly IPushRegistrationService _pushRegistrationService;
|
||||||
private readonly IDeviceRepository _deviceRepository;
|
private readonly IDeviceRepository _deviceRepository;
|
||||||
|
private readonly ILicensingService _licensingService;
|
||||||
private readonly StripePaymentService _stripePaymentService;
|
private readonly StripePaymentService _stripePaymentService;
|
||||||
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
|
||||||
public OrganizationService(
|
public OrganizationService(
|
||||||
IOrganizationRepository organizationRepository,
|
IOrganizationRepository organizationRepository,
|
||||||
@ -38,7 +40,9 @@ namespace Bit.Core.Services
|
|||||||
IMailService mailService,
|
IMailService mailService,
|
||||||
IPushNotificationService pushNotificationService,
|
IPushNotificationService pushNotificationService,
|
||||||
IPushRegistrationService pushRegistrationService,
|
IPushRegistrationService pushRegistrationService,
|
||||||
IDeviceRepository deviceRepository)
|
IDeviceRepository deviceRepository,
|
||||||
|
ILicensingService licensingService,
|
||||||
|
GlobalSettings globalSettings)
|
||||||
{
|
{
|
||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
_organizationUserRepository = organizationUserRepository;
|
_organizationUserRepository = organizationUserRepository;
|
||||||
@ -50,7 +54,9 @@ namespace Bit.Core.Services
|
|||||||
_pushNotificationService = pushNotificationService;
|
_pushNotificationService = pushNotificationService;
|
||||||
_pushRegistrationService = pushRegistrationService;
|
_pushRegistrationService = pushRegistrationService;
|
||||||
_deviceRepository = deviceRepository;
|
_deviceRepository = deviceRepository;
|
||||||
|
_licensingService = licensingService;
|
||||||
_stripePaymentService = new StripePaymentService();
|
_stripePaymentService = new StripePaymentService();
|
||||||
|
_globalSettings = globalSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ReplacePaymentMethodAsync(Guid organizationId, string paymentToken)
|
public async Task ReplacePaymentMethodAsync(Guid organizationId, string paymentToken)
|
||||||
@ -401,11 +407,6 @@ namespace Bit.Core.Services
|
|||||||
throw new BadRequestException("Plan not found.");
|
throw new BadRequestException("Plan not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var customerService = new StripeCustomerService();
|
|
||||||
var subscriptionService = new StripeSubscriptionService();
|
|
||||||
StripeCustomer customer = null;
|
|
||||||
StripeSubscription subscription = null;
|
|
||||||
|
|
||||||
if(!plan.MaxStorageGb.HasValue && signup.AdditionalStorageGb > 0)
|
if(!plan.MaxStorageGb.HasValue && signup.AdditionalStorageGb > 0)
|
||||||
{
|
{
|
||||||
throw new BadRequestException("Plan does not allow additional storage.");
|
throw new BadRequestException("Plan does not allow additional storage.");
|
||||||
@ -428,6 +429,11 @@ namespace Bit.Core.Services
|
|||||||
$"{plan.MaxAdditionalSeats.GetValueOrDefault(0)} additional users.");
|
$"{plan.MaxAdditionalSeats.GetValueOrDefault(0)} additional users.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var customerService = new StripeCustomerService();
|
||||||
|
var subscriptionService = new StripeSubscriptionService();
|
||||||
|
StripeCustomer customer = null;
|
||||||
|
StripeSubscription subscription = null;
|
||||||
|
|
||||||
// Pre-generate the org id so that we can save it with the Stripe subscription..
|
// Pre-generate the org id so that we can save it with the Stripe subscription..
|
||||||
Guid newOrgId = CoreHelpers.GenerateComb();
|
Guid newOrgId = CoreHelpers.GenerateComb();
|
||||||
|
|
||||||
@ -525,6 +531,52 @@ namespace Bit.Core.Services
|
|||||||
RevisionDate = DateTime.UtcNow
|
RevisionDate = DateTime.UtcNow
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return await SignUpAsync(organization, signup.Owner.Id, signup.OwnerKey, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Tuple<Organization, OrganizationUser>> SignUpAsync(
|
||||||
|
OrganizationLicense license, User owner, string ownerKey)
|
||||||
|
{
|
||||||
|
if(license == null || !_licensingService.VerifyLicense(license) || !license.CanUse(_globalSettings.Installation.Id))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Invalid license.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var plan = StaticStore.Plans.FirstOrDefault(p => p.Type == license.PlanType && !p.Disabled);
|
||||||
|
if(plan == null)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Plan not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var organization = new Organization
|
||||||
|
{
|
||||||
|
Name = license.Name,
|
||||||
|
BillingEmail = null,
|
||||||
|
BusinessName = null,
|
||||||
|
PlanType = license.PlanType,
|
||||||
|
Seats = license.Seats,
|
||||||
|
MaxCollections = license.MaxCollections,
|
||||||
|
MaxStorageGb = 10240, // 10 TB
|
||||||
|
UseGroups = license.UseGroups,
|
||||||
|
UseDirectory = license.UseDirectory,
|
||||||
|
UseTotp = license.UseTotp,
|
||||||
|
Plan = license.Plan,
|
||||||
|
Gateway = null,
|
||||||
|
GatewayCustomerId = null,
|
||||||
|
GatewaySubscriptionId = null,
|
||||||
|
Enabled = true,
|
||||||
|
ExpirationDate = license.Expires,
|
||||||
|
LicenseKey = license.LicenseKey,
|
||||||
|
CreationDate = DateTime.UtcNow,
|
||||||
|
RevisionDate = DateTime.UtcNow
|
||||||
|
};
|
||||||
|
|
||||||
|
return await SignUpAsync(organization, owner.Id, ownerKey, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Tuple<Organization, OrganizationUser>> SignUpAsync(Organization organization,
|
||||||
|
Guid ownerId, string ownerKey, bool withPayment)
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _organizationRepository.CreateAsync(organization);
|
await _organizationRepository.CreateAsync(organization);
|
||||||
@ -532,8 +584,8 @@ namespace Bit.Core.Services
|
|||||||
var orgUser = new OrganizationUser
|
var orgUser = new OrganizationUser
|
||||||
{
|
{
|
||||||
OrganizationId = organization.Id,
|
OrganizationId = organization.Id,
|
||||||
UserId = signup.Owner.Id,
|
UserId = ownerId,
|
||||||
Key = signup.OwnerKey,
|
Key = ownerKey,
|
||||||
Type = OrganizationUserType.Owner,
|
Type = OrganizationUserType.Owner,
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
Status = OrganizationUserStatusType.Confirmed,
|
||||||
AccessAll = true,
|
AccessAll = true,
|
||||||
@ -546,13 +598,17 @@ namespace Bit.Core.Services
|
|||||||
// push
|
// push
|
||||||
var deviceIds = await GetUserDeviceIdsAsync(orgUser.UserId.Value);
|
var deviceIds = await GetUserDeviceIdsAsync(orgUser.UserId.Value);
|
||||||
await _pushRegistrationService.AddUserRegistrationOrganizationAsync(deviceIds, organization.Id.ToString());
|
await _pushRegistrationService.AddUserRegistrationOrganizationAsync(deviceIds, organization.Id.ToString());
|
||||||
await _pushNotificationService.PushSyncOrgKeysAsync(signup.Owner.Id);
|
await _pushNotificationService.PushSyncOrgKeysAsync(ownerId);
|
||||||
|
|
||||||
return new Tuple<Organization, OrganizationUser>(organization, orgUser);
|
return new Tuple<Organization, OrganizationUser>(organization, orgUser);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await _stripePaymentService.CancelAndRecoverChargesAsync(organization);
|
if(withPayment)
|
||||||
|
{
|
||||||
|
await _stripePaymentService.CancelAndRecoverChargesAsync(organization);
|
||||||
|
}
|
||||||
|
|
||||||
if(organization.Id != default(Guid))
|
if(organization.Id != default(Guid))
|
||||||
{
|
{
|
||||||
await _organizationRepository.DeleteAsync(organization);
|
await _organizationRepository.DeleteAsync(organization);
|
||||||
|
Loading…
Reference in New Issue
Block a user