diff --git a/Source/Modules/LandingPages/Modules.LandingPages.Web.Server/LandingPagesLayout.razor b/Source/Modules/LandingPages/Modules.LandingPages.Web.Server/LandingPagesLayout.razor index 59377392..d0bfa672 100644 --- a/Source/Modules/LandingPages/Modules.LandingPages.Web.Server/LandingPagesLayout.razor +++ b/Source/Modules/LandingPages/Modules.LandingPages.Web.Server/LandingPagesLayout.razor @@ -3,23 +3,25 @@ @inject IModalService modalService
-
diff --git a/Source/Shared/Features/EFCore/DbContextRegistrator.cs b/Source/Shared/Features/EFCore/DbContextRegistrator.cs index c89eb5a8..ec241e03 100644 --- a/Source/Shared/Features/EFCore/DbContextRegistrator.cs +++ b/Source/Shared/Features/EFCore/DbContextRegistrator.cs @@ -1,7 +1,5 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Shared.Kernel.BuildingBlocks; namespace Shared.Features.EFCore { @@ -10,18 +8,6 @@ public static class DbContextRegistrator public static void RegisterDbContext(this IServiceCollection services) where T : DbContext { services.AddDbContext(); - - using (var serviceProvider = services.BuildServiceProvider()) - { - if (serviceProvider.GetRequiredService().HostingEnvironment.IsProduction()) - { - using (var scope = serviceProvider.CreateScope()) - { - var db = scope.ServiceProvider.GetService(); - db.Database.Migrate(); - } - } - } } } } diff --git a/Source/Shared/Features/EFCore/DbUp/Migrations/0001_TenantIdentity_Initial.sql b/Source/Shared/Features/EFCore/DbUp/Migrations/0001_TenantIdentity_Initial.sql new file mode 100644 index 00000000..7c4b1c6b --- /dev/null +++ b/Source/Shared/Features/EFCore/DbUp/Migrations/0001_TenantIdentity_Initial.sql @@ -0,0 +1,228 @@ +IF OBJECT_ID(N'[MigrationHistory_TenantIdentity]') IS NULL +BEGIN + CREATE TABLE [MigrationHistory_TenantIdentity] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK_MigrationHistory_TenantIdentity] PRIMARY KEY ([MigrationId]) + ); +END; +GO + +BEGIN TRANSACTION; +GO + +IF SCHEMA_ID(N'Identity') IS NULL EXEC(N'CREATE SCHEMA [Identity];'); +GO + +CREATE TABLE [Identity].[AspNetRoles] ( + [Id] uniqueidentifier NOT NULL, + [Name] nvarchar(256) NULL, + [NormalizedName] nvarchar(256) NULL, + [ConcurrencyStamp] nvarchar(max) NULL, + CONSTRAINT [PK_AspNetRoles] PRIMARY KEY ([Id]) +); +GO + +CREATE TABLE [Identity].[AspNetUsers] ( + [Id] uniqueidentifier NOT NULL, + [PictureUri] nvarchar(max) NULL, + [CountOfOpenTabs] int NOT NULL, + [SelectedTenantId] uniqueidentifier NOT NULL, + [UserName] nvarchar(256) NULL, + [NormalizedUserName] nvarchar(256) NULL, + [Email] nvarchar(256) NULL, + [NormalizedEmail] nvarchar(256) NULL, + [EmailConfirmed] bit NOT NULL, + [PasswordHash] nvarchar(max) NULL, + [SecurityStamp] nvarchar(max) NULL, + [ConcurrencyStamp] nvarchar(max) NULL, + [PhoneNumber] nvarchar(max) NULL, + [PhoneNumberConfirmed] bit NOT NULL, + [TwoFactorEnabled] bit NOT NULL, + [LockoutEnd] datetimeoffset NULL, + [LockoutEnabled] bit NOT NULL, + [AccessFailedCount] int NOT NULL, + CONSTRAINT [PK_AspNetUsers] PRIMARY KEY ([Id]) +); +GO + +CREATE TABLE [Identity].[TenantSettings] ( + [Id] uniqueidentifier NOT NULL, + [IconURI] nvarchar(max) NULL, + [CreatedByUserId] uniqueidentifier NOT NULL, + [IsSoftDeleted] bit NOT NULL, + [RowVersion] varbinary(max) NULL, + [CreatedAt] datetimeoffset NOT NULL, + [LastUpdatedAt] datetimeoffset NOT NULL, + [IsDeleted] bit NOT NULL, + CONSTRAINT [PK_TenantSettings] PRIMARY KEY ([Id]) +); +GO + +CREATE TABLE [Identity].[TenantStylings] ( + [Id] uniqueidentifier NOT NULL, + [CreatedByUserId] uniqueidentifier NOT NULL, + [IsSoftDeleted] bit NOT NULL, + [RowVersion] varbinary(max) NULL, + [CreatedAt] datetimeoffset NOT NULL, + [LastUpdatedAt] datetimeoffset NOT NULL, + [IsDeleted] bit NOT NULL, + CONSTRAINT [PK_TenantStylings] PRIMARY KEY ([Id]) +); +GO + +CREATE TABLE [Identity].[AspNetRoleClaims] ( + [Id] int NOT NULL IDENTITY, + [RoleId] uniqueidentifier NOT NULL, + [ClaimType] nvarchar(max) NULL, + [ClaimValue] nvarchar(max) NULL, + CONSTRAINT [PK_AspNetRoleClaims] PRIMARY KEY ([Id]), + CONSTRAINT [FK_AspNetRoleClaims_AspNetRoles_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [Identity].[AspNetRoles] ([Id]) ON DELETE CASCADE +); +GO + +CREATE TABLE [Identity].[AspNetUserClaims] ( + [Id] int NOT NULL IDENTITY, + [UserId] uniqueidentifier NOT NULL, + [ClaimType] nvarchar(max) NULL, + [ClaimValue] nvarchar(max) NULL, + [ApplicationUserId] uniqueidentifier NULL, + CONSTRAINT [PK_AspNetUserClaims] PRIMARY KEY ([Id]), + CONSTRAINT [FK_AspNetUserClaims_AspNetUsers_ApplicationUserId] FOREIGN KEY ([ApplicationUserId]) REFERENCES [Identity].[AspNetUsers] ([Id]), + CONSTRAINT [FK_AspNetUserClaims_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [Identity].[AspNetUsers] ([Id]) ON DELETE CASCADE +); +GO + +CREATE TABLE [Identity].[AspNetUserLogins] ( + [LoginProvider] nvarchar(128) NOT NULL, + [ProviderKey] nvarchar(128) NOT NULL, + [ProviderDisplayName] nvarchar(max) NULL, + [UserId] uniqueidentifier NOT NULL, + [ApplicationUserId] uniqueidentifier NULL, + CONSTRAINT [PK_AspNetUserLogins] PRIMARY KEY ([LoginProvider], [ProviderKey]), + CONSTRAINT [FK_AspNetUserLogins_AspNetUsers_ApplicationUserId] FOREIGN KEY ([ApplicationUserId]) REFERENCES [Identity].[AspNetUsers] ([Id]), + CONSTRAINT [FK_AspNetUserLogins_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [Identity].[AspNetUsers] ([Id]) ON DELETE CASCADE +); +GO + +CREATE TABLE [Identity].[AspNetUserRoles] ( + [UserId] uniqueidentifier NOT NULL, + [RoleId] uniqueidentifier NOT NULL, + CONSTRAINT [PK_AspNetUserRoles] PRIMARY KEY ([UserId], [RoleId]), + CONSTRAINT [FK_AspNetUserRoles_AspNetRoles_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [Identity].[AspNetRoles] ([Id]) ON DELETE CASCADE, + CONSTRAINT [FK_AspNetUserRoles_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [Identity].[AspNetUsers] ([Id]) ON DELETE CASCADE +); +GO + +CREATE TABLE [Identity].[AspNetUserTokens] ( + [UserId] uniqueidentifier NOT NULL, + [LoginProvider] nvarchar(128) NOT NULL, + [Name] nvarchar(128) NOT NULL, + [Value] nvarchar(max) NULL, + [ApplicationUserId] uniqueidentifier NULL, + CONSTRAINT [PK_AspNetUserTokens] PRIMARY KEY ([UserId], [LoginProvider], [Name]), + CONSTRAINT [FK_AspNetUserTokens_AspNetUsers_ApplicationUserId] FOREIGN KEY ([ApplicationUserId]) REFERENCES [Identity].[AspNetUsers] ([Id]), + CONSTRAINT [FK_AspNetUserTokens_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [Identity].[AspNetUsers] ([Id]) ON DELETE CASCADE +); +GO + +CREATE TABLE [Identity].[Tenants] ( + [Id] uniqueidentifier NOT NULL, + [TenantId] uniqueidentifier NOT NULL, + [Name] nvarchar(max) NULL, + [StylingId] uniqueidentifier NULL, + [SettingsId] uniqueidentifier NULL, + [SubscriptionPlanType] int NOT NULL, + [CreatedByUserId] uniqueidentifier NOT NULL, + [IsSoftDeleted] bit NOT NULL, + [RowVersion] varbinary(max) NULL, + [CreatedAt] datetimeoffset NOT NULL, + [LastUpdatedAt] datetimeoffset NOT NULL, + [IsDeleted] bit NOT NULL, + CONSTRAINT [PK_Tenants] PRIMARY KEY ([Id]), + CONSTRAINT [FK_Tenants_TenantSettings_SettingsId] FOREIGN KEY ([SettingsId]) REFERENCES [Identity].[TenantSettings] ([Id]), + CONSTRAINT [FK_Tenants_TenantStylings_StylingId] FOREIGN KEY ([StylingId]) REFERENCES [Identity].[TenantStylings] ([Id]) +); +GO + +CREATE TABLE [Identity].[TenantInvitations] ( + [TenantId] uniqueidentifier NOT NULL, + [UserId] uniqueidentifier NOT NULL, + [Role] int NOT NULL, + CONSTRAINT [FK_TenantInvitations_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [Identity].[AspNetUsers] ([Id]) ON DELETE CASCADE, + CONSTRAINT [FK_TenantInvitations_Tenants_TenantId] FOREIGN KEY ([TenantId]) REFERENCES [Identity].[Tenants] ([Id]) ON DELETE CASCADE +); +GO + +CREATE TABLE [Identity].[TenantMeberships] ( + [Id] uniqueidentifier NOT NULL, + [UserId] uniqueidentifier NOT NULL, + [TenantId] uniqueidentifier NULL, + [Role] int NOT NULL, + [ApplicationUserId] uniqueidentifier NULL, + [CreatedByUserId] uniqueidentifier NOT NULL, + [IsSoftDeleted] bit NOT NULL, + [RowVersion] varbinary(max) NULL, + [CreatedAt] datetimeoffset NOT NULL, + [LastUpdatedAt] datetimeoffset NOT NULL, + [IsDeleted] bit NOT NULL, + CONSTRAINT [PK_TenantMeberships] PRIMARY KEY ([Id]), + CONSTRAINT [FK_TenantMeberships_AspNetUsers_ApplicationUserId] FOREIGN KEY ([ApplicationUserId]) REFERENCES [Identity].[AspNetUsers] ([Id]), + CONSTRAINT [FK_TenantMeberships_Tenants_TenantId] FOREIGN KEY ([TenantId]) REFERENCES [Identity].[Tenants] ([Id]) +); +GO + +CREATE INDEX [IX_AspNetRoleClaims_RoleId] ON [Identity].[AspNetRoleClaims] ([RoleId]); +GO + +CREATE UNIQUE INDEX [RoleNameIndex] ON [Identity].[AspNetRoles] ([NormalizedName]) WHERE [NormalizedName] IS NOT NULL; +GO + +CREATE INDEX [IX_AspNetUserClaims_ApplicationUserId] ON [Identity].[AspNetUserClaims] ([ApplicationUserId]); +GO + +CREATE INDEX [IX_AspNetUserClaims_UserId] ON [Identity].[AspNetUserClaims] ([UserId]); +GO + +CREATE INDEX [IX_AspNetUserLogins_ApplicationUserId] ON [Identity].[AspNetUserLogins] ([ApplicationUserId]); +GO + +CREATE INDEX [IX_AspNetUserLogins_UserId] ON [Identity].[AspNetUserLogins] ([UserId]); +GO + +CREATE INDEX [IX_AspNetUserRoles_RoleId] ON [Identity].[AspNetUserRoles] ([RoleId]); +GO + +CREATE INDEX [EmailIndex] ON [Identity].[AspNetUsers] ([NormalizedEmail]); +GO + +CREATE UNIQUE INDEX [UserNameIndex] ON [Identity].[AspNetUsers] ([NormalizedUserName]) WHERE [NormalizedUserName] IS NOT NULL; +GO + +CREATE INDEX [IX_AspNetUserTokens_ApplicationUserId] ON [Identity].[AspNetUserTokens] ([ApplicationUserId]); +GO + +CREATE INDEX [IX_TenantInvitations_TenantId] ON [Identity].[TenantInvitations] ([TenantId]); +GO + +CREATE INDEX [IX_TenantInvitations_UserId] ON [Identity].[TenantInvitations] ([UserId]); +GO + +CREATE INDEX [IX_TenantMeberships_ApplicationUserId] ON [Identity].[TenantMeberships] ([ApplicationUserId]); +GO + +CREATE INDEX [IX_TenantMeberships_TenantId] ON [Identity].[TenantMeberships] ([TenantId]); +GO + +CREATE INDEX [IX_Tenants_SettingsId] ON [Identity].[Tenants] ([SettingsId]); +GO + +CREATE INDEX [IX_Tenants_StylingId] ON [Identity].[Tenants] ([StylingId]); +GO + +INSERT INTO [MigrationHistory_TenantIdentity] ([MigrationId], [ProductVersion]) +VALUES (N'20240210092230_initial', N'8.0.1'); +GO + +COMMIT; +GO \ No newline at end of file diff --git a/Source/Shared/Features/EFCore/DbUp/Registrator.cs b/Source/Shared/Features/EFCore/DbUp/Registrator.cs new file mode 100644 index 00000000..93c7eb16 --- /dev/null +++ b/Source/Shared/Features/EFCore/DbUp/Registrator.cs @@ -0,0 +1,31 @@ +using DbUp; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Shared.Features.EFCore.Configuration; +using Shared.Kernel.BuildingBlocks; +using System.Reflection; + +namespace Shared.Features.EFCore.DbUp +{ + public static class Registrator + { + public static IServiceCollection AddDbUpMigration(this IServiceCollection services) + { + using var serviceProvider = services.BuildServiceProvider(); + + var isProduction = serviceProvider.GetRequiredService().HostingEnvironment.IsProduction(); + var efCoreConfiguration = serviceProvider.GetRequiredService(); + + var upgrader = DeployChanges.To + .SqlDatabase(isProduction ? efCoreConfiguration.SQLServerConnectionString_Prod : efCoreConfiguration.SQLServerConnectionString_Dev) + .WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly()) + .JournalToSqlTable("dbo", "MigrationHistory") + .LogToConsole() + .Build(); + + upgrader.PerformUpgrade(); + + return services; + } + } +} diff --git a/Source/Shared/Features/EFCore/Registrator.cs b/Source/Shared/Features/EFCore/Registrator.cs index 5394ff52..f827a85b 100644 --- a/Source/Shared/Features/EFCore/Registrator.cs +++ b/Source/Shared/Features/EFCore/Registrator.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Shared.Features.EFCore.Configuration; +using Shared.Features.EFCore.DbUp; using Shared.Features.Modules.Configuration; namespace Shared.Features.EFCore @@ -12,6 +13,7 @@ public static IServiceCollection AddEFCore(this IServiceCollection services, ICo { services.RegisterModuleConfiguration(configuration); services.AddScoped(); + services.AddDbUpMigration(); return services; } diff --git a/Source/Shared/Features/Registrator.cs b/Source/Shared/Features/Registrator.cs index 7afb452f..3f9b99a3 100644 --- a/Source/Shared/Features/Registrator.cs +++ b/Source/Shared/Features/Registrator.cs @@ -18,11 +18,11 @@ public static IServiceCollection AddSharedFeatures(this IServiceCollection servi var serviceProvider = services.BuildServiceProvider(); var configuration = serviceProvider.GetRequiredService(); + services.AddServerExecutionContext(); services.AddMessaging(); services.AddEFCore(configuration); services.AddEmailSender(configuration); services.Add_SignalR(); - services.AddServerExecutionContext(); return services; } diff --git a/Source/Shared/Features/Shared.Features.csproj b/Source/Shared/Features/Shared.Features.csproj index 1d48debc..dd184e93 100644 --- a/Source/Shared/Features/Shared.Features.csproj +++ b/Source/Shared/Features/Shared.Features.csproj @@ -4,11 +4,23 @@ net8.0 + + + + + + + PreserveNewest + + + + + diff --git a/Source/Web/Server/Pages/_Host.cshtml b/Source/Web/Server/Pages/_Host.cshtml index 53a23b01..26162c56 100644 --- a/Source/Web/Server/Pages/_Host.cshtml +++ b/Source/Web/Server/Pages/_Host.cshtml @@ -13,7 +13,7 @@ - + @if (User.Identity.IsAuthenticated) { diff --git a/Source/Web/Server/Web.Server.csproj b/Source/Web/Server/Web.Server.csproj index 9a8abb0b..ea3fb5cd 100644 --- a/Source/Web/Server/Web.Server.csproj +++ b/Source/Web/Server/Web.Server.csproj @@ -6,7 +6,7 @@ - + diff --git a/Source/Web/Server/wwwroot/css/fonts.css b/Source/Web/Server/wwwroot/css/fonts.css deleted file mode 100644 index 316a6238..00000000 --- a/Source/Web/Server/wwwroot/css/fonts.css +++ /dev/null @@ -1,126 +0,0 @@ -.text_sm { - font-size: 12px; - line-height: 16px; -} - -.text_normal { - font-size: 14px; - line-height: 16px; -} - -.text_lg { - font-size: 16px; - line-height: 24px; -} - -.text_xlg { - font-size: 18px; - line-height: 28px; -} - -.text_2xlg { - font-size: 24px; - line-height: 28px; -} - -.text_3xlg { - font-size: 28px; - line-height: 32px; -} - - -@media (min-width: 400px){ - .text_sm { - font-size: 13px; - line-height: 18px; - } - - .text_normal { - font-size: 15px; - line-height: 18px; - } - - .text_lg { - font-size: 17px; - line-height: 24px; - } - - .text_xlg { - font-size: 19px; - line-height: 28px; - } - - .text_2xlg { - font-size: 26px; - line-height: 30px; - } - - .text_3xlg { - font-size: 32px; - line-height: 34px; - } -} - -@media (min-width: 768px) { - .text_sm { - font-size: 14px; - line-height: 18px; - } - - .text_normal { - font-size: 16px; - line-height: 20px; - } - - .text_lg { - font-size: 18px; - line-height: 25px; - } - - .text_xlg { - font-size: 20px; - line-height: 28px; - } - - .text_2xlg { - font-size: 30px; - line-height: 32px; - } - - .text_3xlg { - font-size: 36px; - line-height: 34px; - } -} - -@media (min-width: 1024px) { - .text_sm { - font-size: 14px; - line-height: 18px; - } - - .text_normal { - font-size: 16px; - line-height: 22px; - } - - .text_lg { - font-size: 18px; - line-height: 25px; - } - - .text_xlg { - font-size: 24px; - line-height: 30px; - } - - .text_2xlg { - font-size: 34px; - line-height: 40px; - } - - .text_3xlg { - font-size: 42px; - line-height: 44px; - } -} \ No newline at end of file diff --git a/Source/Web/Server/wwwroot/dist/output.css b/Source/Web/Server/wwwroot/dist/output.css index 78eb28f3..d7857dda 100644 --- a/Source/Web/Server/wwwroot/dist/output.css +++ b/Source/Web/Server/wwwroot/dist/output.css @@ -725,24 +725,16 @@ video { --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } -.to-grey-200 { - --tw-gradient-to: rgb(229 231 235) var(--tw-gradient-to-position); -} - -.to-blue-200 { - --tw-gradient-to: #bfdbfe var(--tw-gradient-to-position); -} - -.to-blue-100 { - --tw-gradient-to: #e0f2fe var(--tw-gradient-to-position); +.to-primary-100 { + --tw-gradient-to: #fae8ff var(--tw-gradient-to-position); } .p-1 { padding: 0.25rem; } -.p-\[20px\] { - padding: 20px; +.p-5 { + padding: 1.25rem; } .p-\[5px\] { @@ -801,7 +793,17 @@ video { font-weight: 600; } -.hover\:bg-white:hover { +.text-primary-800 { + --tw-text-opacity: 1; + color: rgb(134 25 143 / var(--tw-text-opacity)); +} + +.text-primary-900 { + --tw-text-opacity: 1; + color: rgb(76 29 149 / var(--tw-text-opacity)); +} + +.hover\:bg-primary-100:hover { --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + background-color: rgb(250 232 255 / var(--tw-bg-opacity)); } diff --git a/Source/tailwind.config.js b/Source/tailwind.config.js index b7974ed7..cdde98c7 100644 --- a/Source/tailwind.config.js +++ b/Source/tailwind.config.js @@ -8,23 +8,23 @@ module.exports = { 'grey-100': '#edeef1', 'grey-200': 'rgb(229 231 235)', 'grey-300': 'rgb(209 213 219)', - 'blue-50': '#f0f9ff', - 'blue-100': '#e0f2fe', - 'blue-200': '#bfdbfe', - 'blue-300': '#7dd3fc', - 'blue-400': '#38bdf8', - 'blue-500': '#0ea5e9', - 'blue-600': '#0284c7', - 'blue-700': '#0369a1' + 'primary-50': '#fdf4ff', + 'primary-100': '#fae8ff', + 'primary-200': '#f5d0fe', + 'primary-300': '#f0abfc', + 'primary-400': '#e879f9', + 'primary-500': '#d946ef', + 'primary-600': '#c026d3', + 'primary-700': '#a21caf', + 'primary-800': '#86198f', + 'primary-900': '#4c1d95' }, screens: { - 'width-xxsm': { 'raw': '(max-width: 300px)' }, - 'width-xsm': { 'raw': '(mim-width: 480px)' }, - 'width-sm': { 'raw': '(min-width: 560px)' }, - 'width-md': { 'raw': '(min-width: 768px)' }, - 'width-lg': { 'raw': '(min-width: 1024px)' }, + 'width-xs': { 'raw': '(mim-width: 480px)' }, + 'width-s': { 'raw': '(min-width: 560px)' }, + 'width-m': { 'raw': '(min-width: 768px)' }, + 'width-l': { 'raw': '(min-width: 1024px)' }, 'width-xl': { 'raw': '(min-width: 1280px)' }, - 'width-2xl': { 'raw': '(min-width: 1536px)' }, } }, plugins: [],