diff --git a/src/Core/Models/EntityFramework/OrganizationSponsorship.cs b/src/Core/Models/EntityFramework/OrganizationSponsorship.cs
new file mode 100644
index 000000000..53dcd3e9e
--- /dev/null
+++ b/src/Core/Models/EntityFramework/OrganizationSponsorship.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using AutoMapper;
+
+namespace Bit.Core.Models.EntityFramework
+{
+ public class OrganizationSponsorship : Table.OrganizationSponsorship
+ {
+ public virtual Installation Installation { get; set; }
+ public virtual Organization SponsoringOrganization { get; set; }
+ public virtual Organization SponsoredOrganization { get; set; }
+ }
+
+ public class OrganizationSponsorshipMapperProfile : Profile
+ {
+ public OrganizationSponsorshipMapperProfile()
+ {
+ CreateMap
().ReverseMap();
+ }
+ }
+}
diff --git a/src/Core/Models/Table/OrganizationSponsorship.cs b/src/Core/Models/Table/OrganizationSponsorship.cs
index 33b5b8adf..7966d8a09 100644
--- a/src/Core/Models/Table/OrganizationSponsorship.cs
+++ b/src/Core/Models/Table/OrganizationSponsorship.cs
@@ -7,15 +7,14 @@ namespace Bit.Core.Models.Table
public class OrganizationSponsorship : ITableObject
{
public Guid Id { get; set; }
- public Guid InstallationId { get; set; }
+ public Guid? InstallationId { get; set; }
[Required]
public Guid SponsoringOrganizationId { get; set; }
[Required]
public Guid SponsoringOrganizationUserId { get; set; }
- public Guid SponsoringUserId { get; set; }
+ public Guid? SponsoredOrganizationId { get; set; }
[MaxLength(256)]
public string OfferedToEmail { get; set; }
- public Guid? SponsoredOrganizationId { get; set; }
[Required]
public bool CloudSponsor { get; set; }
public DateTime? LastSyncDate { get; set; }
diff --git a/src/Core/Repositories/EntityFramework/DatabaseContext.cs b/src/Core/Repositories/EntityFramework/DatabaseContext.cs
index fcc8275f9..d352e6980 100644
--- a/src/Core/Repositories/EntityFramework/DatabaseContext.cs
+++ b/src/Core/Repositories/EntityFramework/DatabaseContext.cs
@@ -26,6 +26,7 @@ namespace Bit.Core.Repositories.EntityFramework
public DbSet GroupUsers { get; set; }
public DbSet Installations { get; set; }
public DbSet Organizations { get; set; }
+ public DbSet organizationSponsorships { get; set; }
public DbSet OrganizationUsers { get; set; }
public DbSet Policies { get; set; }
public DbSet Providers { get; set; }
@@ -55,6 +56,7 @@ namespace Bit.Core.Repositories.EntityFramework
var eGroupUser = builder.Entity();
var eInstallation = builder.Entity();
var eOrganization = builder.Entity();
+ var eOrganizationSponsorship = builder.Entity();
var eOrganizationUser = builder.Entity();
var ePolicy = builder.Entity();
var eProvider = builder.Entity();
@@ -76,6 +78,7 @@ namespace Bit.Core.Repositories.EntityFramework
eGroup.Property(c => c.Id).ValueGeneratedNever();
eInstallation.Property(c => c.Id).ValueGeneratedNever();
eOrganization.Property(c => c.Id).ValueGeneratedNever();
+ eOrganizationSponsorship.Property(c => c.Id).ValueGeneratedNever();
eOrganizationUser.Property(c => c.Id).ValueGeneratedNever();
ePolicy.Property(c => c.Id).ValueGeneratedNever();
eProvider.Property(c => c.Id).ValueGeneratedNever();
@@ -115,6 +118,7 @@ namespace Bit.Core.Repositories.EntityFramework
eGroupUser.ToTable(nameof(GroupUser));
eInstallation.ToTable(nameof(Installation));
eOrganization.ToTable(nameof(Organization));
+ eOrganizationSponsorship.ToTable(nameof(OrganizationSponsorship));
eOrganizationUser.ToTable(nameof(OrganizationUser));
ePolicy.ToTable(nameof(Policy));
eProvider.ToTable(nameof(Provider));
diff --git a/src/Core/Repositories/EntityFramework/OrganizationSponsorshipRepository.cs b/src/Core/Repositories/EntityFramework/OrganizationSponsorshipRepository.cs
new file mode 100644
index 000000000..611ede3cd
--- /dev/null
+++ b/src/Core/Repositories/EntityFramework/OrganizationSponsorshipRepository.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using AutoMapper;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
+using EFModel = Bit.Core.Models.EntityFramework;
+using TableModel = Bit.Core.Models.Table;
+
+namespace Bit.Core.Repositories.EntityFramework
+{
+ public class OrganizationSponsorshipRepository : Repository, IOrganizationSponsorshipRepository
+ {
+ public OrganizationSponsorshipRepository(IServiceScopeFactory serviceScopeFactory, IMapper mapper) :
+ base(serviceScopeFactory, mapper, (DatabaseContext context) => context.organizationSponsorships)
+ {
+ }
+
+ public async Task GetByOfferedToEmailAsync(string email)
+ {
+ using (var scope = ServiceScopeFactory.CreateScope())
+ {
+ var dbContext = GetDatabaseContext(scope);
+ var orgSponsorship = await GetDbSet(dbContext).Where(e => e.OfferedToEmail == email)
+ .FirstOrDefaultAsync();
+ return orgSponsorship;
+ }
+ }
+ public async Task GetBySponsoredOrganizationIdAsync(Guid sponsoredOrganizationId)
+ {
+ using (var scope = ServiceScopeFactory.CreateScope())
+ {
+ var dbContext = GetDatabaseContext(scope);
+ var orgSponsorship = await GetDbSet(dbContext).Where(e => e.SponsoredOrganizationId == sponsoredOrganizationId)
+ .FirstOrDefaultAsync();
+ return orgSponsorship;
+ }
+ }
+ public async Task GetBySponsoringOrganizationUserIdAsync(Guid sponsoringOrganizationUserId)
+ {
+ using (var scope = ServiceScopeFactory.CreateScope())
+ {
+ var dbContext = GetDatabaseContext(scope);
+ var orgSponsorship = await GetDbSet(dbContext).Where(e => e.SponsoringOrganizationUserId == sponsoringOrganizationUserId)
+ .FirstOrDefaultAsync();
+ return orgSponsorship;
+ }
+ }
+ }
+}
diff --git a/src/Core/Utilities/ServiceCollectionExtensions.cs b/src/Core/Utilities/ServiceCollectionExtensions.cs
index 04c6a2eeb..24a5093f8 100644
--- a/src/Core/Utilities/ServiceCollectionExtensions.cs
+++ b/src/Core/Utilities/ServiceCollectionExtensions.cs
@@ -101,6 +101,7 @@ namespace Bit.Core.Utilities
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
+ services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
@@ -127,6 +128,7 @@ namespace Bit.Core.Utilities
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
+ services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
diff --git a/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_Create.sql b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_Create.sql
new file mode 100644
index 000000000..93257c3bc
--- /dev/null
+++ b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_Create.sql
@@ -0,0 +1,43 @@
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_Create]
+ @Id UNIQUEIDENTIFIER OUTPUT,
+ @InstallationId UNIQUEIDENTIFIER,
+ @SponsoringOrganizationId UNIQUEIDENTIFIER,
+ @SponsoringOrganizationUserID UNIQUEIDENTIFIER,
+ @SponsoredOrganizationId UNIQUEIDENTIFIER,
+ @OfferedToEmail NVARCHAR(256),
+ @CloudSponsor BIT,
+ @LastSyncDate DATETIME2 (7),
+ @TimesRenewedWithoutValidation TINYINT,
+ @SponsorshipLapsedDate DATETIME2 (7)
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ INSERT INTO [dbo].[OrganizationSponsorship]
+ (
+ [Id],
+ [InstallationId],
+ [SponsoringOrganizationId],
+ [SponsoringOrganizationUserID],
+ [SponsoredOrganizationId],
+ [OfferedToEmail],
+ [CloudSponsor],
+ [LastSyncDate],
+ [TimesRenewedWithoutValidation],
+ [SponsorshipLapsedDate]
+ )
+ VALUES
+ (
+ @Id,
+ @InstallationId,
+ @SponsoringOrganizationId,
+ @SponsoringOrganizationUserID,
+ @SponsoredOrganizationId,
+ @OfferedToEmail,
+ @CloudSponsor,
+ @LastSyncDate,
+ @TimesRenewedWithoutValidation,
+ @SponsorshipLapsedDate
+ )
+END
+GO
diff --git a/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_DeleteById.sql b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_DeleteById.sql
new file mode 100644
index 000000000..914707154
--- /dev/null
+++ b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_DeleteById.sql
@@ -0,0 +1,17 @@
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_DeleteById]
+ @Id UNIQUEIDENTIFIER
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ BEGIN TRANSACTION OrgSponsorship_DeleteById
+
+ DELETE
+ FROM
+ [dbo].[OrganizationSponsorship]
+ WHERE
+ [Id] = @Id
+
+ COMMIT TRANSACTION OrgSponsorship_DeleteById
+END
+GO
diff --git a/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_ReadById.sql b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_ReadById.sql
new file mode 100644
index 000000000..630200a32
--- /dev/null
+++ b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_ReadById.sql
@@ -0,0 +1,14 @@
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_ReadById]
+ @Id UNIQUEIDENTIFIER
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ SELECT
+ *
+ FROM
+ [dbo].[OrganizationSponsorshipView]
+ WHERE
+ [Id] = @Id
+END
+GO
diff --git a/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_ReadByOfferedToEmail.sql b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_ReadByOfferedToEmail.sql
new file mode 100644
index 000000000..22fac3f98
--- /dev/null
+++ b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_ReadByOfferedToEmail.sql
@@ -0,0 +1,14 @@
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_ReadByOfferedToEmail]
+ @OfferedToEmail NVARCHAR (256) -- Should not be null
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ SELECT
+ *
+ FROM
+ [dbo].[OrganizationSponsorshipView]
+ WHERE
+ [OfferedToEmail] = @OfferedToEmail
+END
+GO
diff --git a/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_ReadBySponsoredOrganizationId.sql b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_ReadBySponsoredOrganizationId.sql
new file mode 100644
index 000000000..203249cf8
--- /dev/null
+++ b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_ReadBySponsoredOrganizationId.sql
@@ -0,0 +1,14 @@
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_ReadBySponsoredOrganizationId]
+ @SponsoredOrganizationId UNIQUEIDENTIFIER
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ SELECT
+ *
+ FROM
+ [dbo].[OrganizationSponsorshipView]
+ WHERE
+ [SponsoredOrganizationId] = @SponsoredOrganizationId
+END
+GO
diff --git a/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_ReadBySponsoringOrganiationUserId.sql b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_ReadBySponsoringOrganiationUserId.sql
new file mode 100644
index 000000000..817a95cbc
--- /dev/null
+++ b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_ReadBySponsoringOrganiationUserId.sql
@@ -0,0 +1,14 @@
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_ReadBySponsoringOrganizationUserId]
+ @SponsoringOrganizationUserId UNIQUEIDENTIFIER
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ SELECT
+ *
+ FROM
+ [dbo].[OrganizationSponsorshipView]
+ WHERE
+ [SponsoringOrganizationUserId] = @SponsoringOrganizationUserId
+END
+GO
diff --git a/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_Update.sql b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_Update.sql
new file mode 100644
index 000000000..364385f54
--- /dev/null
+++ b/src/Sql/dbo/Stored Procedures/OrganizationSponsorship_Update.sql
@@ -0,0 +1,31 @@
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_Update]
+ @Id UNIQUEIDENTIFIER,
+ @InstallationId UNIQUEIDENTIFIER,
+ @SponsoringOrganizationId UNIQUEIDENTIFIER,
+ @SponsoringOrganizationUserID UNIQUEIDENTIFIER,
+ @SponsoredOrganizationId UNIQUEIDENTIFIER,
+ @OfferedToEmail NVARCHAR(256),
+ @CloudSponsor BIT,
+ @LastSyncDate DATETIME2 (7),
+ @TimesRenewedWithoutValidation TINYINT,
+ @SponsorshipLapsedDate DATETIME2 (7)
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ UPDATE
+ [dbo].[OrganizationSponsorship]
+ SET
+ [InstallationId] = @InstallationId,
+ [SponsoringOrganizationId] = @SponsoringOrganizationId,
+ [SponsoringOrganizationUserID] = @SponsoringOrganizationUserID,
+ [SponsoredOrganizationId] = @SponsoredOrganizationId,
+ [OfferedToEmail] = @OfferedToEmail,
+ [CloudSponsor] = @CloudSponsor,
+ [LastSyncDate] = @LastSyncDate,
+ [TimesRenewedWithoutValidation] = @TimesRenewedWithoutValidation,
+ [SponsorshipLapsedDate] = @SponsorshipLapsedDate
+ WHERE
+ [Id] = @Id
+END
+GO
diff --git a/src/Sql/dbo/Tables/OrganizationSponsorship.sql b/src/Sql/dbo/Tables/OrganizationSponsorship.sql
new file mode 100644
index 000000000..2dc3ead15
--- /dev/null
+++ b/src/Sql/dbo/Tables/OrganizationSponsorship.sql
@@ -0,0 +1,41 @@
+CREATE TABLE [dbo].[OrganizationSponsorship] (
+ [Id] UNIQUEIDENTIFIER NOT NULL,
+ [InstallationId] UNIQUEIDENTIFIER NULL,
+ [SponsoringOrganizationId] UNIQUEIDENTIFIER NOT NULL,
+ [SponsorginOrganizationUserID] UNIQUEIDENTIFIER NOT NULL,
+ [SponsoredOrganizationId] UNIQUEIDENTIFIER NULL,
+ [OfferedToEmail] NVARCHAR (256) NULL,
+ [CloudSponsor] BIT NULL,
+ [LastSyncDate] DATETIME2 (7) NULL,
+ [TimesRenewedWithoutValidation] TINYINT DEFAULT 0,
+ [SponsorshipLapsedDate] DATETIME2 (7) NULL,
+ CONSTRAINT [PK_OrganizationSponsorship] PRIMARY KEY CLUSTERED ([Id] ASC),
+ CONSTRAINT [FK_OrganizationSponsorship_InstallationId] FOREIGN KEY ([InstallationId]) REFERENCES [dbo].[Installation] ([Id]),
+ CONSTRAINT [FK_OrganizationSponsorship_SponsoringOrg] FOREIGN KEY ([SponsoringOrganizationId]) REFERENCES [dbo].[Organization] ([Id]),
+ CONSTRAINT [FK_OrganizationSponsorship_SponsoredOrg] FOREIGN KEY ([SponsoredOrganizationId]) REFERENCES [dbo].[Organization] ([Id]),
+);
+
+
+GO
+CREATE NONCLUSTERED INDEX [IX_OrganizationSponsorship_InstallationId]
+ ON [dbo].[Organization]([Id] ASC, [InstallationId] ASC)
+ WHERE [InstallationId] IS NOT NULL;
+
+GO
+CREATE NONCLUSTERED INDEX [IX_OrganizationSponsorship_SponsoringOrganizationId]
+ ON [dbo].[Organization]([Id] ASC, [SponsoringOrganizationId] ASC)
+
+GO
+CREATE NONCLUSTERED INDEX [IX_OrganizationSponsorship_SponsoringOrganizationUserId]
+ ON [dbo].[Organization]([Id] ASC, [SponsorginOrganizationUserID] ASC)
+
+GO
+CREATE NONCLUSTERED INDEX [IX_OrganizationSponsorship_OfferedToEmail]
+ ON [dbo].[Organization]([Id] ASC, [OfferedToEmail] ASC)
+ WHERE [OfferedToEmail] IS NOT NULL;
+
+GO
+CREATE NONCLUSTERED INDEX [IX_OrganizationSponsorship_SponsoredOrganizationID]
+ ON [dbo].[Organization]([Id] ASC, [SponsoredOrganizationId] ASC)
+ WHERE [SponsoredOrganizationId] IS NOT NULL;
+
diff --git a/test/Core.Test/AutoFixture/EntityFrameworkRepositoryFixtures.cs b/test/Core.Test/AutoFixture/EntityFrameworkRepositoryFixtures.cs
index 4096f6919..0d82ef9b4 100644
--- a/test/Core.Test/AutoFixture/EntityFrameworkRepositoryFixtures.cs
+++ b/test/Core.Test/AutoFixture/EntityFrameworkRepositoryFixtures.cs
@@ -76,6 +76,7 @@ namespace Bit.Core.Test.AutoFixture.EntityFrameworkRepositoryFixtures
cfg.AddProfile();
cfg.AddProfile();
cfg.AddProfile();
+ cfg.AddProfile();
cfg.AddProfile();
cfg.AddProfile();
cfg.AddProfile();
diff --git a/test/Core.Test/AutoFixture/OrganizationSponsorshipFixtures.cs b/test/Core.Test/AutoFixture/OrganizationSponsorshipFixtures.cs
new file mode 100644
index 000000000..4a1704ed2
--- /dev/null
+++ b/test/Core.Test/AutoFixture/OrganizationSponsorshipFixtures.cs
@@ -0,0 +1,59 @@
+using AutoFixture;
+using TableModel = Bit.Core.Models.Table;
+using AutoFixture.Kernel;
+using System;
+using Bit.Core.Repositories.EntityFramework;
+using Bit.Core.Test.AutoFixture.EntityFrameworkRepositoryFixtures;
+using Bit.Test.Common.AutoFixture;
+using Bit.Test.Common.AutoFixture.Attributes;
+using Bit.Core.Test.AutoFixture.OrganizationUserFixtures;
+
+namespace Bit.Core.Test.AutoFixture.OrganizationSponsorshipFixtures
+{
+ internal class OrganizationSponsorshipBuilder : ISpecimenBuilder
+ {
+ public object Create(object request, ISpecimenContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ var type = request as Type;
+ if (type == null || type != typeof(TableModel.OrganizationSponsorship))
+ {
+ return new NoSpecimen();
+ }
+
+ var fixture = new Fixture();
+ var obj = fixture.WithAutoNSubstitutions().Create();
+ return obj;
+ }
+ }
+
+ internal class EfOrganizationSponsorship : ICustomization
+ {
+ public void Customize(IFixture fixture)
+ {
+ fixture.Customizations.Add(new IgnoreVirtualMembersCustomization());
+ fixture.Customizations.Add(new GlobalSettingsBuilder());
+ fixture.Customizations.Add(new OrganizationSponsorshipBuilder());
+ fixture.Customizations.Add(new OrganizationUserBuilder());
+ fixture.Customizations.Add(new EfRepositoryListBuilder());
+ fixture.Customizations.Add(new EfRepositoryListBuilder());
+ }
+ }
+
+ internal class EfOrganizationSponsorshipAutoDataAttribute : CustomAutoDataAttribute
+ {
+ public EfOrganizationSponsorshipAutoDataAttribute() : base(new SutProviderCustomization(), new EfOrganizationSponsorship())
+ { }
+ }
+
+ internal class InlineEfOrganizationSponsorshipAutoDataAttribute : InlineCustomAutoDataAttribute
+ {
+ public InlineEfOrganizationSponsorshipAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
+ typeof(EfOrganizationSponsorship) }, values)
+ { }
+ }
+}
diff --git a/test/Core.Test/Repositories/EntityFramework/EqualityComparers/OrganizationSponsorshipCompare.cs b/test/Core.Test/Repositories/EntityFramework/EqualityComparers/OrganizationSponsorshipCompare.cs
new file mode 100644
index 000000000..cd1c29262
--- /dev/null
+++ b/test/Core.Test/Repositories/EntityFramework/EqualityComparers/OrganizationSponsorshipCompare.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using Bit.Core.Models.Table;
+
+namespace Bit.Core.Test.Repositories.EntityFramework.EqualityComparers
+{
+ public class OrganizationSponsorshipCompare : IEqualityComparer
+ {
+ public bool Equals(OrganizationSponsorship x, OrganizationSponsorship y)
+ {
+ return x.InstallationId.Equals(y.InstallationId) &&
+ x.SponsoringOrganizationId.Equals(y.SponsoringOrganizationId) &&
+ x.SponsoringOrganizationUserId.Equals(y.SponsoringOrganizationUserId) &&
+ x.SponsoredOrganizationId.Equals(y.SponsoredOrganizationId) &&
+ x.OfferedToEmail.Equals(y.OfferedToEmail) &&
+ x.CloudSponsor.Equals(y.CloudSponsor) &&
+ x.TimesRenewedWithoutValidation.Equals(y.TimesRenewedWithoutValidation) &&
+ x.SponsorshipLapsedDate.ToString().Equals(y.SponsorshipLapsedDate.ToString());
+ }
+
+ public int GetHashCode([DisallowNull] OrganizationSponsorship obj)
+ {
+ return base.GetHashCode();
+ }
+ }
+}
diff --git a/test/Core.Test/Repositories/EntityFramework/OrganizationSponsorshipRepositoryTests.cs b/test/Core.Test/Repositories/EntityFramework/OrganizationSponsorshipRepositoryTests.cs
new file mode 100644
index 000000000..67b7ab409
--- /dev/null
+++ b/test/Core.Test/Repositories/EntityFramework/OrganizationSponsorshipRepositoryTests.cs
@@ -0,0 +1,138 @@
+using EfRepo = Bit.Core.Repositories.EntityFramework;
+using SqlRepo = Bit.Core.Repositories.SqlServer;
+using System.Collections.Generic;
+using System.Linq;
+using TableModel = Bit.Core.Models.Table;
+using Xunit;
+using Bit.Core.Test.Repositories.EntityFramework.EqualityComparers;
+using Bit.Core.Test.AutoFixture.Attributes;
+using Bit.Core.Test.AutoFixture.OrganizationSponsorshipFixtures;
+
+namespace Bit.Core.Test.Repositories.EntityFramework
+{
+ public class OrganizationSponsorshipRepositoryTests
+ {
+ [CiSkippedTheory, EfOrganizationSponsorshipAutoData]
+ public async void CreateAsync_Works_DataMatches(
+ TableModel.OrganizationSponsorship organizationSponsorship, TableModel.Organization sponsoringOrg,
+ List efOrgRepos,
+ SqlRepo.OrganizationRepository sqlOrganizationRepo,
+ SqlRepo.OrganizationSponsorshipRepository sqlOrganizationSponsorshipRepo,
+ OrganizationSponsorshipCompare equalityComparer,
+ List suts)
+ {
+ organizationSponsorship.InstallationId = null;
+ organizationSponsorship.SponsoredOrganizationId = null;
+
+ var savedOrganizationSponsorships = new List();
+ foreach (var (sut, orgRepo) in suts.Zip(efOrgRepos))
+ {
+ var efSponsoringOrg = await orgRepo.CreateAsync(sponsoringOrg);
+ sut.ClearChangeTracking();
+ organizationSponsorship.SponsoringOrganizationId = efSponsoringOrg.Id;
+
+ await sut.CreateAsync(organizationSponsorship);
+ sut.ClearChangeTracking();
+
+ var savedOrganizationSponsorship = await sut.GetByIdAsync(organizationSponsorship.Id);
+ savedOrganizationSponsorships.Add(savedOrganizationSponsorship);
+ }
+
+ var sqlSponsoringOrg = await sqlOrganizationRepo.CreateAsync(sponsoringOrg);
+ organizationSponsorship.SponsoringOrganizationId = sqlSponsoringOrg.Id;
+
+ var sqlOrganizationSponsorship = await sqlOrganizationSponsorshipRepo.CreateAsync(organizationSponsorship);
+ savedOrganizationSponsorships.Add(await sqlOrganizationSponsorshipRepo.GetByIdAsync(sqlOrganizationSponsorship.Id));
+
+ var distinctItems = savedOrganizationSponsorships.Distinct(equalityComparer);
+ Assert.True(!distinctItems.Skip(1).Any());
+ }
+
+ [CiSkippedTheory, EfOrganizationSponsorshipAutoData]
+ public async void ReplaceAsync_Works_DataMatches(TableModel.OrganizationSponsorship postOrganizationSponsorship,
+ TableModel.OrganizationSponsorship replaceOrganizationSponsorship, TableModel.Organization sponsoringOrg,
+ List efOrgRepos,
+ SqlRepo.OrganizationRepository sqlOrganizationRepo,
+ SqlRepo.OrganizationSponsorshipRepository sqlOrganizationSponsorshipRepo,
+ OrganizationSponsorshipCompare equalityComparer, List suts)
+ {
+ postOrganizationSponsorship.InstallationId = null;
+ postOrganizationSponsorship.SponsoredOrganizationId = null;
+ replaceOrganizationSponsorship.InstallationId = null;
+ replaceOrganizationSponsorship.SponsoredOrganizationId = null;
+
+ var savedOrganizationSponsorships = new List();
+ foreach (var (sut, orgRepo) in suts.Zip(efOrgRepos))
+ {
+ var efSponsoringOrg = await orgRepo.CreateAsync(sponsoringOrg);
+ sut.ClearChangeTracking();
+ postOrganizationSponsorship.SponsoringOrganizationId = efSponsoringOrg.Id;
+ replaceOrganizationSponsorship.SponsoringOrganizationId = efSponsoringOrg.Id;
+
+ var postEfOrganizationSponsorship = await sut.CreateAsync(postOrganizationSponsorship);
+ sut.ClearChangeTracking();
+
+ replaceOrganizationSponsorship.Id = postEfOrganizationSponsorship.Id;
+ await sut.ReplaceAsync(replaceOrganizationSponsorship);
+ sut.ClearChangeTracking();
+
+ var replacedOrganizationSponsorship = await sut.GetByIdAsync(replaceOrganizationSponsorship.Id);
+ savedOrganizationSponsorships.Add(replacedOrganizationSponsorship);
+ }
+
+ var sqlSponsoringOrg = await sqlOrganizationRepo.CreateAsync(sponsoringOrg);
+ postOrganizationSponsorship.SponsoringOrganizationId = sqlSponsoringOrg.Id;
+
+ var postSqlOrganization = await sqlOrganizationSponsorshipRepo.CreateAsync(postOrganizationSponsorship);
+ replaceOrganizationSponsorship.Id = postSqlOrganization.Id;
+ await sqlOrganizationSponsorshipRepo.ReplaceAsync(replaceOrganizationSponsorship);
+ savedOrganizationSponsorships.Add(await sqlOrganizationSponsorshipRepo.GetByIdAsync(replaceOrganizationSponsorship.Id));
+
+ var distinctItems = savedOrganizationSponsorships.Distinct(equalityComparer);
+ Assert.True(!distinctItems.Skip(1).Any());
+ }
+
+ [CiSkippedTheory, EfOrganizationSponsorshipAutoData]
+ public async void DeleteAsync_Works_DataMatches(TableModel.OrganizationSponsorship organizationSponsorship,
+ TableModel.Organization sponsoringOrg,
+ List efOrgRepos,
+ SqlRepo.OrganizationRepository sqlOrganizationRepo,
+ SqlRepo.OrganizationSponsorshipRepository sqlOrganizationSponsorshipRepo,
+ List suts)
+ {
+ organizationSponsorship.InstallationId = null;
+ organizationSponsorship.SponsoredOrganizationId = null;
+
+ foreach (var (sut, orgRepo) in suts.Zip(efOrgRepos))
+ {
+ var efSponsoringOrg = await orgRepo.CreateAsync(sponsoringOrg);
+ sut.ClearChangeTracking();
+ organizationSponsorship.SponsoringOrganizationId = efSponsoringOrg.Id;
+
+ var postEfOrganizationSponsorship = await sut.CreateAsync(organizationSponsorship);
+ sut.ClearChangeTracking();
+
+ var savedEfOrganizationSponsorship = await sut.GetByIdAsync(postEfOrganizationSponsorship.Id);
+ sut.ClearChangeTracking();
+ Assert.True(savedEfOrganizationSponsorship != null);
+
+ await sut.DeleteAsync(savedEfOrganizationSponsorship);
+ sut.ClearChangeTracking();
+
+ savedEfOrganizationSponsorship = await sut.GetByIdAsync(savedEfOrganizationSponsorship.Id);
+ Assert.True(savedEfOrganizationSponsorship == null);
+ }
+
+ var sqlSponsoringOrg = await sqlOrganizationRepo.CreateAsync(sponsoringOrg);
+ organizationSponsorship.SponsoringOrganizationId = sqlSponsoringOrg.Id;
+
+ var postSqlOrganizationSponsorship = await sqlOrganizationSponsorshipRepo.CreateAsync(organizationSponsorship);
+ var savedSqlOrganizationSponsorship = await sqlOrganizationSponsorshipRepo.GetByIdAsync(postSqlOrganizationSponsorship.Id);
+ Assert.True(savedSqlOrganizationSponsorship != null);
+
+ await sqlOrganizationSponsorshipRepo.DeleteAsync(postSqlOrganizationSponsorship);
+ savedSqlOrganizationSponsorship = await sqlOrganizationSponsorshipRepo.GetByIdAsync(postSqlOrganizationSponsorship.Id);
+ Assert.True(savedSqlOrganizationSponsorship == null);
+ }
+ }
+}
diff --git a/util/Migrator/DbScripts/2021-11-02_00_OrganizationSponsorship.sql b/util/Migrator/DbScripts/2021-11-02_00_OrganizationSponsorship.sql
new file mode 100644
index 000000000..12113573e
--- /dev/null
+++ b/util/Migrator/DbScripts/2021-11-02_00_OrganizationSponsorship.sql
@@ -0,0 +1,286 @@
+-- Create Organization Sponsorships table
+IF OBJECT_ID('[dbo].[OrganizationSponsorship]') IS NULL
+BEGIN
+CREATE TABLE [dbo].[OrganizationSponsorship] (
+ [Id] UNIQUEIDENTIFIER NOT NULL,
+ [InstallationId] UNIQUEIDENTIFIER NULL,
+ [SponsoringOrganizationId] UNIQUEIDENTIFIER NOT NULL,
+ [SponsoringOrganizationUserID] UNIQUEIDENTIFIER NOT NULL,
+ [SponsoredOrganizationId] UNIQUEIDENTIFIER NULL,
+ [OfferedToEmail] NVARCHAR (256) NULL,
+ [CloudSponsor] BIT NULL,
+ [LastSyncDate] DATETIME2 (7) NULL,
+ [TimesRenewedWithoutValidation] TINYINT DEFAULT 0,
+ [SponsorshipLapsedDate] DATETIME2 (7) NULL,
+ CONSTRAINT [PK_OrganizationSponsorship] PRIMARY KEY CLUSTERED ([Id] ASC),
+ CONSTRAINT [FK_OrganizationSponsorship_InstallationId] FOREIGN KEY ([InstallationId]) REFERENCES [dbo].[Installation] ([Id]),
+ CONSTRAINT [FK_OrganizationSponsorship_SponsoringOrg] FOREIGN KEY ([SponsoringOrganizationId]) REFERENCES [dbo].[Organization] ([Id]),
+ CONSTRAINT [FK_OrganizationSponsorship_SponsoredOrg] FOREIGN KEY ([SponsoredOrganizationId]) REFERENCES [dbo].[Organization] ([Id]),
+);
+END
+GO
+
+
+-- Create indexes
+IF NOT EXISTS(SELECT name FROM sys.indexes WHERE name = 'IX_OrganizationSponsorship_InstallationId')
+BEGIN
+CREATE NONCLUSTERED INDEX [IX_OrganizationSponsorship_InstallationId]
+ ON [dbo].[OrganizationSponsorship]([InstallationId] ASC)
+ WHERE [InstallationId] IS NOT NULL;
+END
+GO
+
+IF NOT EXISTS(SELECT name FROM sys.indexes WHERE name = 'IX_OrganizationSponsorship_SponsoringOrganizationId')
+BEGIN
+CREATE NONCLUSTERED INDEX [IX_OrganizationSponsorship_SponsoringOrganizationId]
+ ON [dbo].[OrganizationSponsorship]([SponsoringOrganizationId] ASC)
+END
+GO
+
+IF NOT EXISTS(SELECT name FROM sys.indexes WHERE name = 'IX_OrganizationSponsorship_SponsoringOrganizationUserId')
+BEGIN
+CREATE NONCLUSTERED INDEX [IX_OrganizationSponsorship_SponsoringOrganizationUserId]
+ ON [dbo].[OrganizationSponsorship]([SponsoringOrganizationUserID] ASC)
+END
+GO
+
+IF NOT EXISTS(SELECT name FROM sys.indexes WHERE name = 'IX_OrganizationSponsorship_OfferedToEmail')
+BEGIN
+CREATE NONCLUSTERED INDEX [IX_OrganizationSponsorship_OfferedToEmail]
+ ON [dbo].[OrganizationSponsorship]([OfferedToEmail] ASC)
+ WHERE [OfferedToEmail] IS NOT NULL;
+END
+GO
+
+IF NOT EXISTS(SELECT name FROM sys.indexes WHERE name = 'IX_OrganizationSponsorship_SponsoredOrganizationID')
+BEGIN
+CREATE NONCLUSTERED INDEX [IX_OrganizationSponsorship_SponsoredOrganizationID]
+ ON [dbo].[OrganizationSponsorship]([SponsoredOrganizationId] ASC)
+ WHERE [SponsoredOrganizationId] IS NOT NULL;
+END
+GO
+
+
+-- Create View
+IF EXISTS(SELECT * FROM sys.views WHERE [Name] = 'OrganizationSponsorshipView')
+BEGIN
+ DROP VIEW [dbo].[OrganizationSponsorshipView];
+END
+GO
+
+CREATE VIEW [dbo].[OrganizationSponsorshipView]
+AS
+SELECT
+ *
+FROM
+ [dbo].[OrganizationSponsorship]
+GO
+
+
+-- OrganizationSponsorship_ReadById
+IF OBJECT_ID('[dbo].[OrganizationSponsorship_ReadById]') IS NOT NULL
+BEGIN
+ DROP PROCEDURE [dbo].[OrganizationSponsorship_ReadById]
+END
+GO
+
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_ReadById]
+ @Id UNIQUEIDENTIFIER
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ SELECT
+ *
+ FROM
+ [dbo].[OrganizationSponsorshipView]
+ WHERE
+ [Id] = @Id
+END
+GO
+
+
+-- OrganizationSponsorship_Create
+IF OBJECT_ID('[dbo].[OrganizationSponsorship_Create]') IS NOT NULL
+BEGIN
+ DROP PROCEDURE [dbo].[OrganizationSponsorship_Create]
+END
+GO
+
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_Create]
+ @Id UNIQUEIDENTIFIER OUTPUT,
+ @InstallationId UNIQUEIDENTIFIER,
+ @SponsoringOrganizationId UNIQUEIDENTIFIER,
+ @SponsoringOrganizationUserID UNIQUEIDENTIFIER,
+ @SponsoredOrganizationId UNIQUEIDENTIFIER,
+ @OfferedToEmail NVARCHAR(256),
+ @CloudSponsor BIT,
+ @LastSyncDate DATETIME2 (7),
+ @TimesRenewedWithoutValidation TINYINT,
+ @SponsorshipLapsedDate DATETIME2 (7)
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ INSERT INTO [dbo].[OrganizationSponsorship]
+ (
+ [Id],
+ [InstallationId],
+ [SponsoringOrganizationId],
+ [SponsoringOrganizationUserID],
+ [SponsoredOrganizationId],
+ [OfferedToEmail],
+ [CloudSponsor],
+ [LastSyncDate],
+ [TimesRenewedWithoutValidation],
+ [SponsorshipLapsedDate]
+ )
+ VALUES
+ (
+ @Id,
+ @InstallationId,
+ @SponsoringOrganizationId,
+ @SponsoringOrganizationUserID,
+ @SponsoredOrganizationId,
+ @OfferedToEmail,
+ @CloudSponsor,
+ @LastSyncDate,
+ @TimesRenewedWithoutValidation,
+ @SponsorshipLapsedDate
+ )
+END
+GO
+
+-- OrganizationSponsorship_Update
+IF OBJECT_ID('[dbo].[OrganizationSponsorship_Update]') IS NOT NULL
+BEGIN
+ DROP PROCEDURE [dbo].[OrganizationSponsorship_Update]
+END
+GO
+
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_Update]
+ @Id UNIQUEIDENTIFIER,
+ @InstallationId UNIQUEIDENTIFIER,
+ @SponsoringOrganizationId UNIQUEIDENTIFIER,
+ @SponsoringOrganizationUserID UNIQUEIDENTIFIER,
+ @SponsoredOrganizationId UNIQUEIDENTIFIER,
+ @OfferedToEmail NVARCHAR(256),
+ @CloudSponsor BIT,
+ @LastSyncDate DATETIME2 (7),
+ @TimesRenewedWithoutValidation TINYINT,
+ @SponsorshipLapsedDate DATETIME2 (7)
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ UPDATE
+ [dbo].[OrganizationSponsorship]
+ SET
+ [InstallationId] = @InstallationId,
+ [SponsoringOrganizationId] = @SponsoringOrganizationId,
+ [SponsoringOrganizationUserID] = @SponsoringOrganizationUserID,
+ [SponsoredOrganizationId] = @SponsoredOrganizationId,
+ [OfferedToEmail] = @OfferedToEmail,
+ [CloudSponsor] = @CloudSponsor,
+ [LastSyncDate] = @LastSyncDate,
+ [TimesRenewedWithoutValidation] = @TimesRenewedWithoutValidation,
+ [SponsorshipLapsedDate] = @SponsorshipLapsedDate
+ WHERE
+ [Id] = @Id
+END
+GO
+
+
+-- OrganizationSponsorship_DeleteById
+IF OBJECT_ID('[dbo].[OrganizationSponsorship_DeleteById]') IS NOT NULL
+BEGIN
+ DROP PROCEDURE [dbo].[OrganizationSponsorship_DeleteById]
+END
+GO
+
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_DeleteById]
+ @Id UNIQUEIDENTIFIER
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ BEGIN TRANSACTION OrgSponsorship_DeleteById
+
+ DELETE
+ FROM
+ [dbo].[OrganizationSponsorship]
+ WHERE
+ [Id] = @Id
+
+ COMMIT TRANSACTION OrgSponsorship_DeleteById
+END
+GO
+
+
+-- OrganizationSponsorship_ReadBySponsoringOrganizationUserId
+IF OBJECT_ID('[dbo].[OrganizationSponsorship_ReadBySponsoringOrganizationUserId]') IS NOT NULL
+BEGIN
+ DROP PROCEDURE [dbo].[OrganizationSponsorship_ReadBySponsoringOrganizationUserId]
+END
+GO
+
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_ReadBySponsoringOrganizationUserId]
+ @SponsoringOrganizationUserId UNIQUEIDENTIFIER
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ SELECT
+ *
+ FROM
+ [dbo].[OrganizationSponsorshipView]
+ WHERE
+ [SponsoringOrganizationUserId] = @SponsoringOrganizationUserId
+END
+GO
+
+
+
+-- OrganizationSponsorship_ReadBySponsoredOrganizationId
+IF OBJECT_ID('[dbo].[OrganizationSponsorship_ReadBySponsoredOrganizationId]') IS NOT NULL
+BEGIN
+ DROP PROCEDURE [dbo].[OrganizationSponsorship_ReadBySponsoredOrganizationId]
+END
+GO
+
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_ReadBySponsoredOrganizationId]
+ @SponsoredOrganizationId UNIQUEIDENTIFIER
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ SELECT
+ *
+ FROM
+ [dbo].[OrganizationSponsorshipView]
+ WHERE
+ [SponsoredOrganizationId] = @SponsoredOrganizationId
+END
+GO
+
+-- OrganizationSponsorship_ReadByOfferedToEmail
+IF OBJECT_ID('[dbo].[OrganizationSponsorship_ReadByOfferedToEmail]') IS NOT NULL
+BEGIN
+ DROP PROCEDURE [dbo].[OrganizationSponsorship_ReadByOfferedToEmail]
+END
+GO
+
+CREATE PROCEDURE [dbo].[OrganizationSponsorship_ReadByOfferedToEmail]
+ @OfferedToEmail NVARCHAR (256) -- Should not be null
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ SELECT
+ *
+ FROM
+ [dbo].[OrganizationSponsorshipView]
+ WHERE
+ [OfferedToEmail] = @OfferedToEmail
+END
+GO
diff --git a/util/MySqlMigrations/Migrations/20211102213543_OrganizationSponsorship.Designer.cs b/util/MySqlMigrations/Migrations/20211102213543_OrganizationSponsorship.Designer.cs
new file mode 100644
index 000000000..9a915376e
--- /dev/null
+++ b/util/MySqlMigrations/Migrations/20211102213543_OrganizationSponsorship.Designer.cs
@@ -0,0 +1,1562 @@
+//
+using System;
+using Bit.Core.Repositories.EntityFramework;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace Bit.MySqlMigrations.Migrations
+{
+ [DbContext(typeof(DatabaseContext))]
+ [Migration("20211102213543_OrganizationSponsorship")]
+ partial class OrganizationSponsorship
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("Relational:MaxIdentifierLength", 64)
+ .HasAnnotation("ProductVersion", "5.0.9");
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Cipher", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("Attachments")
+ .HasColumnType("longtext");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Data")
+ .HasColumnType("longtext");
+
+ b.Property("DeletedDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Favorites")
+ .HasColumnType("longtext");
+
+ b.Property("Folders")
+ .HasColumnType("longtext");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("Reprompt")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Cipher");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Collection", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ExternalId")
+ .HasMaxLength(300)
+ .HasColumnType("varchar(300)");
+
+ b.Property("Name")
+ .HasColumnType("longtext");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId");
+
+ b.ToTable("Collection");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.CollectionCipher", b =>
+ {
+ b.Property("CollectionId")
+ .HasColumnType("char(36)");
+
+ b.Property("CipherId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("CollectionId", "CipherId");
+
+ b.HasIndex("CipherId");
+
+ b.ToTable("CollectionCipher");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.CollectionGroup", b =>
+ {
+ b.Property("CollectionId")
+ .HasColumnType("char(36)");
+
+ b.Property("GroupId")
+ .HasColumnType("char(36)");
+
+ b.Property("HidePasswords")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ReadOnly")
+ .HasColumnType("tinyint(1)");
+
+ b.HasKey("CollectionId", "GroupId");
+
+ b.HasIndex("GroupId");
+
+ b.ToTable("CollectionGroups");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.CollectionUser", b =>
+ {
+ b.Property("CollectionId")
+ .HasColumnType("char(36)");
+
+ b.Property("OrganizationUserId")
+ .HasColumnType("char(36)");
+
+ b.Property("HidePasswords")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ReadOnly")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("CollectionId", "OrganizationUserId");
+
+ b.HasIndex("OrganizationUserId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("CollectionUsers");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Device", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Identifier")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("Name")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("PushToken")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Device");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.EmergencyAccess", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Email")
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)");
+
+ b.Property("GranteeId")
+ .HasColumnType("char(36)");
+
+ b.Property("GrantorId")
+ .HasColumnType("char(36)");
+
+ b.Property("KeyEncrypted")
+ .HasColumnType("longtext");
+
+ b.Property("LastNotificationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("RecoveryInitiatedDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Status")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("WaitTimeDays")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("GranteeId");
+
+ b.HasIndex("GrantorId");
+
+ b.ToTable("EmergencyAccess");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Event", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("ActingUserId")
+ .HasColumnType("char(36)");
+
+ b.Property("CipherId")
+ .HasColumnType("char(36)");
+
+ b.Property("CollectionId")
+ .HasColumnType("char(36)");
+
+ b.Property("Date")
+ .HasColumnType("datetime(6)");
+
+ b.Property("DeviceType")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("GroupId")
+ .HasColumnType("char(36)");
+
+ b.Property("IpAddress")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("OrganizationUserId")
+ .HasColumnType("char(36)");
+
+ b.Property("PolicyId")
+ .HasColumnType("char(36)");
+
+ b.Property("ProviderId")
+ .HasColumnType("char(36)");
+
+ b.Property("ProviderOrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("ProviderUserId")
+ .HasColumnType("char(36)");
+
+ b.Property("Type")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Event");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Folder", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Name")
+ .HasColumnType("longtext");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Folder");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Grant", b =>
+ {
+ b.Property("Key")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("ClientId")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("ConsumedDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Data")
+ .HasColumnType("longtext");
+
+ b.Property("Description")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("ExpirationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("SessionId")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.Property("SubjectId")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("Type")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.HasKey("Key");
+
+ b.ToTable("Grant");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Group", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AccessAll")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ExternalId")
+ .HasMaxLength(300)
+ .HasColumnType("varchar(300)");
+
+ b.Property("Name")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId");
+
+ b.ToTable("Group");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.GroupUser", b =>
+ {
+ b.Property("GroupId")
+ .HasColumnType("char(36)");
+
+ b.Property("OrganizationUserId")
+ .HasColumnType("char(36)");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("GroupId", "OrganizationUserId");
+
+ b.HasIndex("OrganizationUserId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("GroupUser");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Installation", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Email")
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)");
+
+ b.Property("Enabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Key")
+ .HasMaxLength(150)
+ .HasColumnType("varchar(150)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Installation");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Organization", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("ApiKey")
+ .HasMaxLength(30)
+ .HasColumnType("varchar(30)");
+
+ b.Property("BillingEmail")
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)");
+
+ b.Property("BusinessAddress1")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("BusinessAddress2")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("BusinessAddress3")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("BusinessCountry")
+ .HasMaxLength(2)
+ .HasColumnType("varchar(2)");
+
+ b.Property("BusinessName")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("BusinessTaxNumber")
+ .HasMaxLength(30)
+ .HasColumnType("varchar(30)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Enabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ExpirationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Gateway")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("GatewayCustomerId")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("GatewaySubscriptionId")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("Identifier")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("LicenseKey")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.Property("MaxAutoscaleSeats")
+ .HasColumnType("int");
+
+ b.Property("MaxCollections")
+ .HasColumnType("smallint");
+
+ b.Property("MaxStorageGb")
+ .HasColumnType("smallint");
+
+ b.Property("Name")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("OwnersNotifiedOfAutoscaling")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Plan")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("PlanType")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("PrivateKey")
+ .HasColumnType("longtext");
+
+ b.Property("PublicKey")
+ .HasColumnType("longtext");
+
+ b.Property("ReferenceData")
+ .HasColumnType("longtext");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Seats")
+ .HasColumnType("int");
+
+ b.Property("SelfHost")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Storage")
+ .HasColumnType("bigint");
+
+ b.Property("TwoFactorProviders")
+ .HasColumnType("longtext");
+
+ b.Property("Use2fa")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseApi")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseDirectory")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseEvents")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseGroups")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UsePolicies")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseResetPassword")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseSso")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseTotp")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UsersGetPremium")
+ .HasColumnType("tinyint(1)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Organization");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.OrganizationSponsorship", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CloudSponsor")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("InstallationId")
+ .HasColumnType("char(36)");
+
+ b.Property("LastSyncDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("OfferedToEmail")
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)");
+
+ b.Property("SponsoredOrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("SponsoringOrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("SponsoringOrganizationUserId")
+ .HasColumnType("char(36)");
+
+ b.Property("SponsorshipLapsedDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("TimesRenewedWithoutValidation")
+ .HasColumnType("tinyint unsigned");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstallationId");
+
+ b.HasIndex("SponsoredOrganizationId");
+
+ b.HasIndex("SponsoringOrganizationId");
+
+ b.ToTable("OrganizationSponsorship");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.OrganizationUser", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AccessAll")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Email")
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)");
+
+ b.Property("ExternalId")
+ .HasMaxLength(300)
+ .HasColumnType("varchar(300)");
+
+ b.Property("Key")
+ .HasColumnType("longtext");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("Permissions")
+ .HasColumnType("longtext");
+
+ b.Property("ResetPasswordKey")
+ .HasColumnType("longtext");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Status")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("OrganizationUser");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Policy", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Data")
+ .HasColumnType("longtext");
+
+ b.Property("Enabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId");
+
+ b.ToTable("Policy");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Provider.Provider", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("BillingEmail")
+ .HasColumnType("longtext");
+
+ b.Property("BusinessAddress1")
+ .HasColumnType("longtext");
+
+ b.Property("BusinessAddress2")
+ .HasColumnType("longtext");
+
+ b.Property("BusinessAddress3")
+ .HasColumnType("longtext");
+
+ b.Property("BusinessCountry")
+ .HasColumnType("longtext");
+
+ b.Property("BusinessName")
+ .HasColumnType("longtext");
+
+ b.Property("BusinessTaxNumber")
+ .HasColumnType("longtext");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Enabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Name")
+ .HasColumnType("longtext");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Status")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("UseEvents")
+ .HasColumnType("tinyint(1)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Provider");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Provider.ProviderOrganization", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Key")
+ .HasColumnType("longtext");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("ProviderId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Settings")
+ .HasColumnType("longtext");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId");
+
+ b.HasIndex("ProviderId");
+
+ b.ToTable("ProviderOrganization");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Provider.ProviderUser", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Email")
+ .HasColumnType("longtext");
+
+ b.Property("Key")
+ .HasColumnType("longtext");
+
+ b.Property("Permissions")
+ .HasColumnType("longtext");
+
+ b.Property("ProviderId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Status")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ProviderId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ProviderUser");
+ });
+
+ modelBuilder.Entity("Bit.Core.Models.EntityFramework.Send", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AccessCount")
+ .HasColumnType("int");
+
+ b.Property