mirror of
https://github.com/bitwarden/server.git
synced 2025-07-03 00:52:49 -05:00
Families for enterprise/stripe integrations (#1699)
* Add PlanSponsorshipType to static store * Add sponsorship type to token and creates sponsorship * PascalCase properties * Require sponsorship for remove * Create subscription sponsorship helper class * Handle Sponsored subscription changes * Add sponsorship id to subscription metadata * Make sponsoring references nullable This state indicates that a sponsorship has lapsed, but was not able to be reverted for billing reasons * WIP: Validate and remove subscriptions * Update sponsorships on organization and org user delete * Add friendly name to organization sponsorship
This commit is contained in:
@ -42,8 +42,11 @@ namespace Bit.Api.Controllers
|
||||
{
|
||||
// TODO: validate has right to sponsor, send sponsorship email
|
||||
var sponsoringOrgIdGuid = new Guid(sponsoringOrgId);
|
||||
var requiredSponsoringProductType = StaticStore.GetSponsoredPlan(model.PlanSponsorshipType)?.SponsoringProductType;
|
||||
var sponsoringOrg = await _organizationRepository.GetByIdAsync(sponsoringOrgIdGuid);
|
||||
if (sponsoringOrg == null || !PlanTypeHelper.HasEnterprisePlan(sponsoringOrg))
|
||||
if (requiredSponsoringProductType == null ||
|
||||
sponsoringOrg == null ||
|
||||
StaticStore.GetPlan(sponsoringOrg.PlanType).Product != requiredSponsoringProductType.Value)
|
||||
{
|
||||
throw new BadRequestException("Specified Organization cannot sponsor other organizations.");
|
||||
}
|
||||
@ -64,14 +67,14 @@ namespace Bit.Api.Controllers
|
||||
throw new BadRequestException("Can only sponsor one organization per Organization User.");
|
||||
}
|
||||
|
||||
await _organizationsSponsorshipService.OfferSponsorshipAsync(sponsoringOrg, sponsoringOrgUser, model.PlanSponsorshipType, model.sponsoredEmail);
|
||||
await _organizationsSponsorshipService.OfferSponsorshipAsync(sponsoringOrg, sponsoringOrgUser,
|
||||
model.PlanSponsorshipType, model.SponsoredEmail, model.FriendlyName);
|
||||
}
|
||||
|
||||
[HttpPost("sponsored/redeem/families-for-enterprise")]
|
||||
[SelfHosted(NotSelfHostedOnly = true)]
|
||||
public async Task RedeemSponsorship([FromQuery] string sponsorshipToken, [FromBody] OrganizationSponsorshipRedeemRequestModel model)
|
||||
{
|
||||
// TODO: parse out sponsorshipInfo
|
||||
if (!await _organizationsSponsorshipService.ValidateRedemptionTokenAsync(sponsorshipToken))
|
||||
{
|
||||
throw new BadRequestException("Failed to parse sponsorship token.");
|
||||
@ -99,9 +102,12 @@ namespace Bit.Api.Controllers
|
||||
throw new BadRequestException("Cannot redeem a sponsorship offer for an organization that is already sponsored. Revoke existing sponsorship first.");
|
||||
}
|
||||
|
||||
// Check org to sponsor's product type
|
||||
var requiredSponsoredProductType = StaticStore.GetSponsoredPlan(model.PlanSponsorshipType)?.SponsoredProductType;
|
||||
var organizationToSponsor = await _organizationRepository.GetByIdAsync(model.SponsoredOrganizationId);
|
||||
// TODO: only current families plan?
|
||||
if (organizationToSponsor == null || !PlanTypeHelper.HasFamiliesPlan(organizationToSponsor))
|
||||
if (requiredSponsoredProductType == null ||
|
||||
organizationToSponsor == null ||
|
||||
StaticStore.GetPlan(organizationToSponsor.PlanType).Product != requiredSponsoredProductType.Value)
|
||||
{
|
||||
throw new BadRequestException("Can only redeem sponsorship offer on families organizations.");
|
||||
}
|
||||
@ -124,12 +130,19 @@ namespace Bit.Api.Controllers
|
||||
|
||||
var existingOrgSponsorship = await _organizationSponsorshipRepository
|
||||
.GetBySponsoringOrganizationUserIdAsync(sponsoringOrgUserIdGuid);
|
||||
if (existingOrgSponsorship == null)
|
||||
if (existingOrgSponsorship == null || existingOrgSponsorship.SponsoredOrganizationId == null)
|
||||
{
|
||||
throw new BadRequestException("You are not currently sponsoring and organization.");
|
||||
throw new BadRequestException("You are not currently sponsoring an organization.");
|
||||
}
|
||||
|
||||
await _organizationsSponsorshipService.RemoveSponsorshipAsync(existingOrgSponsorship);
|
||||
var sponsoredOrganization = await _organizationRepository
|
||||
.GetByIdAsync(existingOrgSponsorship.SponsoredOrganizationId.Value);
|
||||
if (sponsoredOrganization == null)
|
||||
{
|
||||
throw new BadRequestException("Unable to find the sponsored Organization.");
|
||||
}
|
||||
|
||||
await _organizationsSponsorshipService.RemoveSponsorshipAsync(sponsoredOrganization, existingOrgSponsorship);
|
||||
}
|
||||
|
||||
[HttpDelete("sponsored/{sponsoredOrgId}")]
|
||||
@ -146,12 +159,20 @@ namespace Bit.Api.Controllers
|
||||
|
||||
var existingOrgSponsorship = await _organizationSponsorshipRepository
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrgIdGuid);
|
||||
if (existingOrgSponsorship == null)
|
||||
if (existingOrgSponsorship == null || existingOrgSponsorship.SponsoredOrganizationId == null)
|
||||
{
|
||||
throw new BadRequestException("The requested organization is not currently being sponsored.");
|
||||
}
|
||||
|
||||
await _organizationsSponsorshipService.RemoveSponsorshipAsync(existingOrgSponsorship);
|
||||
var sponsoredOrganization = await _organizationRepository
|
||||
.GetByIdAsync(existingOrgSponsorship.SponsoredOrganizationId.Value);
|
||||
if (sponsoredOrganization == null)
|
||||
{
|
||||
throw new BadRequestException("Unable to find the sponsored Organization.");
|
||||
}
|
||||
|
||||
|
||||
await _organizationsSponsorshipService.RemoveSponsorshipAsync(sponsoredOrganization, existingOrgSponsorship);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user