From 2bb7c17cce220eff780d2a41384a01b83ff1ca7c Mon Sep 17 00:00:00 2001
From: John Harrington <84741727+harr1424@users.noreply.github.com>
Date: Sun, 1 Mar 2026 18:13:23 -0700
Subject: [PATCH 1/9] initial send controls
---
src/Core/AdminConsole/Enums/PolicyType.cs | 9 +
.../Policies/SendControlsPolicyData.cs | 12 +
.../SendControlsPolicyRequirement.cs | 39 +
.../PolicyServiceCollectionExtensions.cs | 4 +
.../DisableSendSyncPolicyValidator.cs | 54 +
.../SendControlsSyncPolicyValidator.cs | 75 +
.../SendOptionsSyncPolicyValidator.cs | 58 +
src/Core/Constants.cs | 1 +
.../Services/SendValidationService.cs | 32 +
...26-02-28_00_CreateSendControlsPolicies.sql | 55 +
...000_CreateSendControlsPolicies.Designer.cs | 3568 ++++++++++++++++
...260228000000_CreateSendControlsPolicies.cs | 64 +
...000_CreateSendControlsPolicies.Designer.cs | 3574 +++++++++++++++++
...260228000000_CreateSendControlsPolicies.cs | 52 +
...000_CreateSendControlsPolicies.Designer.cs | 3557 ++++++++++++++++
...260228000000_CreateSendControlsPolicies.cs | 76 +
16 files changed, 11230 insertions(+)
create mode 100644 src/Core/AdminConsole/Models/Data/Organizations/Policies/SendControlsPolicyData.cs
create mode 100644 src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/SendControlsPolicyRequirement.cs
create mode 100644 src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyValidators/DisableSendSyncPolicyValidator.cs
create mode 100644 src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyValidators/SendControlsSyncPolicyValidator.cs
create mode 100644 src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyValidators/SendOptionsSyncPolicyValidator.cs
create mode 100644 util/Migrator/DbScripts_transition/2026-02-28_00_CreateSendControlsPolicies.sql
create mode 100644 util/MySqlMigrations/Migrations/20260228000000_CreateSendControlsPolicies.Designer.cs
create mode 100644 util/MySqlMigrations/Migrations/20260228000000_CreateSendControlsPolicies.cs
create mode 100644 util/PostgresMigrations/Migrations/20260228000000_CreateSendControlsPolicies.Designer.cs
create mode 100644 util/PostgresMigrations/Migrations/20260228000000_CreateSendControlsPolicies.cs
create mode 100644 util/SqliteMigrations/Migrations/20260228000000_CreateSendControlsPolicies.Designer.cs
create mode 100644 util/SqliteMigrations/Migrations/20260228000000_CreateSendControlsPolicies.cs
diff --git a/src/Core/AdminConsole/Enums/PolicyType.cs b/src/Core/AdminConsole/Enums/PolicyType.cs
index bd6daf7cdffa..ad61782521ab 100644
--- a/src/Core/AdminConsole/Enums/PolicyType.cs
+++ b/src/Core/AdminConsole/Enums/PolicyType.cs
@@ -8,7 +8,11 @@ public enum PolicyType : byte
SingleOrg = 3,
RequireSso = 4,
OrganizationDataOwnership = 5,
+ // Deprecated: superseded by SendControls (20) when pm-31885-send-controls flag is active.
+ // Do not add [Obsolete] until the flag is retired.
DisableSend = 6,
+ // Deprecated: superseded by SendControls (20) when pm-31885-send-controls flag is active.
+ // Do not add [Obsolete] until the flag is retired.
SendOptions = 7,
ResetPassword = 8,
MaximumVaultTimeout = 9,
@@ -22,6 +26,10 @@ public enum PolicyType : byte
AutotypeDefaultSetting = 17,
AutomaticUserConfirmation = 18,
BlockClaimedDomainAccountCreation = 19,
+ ///
+ /// Supersedes DisableSend (6) and SendOptions (7) when the pm-31885-send-controls feature flag is active.
+ ///
+ SendControls = 20,
}
public static class PolicyTypeExtensions
@@ -54,6 +62,7 @@ public static string GetName(this PolicyType type)
PolicyType.AutotypeDefaultSetting => "Autotype default setting",
PolicyType.AutomaticUserConfirmation => "Automatically confirm invited users",
PolicyType.BlockClaimedDomainAccountCreation => "Block account creation for claimed domains",
+ PolicyType.SendControls => "Send controls",
};
}
}
diff --git a/src/Core/AdminConsole/Models/Data/Organizations/Policies/SendControlsPolicyData.cs b/src/Core/AdminConsole/Models/Data/Organizations/Policies/SendControlsPolicyData.cs
new file mode 100644
index 000000000000..4a4027aa4c52
--- /dev/null
+++ b/src/Core/AdminConsole/Models/Data/Organizations/Policies/SendControlsPolicyData.cs
@@ -0,0 +1,12 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
+
+public class SendControlsPolicyData : IPolicyDataModel
+{
+ [Display(Name = "DisableSend")]
+ public bool DisableSend { get; set; }
+
+ [Display(Name = "DisableHideEmail")]
+ public bool DisableHideEmail { get; set; }
+}
diff --git a/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/SendControlsPolicyRequirement.cs b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/SendControlsPolicyRequirement.cs
new file mode 100644
index 000000000000..de0646ff1ba2
--- /dev/null
+++ b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/SendControlsPolicyRequirement.cs
@@ -0,0 +1,39 @@
+using Bit.Core.AdminConsole.Enums;
+using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
+
+namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
+
+///
+/// Policy requirements for the Send Controls policy.
+///
+public class SendControlsPolicyRequirement : IPolicyRequirement
+{
+ ///
+ /// Indicates whether Send is disabled for the user. If true, the user should not be able to create or edit Sends.
+ /// They may still delete existing Sends.
+ ///
+ public bool DisableSend { get; init; }
+
+ ///
+ /// Indicates whether the user is prohibited from hiding their email from the recipient of a Send.
+ ///
+ public bool DisableHideEmail { get; init; }
+}
+
+public class SendControlsPolicyRequirementFactory : BasePolicyRequirementFactory
+{
+ public override PolicyType PolicyType => PolicyType.SendControls;
+
+ public override SendControlsPolicyRequirement Create(IEnumerable policyDetails)
+ {
+ return policyDetails
+ .Select(p => p.GetDataModel())
+ .Aggregate(
+ new SendControlsPolicyRequirement(),
+ (result, data) => new SendControlsPolicyRequirement
+ {
+ DisableSend = result.DisableSend || data.DisableSend,
+ DisableHideEmail = result.DisableHideEmail || data.DisableHideEmail,
+ });
+ }
+}
diff --git a/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyServiceCollectionExtensions.cs b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyServiceCollectionExtensions.cs
index a7657dc71477..c5a0054cf05a 100644
--- a/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyServiceCollectionExtensions.cs
+++ b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyServiceCollectionExtensions.cs
@@ -63,6 +63,9 @@ private static void AddPolicyUpdateEvents(this IServiceCollection services)
services.AddScoped();
services.AddScoped();
services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
}
private static void AddPolicyRequirements(this IServiceCollection services)
@@ -76,5 +79,6 @@ private static void AddPolicyRequirements(this IServiceCollection services)
services.AddScoped, MasterPasswordPolicyRequirementFactory>();
services.AddScoped, SingleOrganizationPolicyRequirementFactory>();
services.AddScoped, AutomaticUserConfirmationPolicyRequirementFactory>();
+ services.AddScoped, SendControlsPolicyRequirementFactory>();
}
}
diff --git a/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyValidators/DisableSendSyncPolicyValidator.cs b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyValidators/DisableSendSyncPolicyValidator.cs
new file mode 100644
index 000000000000..32d085b9da0f
--- /dev/null
+++ b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyValidators/DisableSendSyncPolicyValidator.cs
@@ -0,0 +1,54 @@
+#nullable enable
+
+using Bit.Core.AdminConsole.Entities;
+using Bit.Core.AdminConsole.Enums;
+using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
+using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
+using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
+using Bit.Core.AdminConsole.Repositories;
+using Bit.Core.Utilities;
+
+namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
+
+///
+/// Syncs changes to the DisableSend policy into the SendControls policy row.
+/// Runs regardless of the pm-31885-send-controls feature flag to ensure SendControls
+/// always stays current for when the flag is eventually enabled.
+///
+public class DisableSendSyncPolicyValidator(IPolicyRepository policyRepository) : IOnPolicyPostUpdateEvent
+{
+ public PolicyType Type => PolicyType.DisableSend;
+
+ public async Task ExecutePostUpsertSideEffectAsync(
+ SavePolicyModel policyRequest,
+ Policy postUpsertedPolicyState,
+ Policy? previousPolicyState)
+ {
+ var policyUpdate = policyRequest.PolicyUpdate;
+
+ var sendControlsPolicy = await policyRepository.GetByOrganizationIdTypeAsync(
+ policyUpdate.OrganizationId, PolicyType.SendControls);
+
+ var data = sendControlsPolicy != null
+ ? CoreHelpers.LoadClassFromJsonData(sendControlsPolicy.Data) ?? new SendControlsPolicyData()
+ : new SendControlsPolicyData();
+
+ data.DisableSend = postUpsertedPolicyState.Enabled;
+
+ var policy = sendControlsPolicy ?? new Policy
+ {
+ OrganizationId = policyUpdate.OrganizationId,
+ Type = PolicyType.SendControls,
+ };
+
+ if (sendControlsPolicy == null)
+ {
+ policy.SetNewId();
+ }
+
+ policy.Enabled = data.DisableSend || data.DisableHideEmail;
+ policy.SetDataModel(data);
+
+ await policyRepository.UpsertAsync(policy);
+ }
+}
diff --git a/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyValidators/SendControlsSyncPolicyValidator.cs b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyValidators/SendControlsSyncPolicyValidator.cs
new file mode 100644
index 000000000000..405bc564a176
--- /dev/null
+++ b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyValidators/SendControlsSyncPolicyValidator.cs
@@ -0,0 +1,75 @@
+#nullable enable
+
+using Bit.Core.AdminConsole.Entities;
+using Bit.Core.AdminConsole.Enums;
+using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
+using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
+using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
+using Bit.Core.AdminConsole.Repositories;
+using Bit.Core.Services;
+using Bit.Core.Utilities;
+
+namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
+
+///
+/// When the pm-31885-send-controls flag is active, syncs changes to the SendControls policy
+/// back into the legacy DisableSend and SendOptions policy rows, enabling safe rollback.
+///
+public class SendControlsSyncPolicyValidator(
+ IPolicyRepository policyRepository,
+ IFeatureService featureService) : IOnPolicyPostUpdateEvent
+{
+ public PolicyType Type => PolicyType.SendControls;
+
+ public async Task ExecutePostUpsertSideEffectAsync(
+ SavePolicyModel policyRequest,
+ Policy postUpsertedPolicyState,
+ Policy? previousPolicyState)
+ {
+ if (!featureService.IsEnabled(FeatureFlagKeys.SendControls))
+ {
+ return;
+ }
+
+ var data = CoreHelpers.LoadClassFromJsonData(postUpsertedPolicyState.Data)
+ ?? new SendControlsPolicyData();
+
+ await UpsertLegacyPolicyAsync(
+ policyRequest.PolicyUpdate.OrganizationId,
+ PolicyType.DisableSend,
+ enabled: postUpsertedPolicyState.Enabled && data.DisableSend,
+ policyData: null);
+
+ var sendOptionsData = new SendOptionsPolicyData { DisableHideEmail = data.DisableHideEmail };
+ await UpsertLegacyPolicyAsync(
+ policyRequest.PolicyUpdate.OrganizationId,
+ PolicyType.SendOptions,
+ enabled: postUpsertedPolicyState.Enabled && data.DisableHideEmail,
+ policyData: CoreHelpers.ClassToJsonData(sendOptionsData));
+ }
+
+ private async Task UpsertLegacyPolicyAsync(
+ Guid organizationId,
+ PolicyType type,
+ bool enabled,
+ string? policyData)
+ {
+ var existing = await policyRepository.GetByOrganizationIdTypeAsync(organizationId, type);
+
+ var policy = existing ?? new Policy
+ {
+ OrganizationId = organizationId,
+ Type = type,
+ };
+
+ if (existing == null)
+ {
+ policy.SetNewId();
+ }
+
+ policy.Enabled = enabled;
+ policy.Data = policyData;
+
+ await policyRepository.UpsertAsync(policy);
+ }
+}
diff --git a/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyValidators/SendOptionsSyncPolicyValidator.cs b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyValidators/SendOptionsSyncPolicyValidator.cs
new file mode 100644
index 000000000000..1df362d30688
--- /dev/null
+++ b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyValidators/SendOptionsSyncPolicyValidator.cs
@@ -0,0 +1,58 @@
+#nullable enable
+
+using Bit.Core.AdminConsole.Entities;
+using Bit.Core.AdminConsole.Enums;
+using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
+using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
+using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
+using Bit.Core.AdminConsole.Repositories;
+using Bit.Core.Utilities;
+
+namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
+
+///
+/// Syncs changes to the SendOptions policy into the SendControls policy row.
+/// Runs regardless of the pm-31885-send-controls feature flag to ensure SendControls
+/// always stays current for when the flag is eventually enabled.
+///
+public class SendOptionsSyncPolicyValidator(IPolicyRepository policyRepository) : IOnPolicyPostUpdateEvent
+{
+ public PolicyType Type => PolicyType.SendOptions;
+
+ public async Task ExecutePostUpsertSideEffectAsync(
+ SavePolicyModel policyRequest,
+ Policy postUpsertedPolicyState,
+ Policy? previousPolicyState)
+ {
+ var policyUpdate = policyRequest.PolicyUpdate;
+
+ var parsedSendOptions = postUpsertedPolicyState.Enabled
+ ? CoreHelpers.LoadClassFromJsonData(postUpsertedPolicyState.Data)
+ : null;
+
+ var sendControlsPolicy = await policyRepository.GetByOrganizationIdTypeAsync(
+ policyUpdate.OrganizationId, PolicyType.SendControls);
+
+ var data = sendControlsPolicy != null
+ ? CoreHelpers.LoadClassFromJsonData(sendControlsPolicy.Data) ?? new SendControlsPolicyData()
+ : new SendControlsPolicyData();
+
+ data.DisableHideEmail = parsedSendOptions?.DisableHideEmail ?? false;
+
+ var policy = sendControlsPolicy ?? new Policy
+ {
+ OrganizationId = policyUpdate.OrganizationId,
+ Type = PolicyType.SendControls,
+ };
+
+ if (sendControlsPolicy == null)
+ {
+ policy.SetNewId();
+ }
+
+ policy.Enabled = data.DisableSend || data.DisableHideEmail;
+ policy.SetDataModel(data);
+
+ await policyRepository.UpsertAsync(policy);
+ }
+}
diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs
index a0e8482d668b..9e492ca45435 100644
--- a/src/Core/Constants.cs
+++ b/src/Core/Constants.cs
@@ -244,6 +244,7 @@ public static class FeatureFlagKeys
public const string ChromiumImporterWithABE = "pm-25855-chromium-importer-abe";
public const string SendUIRefresh = "pm-28175-send-ui-refresh";
public const string SendEmailOTP = "pm-19051-send-email-verification";
+ public const string SendControls = "pm-31885-send-controls";
/* Vault Team */
public const string CipherKeyEncryption = "cipher-key-encryption";
diff --git a/src/Core/Tools/SendFeatures/Services/SendValidationService.cs b/src/Core/Tools/SendFeatures/Services/SendValidationService.cs
index bd987bb396bc..afa0caac14e2 100644
--- a/src/Core/Tools/SendFeatures/Services/SendValidationService.cs
+++ b/src/Core/Tools/SendFeatures/Services/SendValidationService.cs
@@ -56,6 +56,12 @@ public SendValidationService(
public async Task ValidateUserCanSaveAsync(Guid? userId, Send send)
{
+ if (_featureService.IsEnabled(FeatureFlagKeys.SendControls))
+ {
+ await ValidateUserCanSaveAsync_SendControls(userId, send);
+ return;
+ }
+
if (_featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements))
{
await ValidateUserCanSaveAsync_vNext(userId, send);
@@ -84,6 +90,32 @@ public async Task ValidateUserCanSaveAsync(Guid? userId, Send send)
}
}
+ private async Task ValidateUserCanSaveAsync_SendControls(Guid? userId, Send send)
+ {
+ if (!userId.HasValue || (!_currentContext.Organizations?.Any() ?? true))
+ {
+ return;
+ }
+
+ var sendControlsPolicies = await _policyService.GetPoliciesApplicableToUserAsync(
+ userId.Value, PolicyType.SendControls);
+
+ if (sendControlsPolicies.Any(p =>
+ CoreHelpers.LoadClassFromJsonData(p.PolicyData)?.DisableSend ?? false))
+ {
+ throw new BadRequestException("Due to an Enterprise Policy, you are only able to delete an existing Send.");
+ }
+
+ if (send.HideEmail.GetValueOrDefault())
+ {
+ if (sendControlsPolicies.Any(p =>
+ CoreHelpers.LoadClassFromJsonData(p.PolicyData)?.DisableHideEmail ?? false))
+ {
+ throw new BadRequestException("Due to an Enterprise Policy, you are not allowed to hide your email address from recipients when creating or editing a Send.");
+ }
+ }
+ }
+
public async Task ValidateUserCanSaveAsync_vNext(Guid? userId, Send send)
{
if (!userId.HasValue)
diff --git a/util/Migrator/DbScripts_transition/2026-02-28_00_CreateSendControlsPolicies.sql b/util/Migrator/DbScripts_transition/2026-02-28_00_CreateSendControlsPolicies.sql
new file mode 100644
index 000000000000..38a42451d4d7
--- /dev/null
+++ b/util/Migrator/DbScripts_transition/2026-02-28_00_CreateSendControlsPolicies.sql
@@ -0,0 +1,55 @@
+-- Migrate existing DisableSend (6) and SendOptions (7) policies into new SendControls (20)
+-- EDD-compatible: only inserts new rows, never modifies existing data
+
+DECLARE @SendControlsType TINYINT = 20;
+DECLARE @DisableSendType TINYINT = 6;
+DECLARE @SendOptionsType TINYINT = 7;
+DECLARE @BatchSize INT = 2000;
+DECLARE @RowsAffected INT = 1;
+
+WHILE @RowsAffected > 0
+BEGIN
+ INSERT INTO [dbo].[Policy] (
+ [Id], [OrganizationId], [Type], [Enabled], [Data], [CreationDate], [RevisionDate]
+ )
+ SELECT TOP (@BatchSize)
+ NEWID(),
+ combined.OrganizationId,
+ @SendControlsType,
+ -- Policy is enabled if either old policy was enabled
+ CASE WHEN ISNULL(combined.DisableSendEnabled, 0) = 1
+ OR ISNULL(combined.SendOptionsEnabled, 0) = 1
+ THEN 1 ELSE 0 END,
+ -- Build JSON: use ISJSON guard for SendOptions.Data
+ N'{"disableSend":' +
+ CASE WHEN ISNULL(combined.DisableSendEnabled, 0) = 1
+ THEN N'true' ELSE N'false' END +
+ N',"disableHideEmail":' +
+ CASE WHEN combined.SendOptionsData IS NOT NULL
+ AND ISJSON(combined.SendOptionsData) = 1
+ AND JSON_VALUE(combined.SendOptionsData, '$.disableHideEmail') = 'true'
+ THEN N'true' ELSE N'false' END +
+ N'}',
+ GETUTCDATE(),
+ GETUTCDATE()
+ FROM (
+ SELECT
+ COALESCE(ds.OrganizationId, so.OrganizationId) AS OrganizationId,
+ ds.Enabled AS DisableSendEnabled,
+ so.Enabled AS SendOptionsEnabled,
+ so.Data AS SendOptionsData
+ FROM [dbo].[Policy] ds
+ FULL OUTER JOIN [dbo].[Policy] so
+ ON ds.OrganizationId = so.OrganizationId
+ AND so.Type = @SendOptionsType
+ WHERE (ds.Type = @DisableSendType OR so.Type = @SendOptionsType)
+ ) combined
+ -- Skip orgs that already have a SendControls row
+ WHERE NOT EXISTS (
+ SELECT 1 FROM [dbo].[Policy] sc
+ WHERE sc.OrganizationId = combined.OrganizationId
+ AND sc.Type = @SendControlsType
+ );
+
+ SET @RowsAffected = @@ROWCOUNT;
+END
diff --git a/util/MySqlMigrations/Migrations/20260228000000_CreateSendControlsPolicies.Designer.cs b/util/MySqlMigrations/Migrations/20260228000000_CreateSendControlsPolicies.Designer.cs
new file mode 100644
index 000000000000..3c9419eecbc4
--- /dev/null
+++ b/util/MySqlMigrations/Migrations/20260228000000_CreateSendControlsPolicies.Designer.cs
@@ -0,0 +1,3568 @@
+//
+using System;
+using Bit.Infrastructure.EntityFramework.Repositories;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Bit.MySqlMigrations.Migrations
+{
+ [DbContext(typeof(DatabaseContext))]
+ [Migration("20260228000000_CreateSendControlsPolicies")]
+ partial class CreateSendControlsPolicies
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.8")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
+
+ modelBuilder.Entity("Bit.Core.Dirt.Reports.Models.Data.OrganizationMemberBaseDetail", b =>
+ {
+ b.Property("CipherId")
+ .HasColumnType("char(36)");
+
+ b.Property("CollectionId")
+ .HasColumnType("char(36)");
+
+ b.Property("CollectionName")
+ .HasColumnType("longtext");
+
+ b.Property("Email")
+ .HasColumnType("longtext");
+
+ b.Property("GroupId")
+ .HasColumnType("char(36)");
+
+ b.Property("GroupName")
+ .HasColumnType("longtext");
+
+ b.Property("HidePasswords")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Manage")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ReadOnly")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ResetPasswordKey")
+ .HasColumnType("longtext");
+
+ b.Property("TwoFactorProviders")
+ .HasColumnType("longtext");
+
+ b.Property("UserGuid")
+ .HasColumnType("char(36)");
+
+ b.Property("UserName")
+ .HasColumnType("longtext");
+
+ b.Property("UsesKeyConnector")
+ .HasColumnType("tinyint(1)");
+
+ b.ToTable("OrganizationMemberBaseDetails");
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AllowAdminAccessToAllCollectionItems")
+ .HasColumnType("tinyint(1)")
+ .HasDefaultValue(true);
+
+ b.Property("BillingEmail")
+ .IsRequired()
+ .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("LimitCollectionCreation")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LimitCollectionDeletion")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LimitItemDeletion")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("MaxAutoscaleSeats")
+ .HasColumnType("int");
+
+ b.Property("MaxAutoscaleSmSeats")
+ .HasColumnType("int");
+
+ b.Property("MaxAutoscaleSmServiceAccounts")
+ .HasColumnType("int");
+
+ b.Property("MaxCollections")
+ .HasColumnType("smallint");
+
+ b.Property("MaxStorageGb")
+ .HasColumnType("smallint");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("OwnersNotifiedOfAutoscaling")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Plan")
+ .IsRequired()
+ .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("SmSeats")
+ .HasColumnType("int");
+
+ b.Property("SmServiceAccounts")
+ .HasColumnType("int");
+
+ b.Property("Status")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("Storage")
+ .HasColumnType("bigint");
+
+ b.Property("SyncSeats")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("TwoFactorProviders")
+ .HasColumnType("longtext");
+
+ b.Property("Use2fa")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseAdminSponsoredFamilies")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseApi")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseAutomaticUserConfirmation")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseCustomPermissions")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseDirectory")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseDisableSmAdsForUsers")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseEvents")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseGroups")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseKeyConnector")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseMyItems")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseOrganizationDomains")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UsePasswordManager")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UsePhishingBlocker")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UsePolicies")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseResetPassword")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseRiskInsights")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseScim")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseSecretsManager")
+ .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.HasIndex("Id", "Enabled")
+ .HasAnnotation("Npgsql:IndexInclude", new[] { "UseTotp", "UsersGetPremium" });
+
+ b.ToTable("Organization", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.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")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.HasIndex("OrganizationId", "Type")
+ .IsUnique()
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.ToTable("Policy", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Provider.Provider", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("BillingEmail")
+ .HasColumnType("longtext");
+
+ b.Property("BillingPhone")
+ .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("DiscountId")
+ .HasColumnType("longtext");
+
+ b.Property("Enabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Gateway")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("GatewayCustomerId")
+ .HasColumnType("longtext");
+
+ b.Property("GatewaySubscriptionId")
+ .HasColumnType("longtext");
+
+ b.Property("Name")
+ .HasColumnType("longtext");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Status")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("UseEvents")
+ .HasColumnType("tinyint(1)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Provider", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.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", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.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", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Auth.Models.AuthRequest", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AccessCode")
+ .HasMaxLength(25)
+ .HasColumnType("varchar(25)");
+
+ b.Property("Approved")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("AuthenticationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Key")
+ .HasColumnType("longtext");
+
+ b.Property("MasterPasswordHash")
+ .HasColumnType("longtext");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("PublicKey")
+ .HasColumnType("longtext");
+
+ b.Property("RequestCountryName")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("RequestDeviceIdentifier")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("RequestDeviceType")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("RequestIpAddress")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("ResponseDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ResponseDeviceId")
+ .HasColumnType("char(36)");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId");
+
+ b.HasIndex("ResponseDeviceId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AuthRequest", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Auth.Models.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("smallint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("GranteeId");
+
+ b.HasIndex("GrantorId");
+
+ b.ToTable("EmergencyAccess", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Auth.Models.Grant", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("ClientId")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("ConsumedDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Data")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("Description")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("ExpirationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Key")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("SessionId")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.Property("SubjectId")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.HasKey("Id")
+ .HasName("PK_Grant")
+ .HasAnnotation("SqlServer:Clustered", true);
+
+ b.HasIndex("ExpirationDate")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.HasIndex("Key")
+ .IsUnique();
+
+ b.ToTable("Grant", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Auth.Models.SsoConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ 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.HasKey("Id");
+
+ b.HasIndex("OrganizationId");
+
+ b.ToTable("SsoConfig", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Auth.Models.SsoUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ExternalId")
+ .HasMaxLength(300)
+ .HasColumnType("varchar(300)");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("OrganizationId", "ExternalId")
+ .IsUnique()
+ .HasAnnotation("Npgsql:IndexInclude", new[] { "UserId" })
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.HasIndex("OrganizationId", "UserId")
+ .IsUnique()
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.ToTable("SsoUser", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Auth.Models.WebAuthnCredential", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AaGuid")
+ .HasColumnType("char(36)");
+
+ b.Property("Counter")
+ .HasColumnType("int");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("CredentialId")
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)");
+
+ b.Property("EncryptedPrivateKey")
+ .HasMaxLength(2000)
+ .HasColumnType("varchar(2000)");
+
+ b.Property("EncryptedPublicKey")
+ .HasMaxLength(2000)
+ .HasColumnType("varchar(2000)");
+
+ b.Property("EncryptedUserKey")
+ .HasMaxLength(2000)
+ .HasColumnType("varchar(2000)");
+
+ b.Property("Name")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("PublicKey")
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("SupportsPrf")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Type")
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("WebAuthnCredential", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Billing.Models.ClientOrganizationMigrationRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("ExpirationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("GatewayCustomerId")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("GatewaySubscriptionId")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("MaxAutoscaleSeats")
+ .HasColumnType("int");
+
+ b.Property("MaxStorageGb")
+ .HasColumnType("smallint");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("PlanType")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("ProviderId")
+ .HasColumnType("char(36)");
+
+ b.Property("Seats")
+ .HasColumnType("int");
+
+ b.Property("Status")
+ .HasColumnType("tinyint unsigned");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ProviderId", "OrganizationId")
+ .IsUnique();
+
+ b.ToTable("ClientOrganizationMigrationRecord", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Billing.Models.OrganizationInstallation", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("InstallationId")
+ .HasColumnType("char(36)");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id")
+ .HasAnnotation("SqlServer:Clustered", true);
+
+ b.HasIndex("InstallationId")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.HasIndex("OrganizationId")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.ToTable("OrganizationInstallation", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Billing.Models.ProviderInvoiceItem", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AssignedSeats")
+ .HasColumnType("int");
+
+ b.Property("ClientId")
+ .HasColumnType("char(36)");
+
+ b.Property("ClientName")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("Created")
+ .HasColumnType("datetime(6)");
+
+ b.Property("InvoiceId")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("InvoiceNumber")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("PlanName")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("ProviderId")
+ .HasColumnType("char(36)");
+
+ b.Property("Total")
+ .HasColumnType("decimal(65,30)");
+
+ b.Property("UsedSeats")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ProviderId");
+
+ b.ToTable("ProviderInvoiceItem", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Billing.Models.ProviderPlan", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AllocatedSeats")
+ .HasColumnType("int");
+
+ b.Property("PlanType")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("ProviderId")
+ .HasColumnType("char(36)");
+
+ b.Property("PurchasedSeats")
+ .HasColumnType("int");
+
+ b.Property("SeatMinimum")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ProviderId");
+
+ b.HasIndex("Id", "PlanType")
+ .IsUnique();
+
+ b.ToTable("ProviderPlan", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Billing.Models.SubscriptionDiscount", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AmountOff")
+ .HasColumnType("bigint");
+
+ b.Property("AudienceType")
+ .HasColumnType("int");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Currency")
+ .HasMaxLength(10)
+ .HasColumnType("varchar(10)");
+
+ b.Property("Duration")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("DurationInMonths")
+ .HasColumnType("int");
+
+ b.Property("EndDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Name")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.Property("PercentOff")
+ .HasPrecision(5, 2)
+ .HasColumnType("decimal(5,2)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("StartDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("StripeCouponId")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property