1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-29 13:25:17 +01:00

Add PlanSponsorshipType to db model

This commit is contained in:
Matt Gibson 2021-11-04 12:51:22 -04:00
parent 079adc60b6
commit d93fcf432f
20 changed files with 75 additions and 18 deletions

View File

@ -64,7 +64,7 @@ namespace Bit.Api.Controllers
throw new BadRequestException("Can only sponsor one organization per Organization User.");
}
await _organizationsSponsorshipService.OfferSponsorshipAsync(sponsoringOrg, sponsoringOrgUser, model.sponsoredEmail);
await _organizationsSponsorshipService.OfferSponsorshipAsync(sponsoringOrg, sponsoringOrgUser, model.PlanSponsorshipType, model.sponsoredEmail);
}
[HttpPost("sponsored/redeem/families-for-enterprise")]

View File

@ -0,0 +1,10 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Enums
{
public enum PlanSponsorshipType : byte
{
[Display(Name = "Families For Enterprise")]
FamiliesForEnterprise = 0,
}
}

View File

@ -1,13 +1,18 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api.Request
{
public class OrganizationSponsorshipRequestModel
{
[Required]
public PlanSponsorshipType PlanSponsorshipType { get; set; }
[Required]
public Guid OrganizationUserId { get; set; }
[Required]
[StringLength(256)]
[StrictEmailAddress]

View File

@ -1,5 +1,6 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Table
@ -15,6 +16,7 @@ namespace Bit.Core.Models.Table
public Guid? SponsoredOrganizationId { get; set; }
[MaxLength(256)]
public string OfferedToEmail { get; set; }
public PlanSponsorshipType? PlanSponsorshipType { get; set; }
[Required]
public bool CloudSponsor { get; set; }
public DateTime? LastSyncDate { get; set; }

View File

@ -1,4 +1,5 @@
using System.Threading.Tasks;
using Bit.Core.Enums;
using Bit.Core.Models.Table;
namespace Bit.Core.Services
@ -6,7 +7,7 @@ namespace Bit.Core.Services
public interface IOrganizationSponsorshipService
{
Task<bool> ValidateRedemptionTokenAsync(string encryptedToken);
Task OfferSponsorshipAsync(Organization sponsoringOrg, OrganizationUser sponsoringOrgUser, string sponsoredEmail);
Task OfferSponsorshipAsync(Organization sponsoringOrg, OrganizationUser sponsoringOrgUser, PlanSponsorshipType sponsorshipType, string sponsoredEmail);
Task SetUpSponsorshipAsync(OrganizationSponsorship sponsorship, Organization sponsoredOrganization);
Task RemoveSponsorshipAsync(OrganizationSponsorship sponsorship);
}

View File

@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using Bit.Core.Enums;
using Bit.Core.Models.Table;
using Bit.Core.Repositories;
using Microsoft.AspNetCore.DataProtection;
@ -38,25 +39,31 @@ namespace Bit.Core.Services
if (dataParts[0].Equals(FamiliesForEnterpriseTokenName))
{
if (!Guid.TryParse(dataParts[1], out Guid sponsorshipId))
if (!Guid.TryParse(dataParts[1], out Guid sponsorshipId) ||
!Enum.TryParse<PlanSponsorshipType>(dataParts[2], true, out var sponsorshipType))
{
return false;
}
var sponsorship = await _organizationSponsorshipRepository.GetByIdAsync(sponsorshipId);
return sponsorship != null;
if (sponsorship == null || sponsorship.PlanSponsorshipType != sponsorshipType)
{
return false;
}
return true;
}
return false;
}
private string RedemptionToken(Guid sponsorshipId) =>
private string RedemptionToken(Guid sponsorshipId, PlanSponsorshipType sponsorshipType) =>
string.Concat(
TokenClearTextPrefix,
_dataProtector.Protect($"{FamiliesForEnterpriseTokenName} {sponsorshipId}")
_dataProtector.Protect($"{FamiliesForEnterpriseTokenName} {sponsorshipId} {sponsorshipType}")
);
public async Task OfferSponsorshipAsync(Organization sponsoringOrg, OrganizationUser sponsoringOrgUser, string sponsoredEmail)
public async Task OfferSponsorshipAsync(Organization sponsoringOrg, OrganizationUser sponsoringOrgUser, PlanSponsorshipType sponsorshipType, string sponsoredEmail)
{
var sponsorship = new OrganizationSponsorship
{

View File

@ -5,6 +5,7 @@ CREATE PROCEDURE [dbo].[OrganizationSponsorship_Create]
@SponsoringOrganizationUserID UNIQUEIDENTIFIER,
@SponsoredOrganizationId UNIQUEIDENTIFIER,
@OfferedToEmail NVARCHAR(256),
@PlanSponsorshipType TINYINT,
@CloudSponsor BIT,
@LastSyncDate DATETIME2 (7),
@TimesRenewedWithoutValidation TINYINT,
@ -21,6 +22,7 @@ BEGIN
[SponsoringOrganizationUserID],
[SponsoredOrganizationId],
[OfferedToEmail],
[PlanSponsorshipType],
[CloudSponsor],
[LastSyncDate],
[TimesRenewedWithoutValidation],
@ -34,6 +36,7 @@ BEGIN
@SponsoringOrganizationUserID,
@SponsoredOrganizationId,
@OfferedToEmail,
@PlanSponsorshipType,
@CloudSponsor,
@LastSyncDate,
@TimesRenewedWithoutValidation,

View File

@ -5,6 +5,7 @@ CREATE PROCEDURE [dbo].[OrganizationSponsorship_Update]
@SponsoringOrganizationUserID UNIQUEIDENTIFIER,
@SponsoredOrganizationId UNIQUEIDENTIFIER,
@OfferedToEmail NVARCHAR(256),
@PlanSponsorshipType TINYINT,
@CloudSponsor BIT,
@LastSyncDate DATETIME2 (7),
@TimesRenewedWithoutValidation TINYINT,
@ -21,6 +22,7 @@ BEGIN
[SponsoringOrganizationUserID] = @SponsoringOrganizationUserID,
[SponsoredOrganizationId] = @SponsoredOrganizationId,
[OfferedToEmail] = @OfferedToEmail,
[PlanSponsorshipType] = @PlanSponsorshipType,
[CloudSponsor] = @CloudSponsor,
[LastSyncDate] = @LastSyncDate,
[TimesRenewedWithoutValidation] = @TimesRenewedWithoutValidation,

View File

@ -2,9 +2,10 @@ CREATE TABLE [dbo].[OrganizationSponsorship] (
[Id] UNIQUEIDENTIFIER NOT NULL,
[InstallationId] UNIQUEIDENTIFIER NULL,
[SponsoringOrganizationId] UNIQUEIDENTIFIER NOT NULL,
[SponsorginOrganizationUserID] UNIQUEIDENTIFIER NOT NULL,
[SponsoringOrganizationUserID] UNIQUEIDENTIFIER NOT NULL,
[SponsoredOrganizationId] UNIQUEIDENTIFIER NULL,
[OfferedToEmail] NVARCHAR (256) NULL,
[PlanSponsorshipType] TINYINT NULL,
[CloudSponsor] BIT NULL,
[LastSyncDate] DATETIME2 (7) NULL,
[TimesRenewedWithoutValidation] TINYINT DEFAULT 0,

View File

@ -44,7 +44,7 @@ namespace Bit.Api.Test.Controllers
Assert.Contains("Specified Organization cannot sponsor other organizations.", exception.Message);
await sutProvider.GetDependency<IOrganizationSponsorshipService>()
.DidNotReceiveWithAnyArgs()
.OfferSponsorshipAsync(default, default, default);
.OfferSponsorshipAsync(default, default, default, default);
}
public static IEnumerable<object[]> NonConfirmedOrganizationUsersStatuses =>
@ -73,7 +73,7 @@ namespace Bit.Api.Test.Controllers
Assert.Contains("Only confirm users can sponsor other organizations.", exception.Message);
await sutProvider.GetDependency<IOrganizationSponsorshipService>()
.DidNotReceiveWithAnyArgs()
.OfferSponsorshipAsync(default, default, default);
.OfferSponsorshipAsync(default, default, default, default);
}
[Theory]
@ -96,7 +96,7 @@ namespace Bit.Api.Test.Controllers
Assert.Contains("Can only create organization sponsorships for yourself.", exception.Message);
await sutProvider.GetDependency<IOrganizationSponsorshipService>()
.DidNotReceiveWithAnyArgs()
.OfferSponsorshipAsync(default, default, default);
.OfferSponsorshipAsync(default, default, default, default);
}
[Theory]
@ -121,7 +121,7 @@ namespace Bit.Api.Test.Controllers
Assert.Contains("Can only sponsor one organization per Organization User.", exception.Message);
await sutProvider.GetDependency<IOrganizationSponsorshipService>()
.DidNotReceiveWithAnyArgs()
.OfferSponsorshipAsync(default, default, default);
.OfferSponsorshipAsync(default, default, default, default);
}
[Theory]

View File

@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Bit.Core.Enums;
using Bit.Core.Models.Table;
using Bit.Core.Repositories;
using Bit.Core.Services;
@ -35,7 +36,8 @@ namespace Bit.Core.Test.Services
public async Task OfferSponsorship_CreatesSponsorship(Organization sponsoringOrg, OrganizationUser sponsoringOrgUser,
string sponsoredEmail, SutProvider<OrganizationSponsorshipService> sutProvider)
{
await sutProvider.Sut.OfferSponsorshipAsync(sponsoringOrg, sponsoringOrgUser, sponsoredEmail);
await sutProvider.Sut.OfferSponsorshipAsync(sponsoringOrg, sponsoringOrgUser,
PlanSponsorshipType.FamiliesForEnterprise, sponsoredEmail);
var expectedSponsorship = new OrganizationSponsorship
{
@ -64,7 +66,9 @@ namespace Bit.Core.Test.Services
return expectedException;
});
var actualException = await Assert.ThrowsAsync<Exception>(() => sutProvider.Sut.OfferSponsorshipAsync(sponsoringOrg, sponsoringOrgUser, sponsoredEmail));
var actualException = await Assert.ThrowsAsync<Exception>(() =>
sutProvider.Sut.OfferSponsorshipAsync(sponsoringOrg, sponsoringOrgUser,
PlanSponsorshipType.FamiliesForEnterprise, sponsoredEmail));
Assert.Same(expectedException, actualException);
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().Received(1)

View File

@ -8,6 +8,7 @@ CREATE TABLE [dbo].[OrganizationSponsorship] (
[SponsoringOrganizationUserID] UNIQUEIDENTIFIER NOT NULL,
[SponsoredOrganizationId] UNIQUEIDENTIFIER NULL,
[OfferedToEmail] NVARCHAR (256) NULL,
[PlanSponsorshipType] TINYINT NULL,
[CloudSponsor] BIT NULL,
[LastSyncDate] DATETIME2 (7) NULL,
[TimesRenewedWithoutValidation] TINYINT DEFAULT 0,
@ -114,6 +115,7 @@ CREATE PROCEDURE [dbo].[OrganizationSponsorship_Create]
@SponsoringOrganizationUserID UNIQUEIDENTIFIER,
@SponsoredOrganizationId UNIQUEIDENTIFIER,
@OfferedToEmail NVARCHAR(256),
@PlanSponsorshipType TINYINT,
@CloudSponsor BIT,
@LastSyncDate DATETIME2 (7),
@TimesRenewedWithoutValidation TINYINT,
@ -130,6 +132,7 @@ BEGIN
[SponsoringOrganizationUserID],
[SponsoredOrganizationId],
[OfferedToEmail],
[PlanSponsorshipType],
[CloudSponsor],
[LastSyncDate],
[TimesRenewedWithoutValidation],
@ -143,6 +146,7 @@ BEGIN
@SponsoringOrganizationUserID,
@SponsoredOrganizationId,
@OfferedToEmail,
@PlanSponsorshipType,
@CloudSponsor,
@LastSyncDate,
@TimesRenewedWithoutValidation,
@ -165,6 +169,7 @@ CREATE PROCEDURE [dbo].[OrganizationSponsorship_Update]
@SponsoringOrganizationUserID UNIQUEIDENTIFIER,
@SponsoredOrganizationId UNIQUEIDENTIFIER,
@OfferedToEmail NVARCHAR(256),
@PlanSponsorshipType TINYINT,
@CloudSponsor BIT,
@LastSyncDate DATETIME2 (7),
@TimesRenewedWithoutValidation TINYINT,
@ -181,6 +186,7 @@ BEGIN
[SponsoringOrganizationUserID] = @SponsoringOrganizationUserID,
[SponsoredOrganizationId] = @SponsoredOrganizationId,
[OfferedToEmail] = @OfferedToEmail,
[PlanSponsorshipType] = @PlanSponsorshipType,
[CloudSponsor] = @CloudSponsor,
[LastSyncDate] = @LastSyncDate,
[TimesRenewedWithoutValidation] = @TimesRenewedWithoutValidation,

View File

@ -9,7 +9,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Bit.MySqlMigrations.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20211102213543_OrganizationSponsorship")]
[Migration("20211104164838_OrganizationSponsorship")]
partial class OrganizationSponsorship
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -605,6 +605,9 @@ namespace Bit.MySqlMigrations.Migrations
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<byte?>("PlanSponsorshipType")
.HasColumnType("tinyint unsigned");
b.Property<Guid?>("SponsoredOrganizationId")
.HasColumnType("char(36)");

View File

@ -25,6 +25,7 @@ namespace Bit.MySqlMigrations.Migrations
SponsoredOrganizationId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
OfferedToEmail = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
PlanSponsorshipType = table.Column<byte>(type: "tinyint unsigned", nullable: true),
CloudSponsor = table.Column<bool>(type: "tinyint(1)", nullable: false),
LastSyncDate = table.Column<DateTime>(type: "datetime(6)", nullable: true),
TimesRenewedWithoutValidation = table.Column<byte>(type: "tinyint unsigned", nullable: false),

View File

@ -603,6 +603,9 @@ namespace Bit.MySqlMigrations.Migrations
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<byte?>("PlanSponsorshipType")
.HasColumnType("tinyint unsigned");
b.Property<Guid?>("SponsoredOrganizationId")
.HasColumnType("char(36)");

View File

@ -9,6 +9,7 @@ CREATE TABLE `OrganizationSponsorship` (
`SponsoringOrganizationUserId` char(36) COLLATE ascii_general_ci NOT NULL,
`SponsoredOrganizationId` char(36) COLLATE ascii_general_ci NULL,
`OfferedToEmail` varchar(256) CHARACTER SET utf8mb4 NULL,
`PlanSponsorshipType` tinyint unsigned NULL,
`CloudSponsor` tinyint(1) NOT NULL,
`LastSyncDate` datetime(6) NULL,
`TimesRenewedWithoutValidation` tinyint unsigned NOT NULL,
@ -26,6 +27,6 @@ CREATE INDEX `IX_OrganizationSponsorship_SponsoredOrganizationId` ON `Organizati
CREATE INDEX `IX_OrganizationSponsorship_SponsoringOrganizationId` ON `OrganizationSponsorship` (`SponsoringOrganizationId`);
INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`)
VALUES ('20211102213543_OrganizationSponsorship', '5.0.9');
VALUES ('20211104164838_OrganizationSponsorship', '5.0.9');
COMMIT;

View File

@ -10,7 +10,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Bit.PostgresMigrations.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20211102205745_OrganizationSponsorship")]
[Migration("20211104164532_OrganizationSponsorship")]
partial class OrganizationSponsorship
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -609,6 +609,9 @@ namespace Bit.PostgresMigrations.Migrations
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<byte?>("PlanSponsorshipType")
.HasColumnType("smallint");
b.Property<Guid?>("SponsoredOrganizationId")
.HasColumnType("uuid");

View File

@ -24,6 +24,7 @@ namespace Bit.PostgresMigrations.Migrations
SponsoringOrganizationUserId = table.Column<Guid>(type: "uuid", nullable: false),
SponsoredOrganizationId = table.Column<Guid>(type: "uuid", nullable: true),
OfferedToEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
PlanSponsorshipType = table.Column<byte>(type: "smallint", nullable: true),
CloudSponsor = table.Column<bool>(type: "boolean", nullable: false),
LastSyncDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
TimesRenewedWithoutValidation = table.Column<byte>(type: "smallint", nullable: false),

View File

@ -607,6 +607,9 @@ namespace Bit.PostgresMigrations.Migrations
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<byte?>("PlanSponsorshipType")
.HasColumnType("smallint");
b.Property<Guid?>("SponsoredOrganizationId")
.HasColumnType("uuid");

View File

@ -9,6 +9,7 @@ CREATE TABLE "OrganizationSponsorship" (
"SponsoringOrganizationUserId" uuid NOT NULL,
"SponsoredOrganizationId" uuid NULL,
"OfferedToEmail" character varying(256) NULL,
"PlanSponsorshipType" smallint NULL,
"CloudSponsor" boolean NOT NULL,
"LastSyncDate" timestamp without time zone NULL,
"TimesRenewedWithoutValidation" smallint NOT NULL,
@ -26,6 +27,6 @@ CREATE INDEX "IX_OrganizationSponsorship_SponsoredOrganizationId" ON "Organizati
CREATE INDEX "IX_OrganizationSponsorship_SponsoringOrganizationId" ON "OrganizationSponsorship" ("SponsoringOrganizationId");
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20211102205745_OrganizationSponsorship', '5.0.9');
VALUES ('20211104164532_OrganizationSponsorship', '5.0.9');
COMMIT;