diff --git a/src/Umbraco.Cms.Api.Common/Umbraco.Cms.Api.Common.csproj b/src/Umbraco.Cms.Api.Common/Umbraco.Cms.Api.Common.csproj index 2057a5d9b5..edf3fd1f98 100644 --- a/src/Umbraco.Cms.Api.Common/Umbraco.Cms.Api.Common.csproj +++ b/src/Umbraco.Cms.Api.Common/Umbraco.Cms.Api.Common.csproj @@ -14,6 +14,9 @@ + + + diff --git a/src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs index 37d84bc273..3c10318b07 100644 --- a/src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs @@ -1,7 +1,6 @@ using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Api.Common.Configuration; using Umbraco.Cms.Api.Common.DependencyInjection; using Umbraco.Cms.Api.Delivery.Accessors; using Umbraco.Cms.Api.Delivery.Configuration; @@ -33,6 +32,7 @@ public static class UmbracoBuilderExtensions builder.Services.ConfigureOptions(); builder.AddUmbracoApiOpenApiUI(); + builder.AddUmbracoEFCoreDbContext(); builder .Services .AddControllers() @@ -47,3 +47,4 @@ public static class UmbracoBuilderExtensions return builder; } } + diff --git a/src/Umbraco.Cms.Persistence.EFCore.SqlServer/EFCoreSqlServerComposer.cs b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/EFCoreSqlServerComposer.cs new file mode 100644 index 0000000000..a852fe2c45 --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/EFCoreSqlServerComposer.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Persistence.EFCore.Migrations; + +namespace Umbraco.Cms.Persistence.EFCore.SqlServer; + +public class EFCoreSqlServerComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + } +} diff --git a/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Migrations/20230622184303_InitialCreate.Designer.cs b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Migrations/20230622184303_InitialCreate.Designer.cs new file mode 100644 index 0000000000..602cd3a279 --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Migrations/20230622184303_InitialCreate.Designer.cs @@ -0,0 +1,266 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Umbraco.Cms.Persistence.EFCore.SqlServer.Migrations +{ + [DbContext(typeof(UmbracoDbContext))] + [Migration("20230622184303_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("nvarchar(450)"); + + b.Property("ClientId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("ClientSecret") + .HasColumnType("nvarchar(max)"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ConsentType") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("DisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayNames") + .HasColumnType("nvarchar(max)"); + + b.Property("Permissions") + .HasColumnType("nvarchar(max)"); + + b.Property("PostLogoutRedirectUris") + .HasColumnType("nvarchar(max)"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("RedirectUris") + .HasColumnType("nvarchar(max)"); + + b.Property("Requirements") + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique() + .HasFilter("[ClientId] IS NOT NULL"); + + b.ToTable("umbracoOpenIddictApplications", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("nvarchar(450)"); + + b.Property("ApplicationId") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("Scopes") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("umbracoOpenIddictAuthorizations", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Descriptions") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayNames") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("Resources") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique() + .HasFilter("[Name] IS NOT NULL"); + + b.ToTable("umbracoOpenIddictScopes", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("nvarchar(450)"); + + b.Property("ApplicationId") + .HasColumnType("nvarchar(450)"); + + b.Property("AuthorizationId") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ExpirationDate") + .HasColumnType("datetime2"); + + b.Property("Payload") + .HasColumnType("nvarchar(max)"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("RedemptionDate") + .HasColumnType("datetime2"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorizationId"); + + b.HasIndex("ReferenceId") + .IsUnique() + .HasFilter("[ReferenceId] IS NOT NULL"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("umbracoOpenIddictTokens", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application") + .WithMany("Authorizations") + .HasForeignKey("ApplicationId"); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application") + .WithMany("Tokens") + .HasForeignKey("ApplicationId"); + + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", "Authorization") + .WithMany("Tokens") + .HasForeignKey("AuthorizationId"); + + b.Navigation("Application"); + + b.Navigation("Authorization"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b => + { + b.Navigation("Authorizations"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Navigation("Tokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Migrations/20230622184303_InitialCreate.cs b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Migrations/20230622184303_InitialCreate.cs new file mode 100644 index 0000000000..9bf5191959 --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Migrations/20230622184303_InitialCreate.cs @@ -0,0 +1,166 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Umbraco.Cms.Persistence.EFCore.SqlServer.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "umbracoOpenIddictApplications", + columns: table => new + { + Id = table.Column(type: "nvarchar(450)", nullable: false), + ClientId = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), + ClientSecret = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyToken = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + ConsentType = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + DisplayName = table.Column(type: "nvarchar(max)", nullable: true), + DisplayNames = table.Column(type: "nvarchar(max)", nullable: true), + Permissions = table.Column(type: "nvarchar(max)", nullable: true), + PostLogoutRedirectUris = table.Column(type: "nvarchar(max)", nullable: true), + Properties = table.Column(type: "nvarchar(max)", nullable: true), + RedirectUris = table.Column(type: "nvarchar(max)", nullable: true), + Requirements = table.Column(type: "nvarchar(max)", nullable: true), + Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_umbracoOpenIddictApplications", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "umbracoOpenIddictScopes", + columns: table => new + { + Id = table.Column(type: "nvarchar(450)", nullable: false), + ConcurrencyToken = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + Description = table.Column(type: "nvarchar(max)", nullable: true), + Descriptions = table.Column(type: "nvarchar(max)", nullable: true), + DisplayName = table.Column(type: "nvarchar(max)", nullable: true), + DisplayNames = table.Column(type: "nvarchar(max)", nullable: true), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), + Properties = table.Column(type: "nvarchar(max)", nullable: true), + Resources = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_umbracoOpenIddictScopes", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "umbracoOpenIddictAuthorizations", + columns: table => new + { + Id = table.Column(type: "nvarchar(450)", nullable: false), + ApplicationId = table.Column(type: "nvarchar(450)", nullable: true), + ConcurrencyToken = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: true), + Properties = table.Column(type: "nvarchar(max)", nullable: true), + Scopes = table.Column(type: "nvarchar(max)", nullable: true), + Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + Subject = table.Column(type: "nvarchar(400)", maxLength: 400, nullable: true), + Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_umbracoOpenIddictAuthorizations", x => x.Id); + table.ForeignKey( + name: "FK_umbracoOpenIddictAuthorizations_umbracoOpenIddictApplications_ApplicationId", + column: x => x.ApplicationId, + principalTable: "umbracoOpenIddictApplications", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "umbracoOpenIddictTokens", + columns: table => new + { + Id = table.Column(type: "nvarchar(450)", nullable: false), + ApplicationId = table.Column(type: "nvarchar(450)", nullable: true), + AuthorizationId = table.Column(type: "nvarchar(450)", nullable: true), + ConcurrencyToken = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: true), + ExpirationDate = table.Column(type: "datetime2", nullable: true), + Payload = table.Column(type: "nvarchar(max)", nullable: true), + Properties = table.Column(type: "nvarchar(max)", nullable: true), + RedemptionDate = table.Column(type: "datetime2", nullable: true), + ReferenceId = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), + Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + Subject = table.Column(type: "nvarchar(400)", maxLength: 400, nullable: true), + Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_umbracoOpenIddictTokens", x => x.Id); + table.ForeignKey( + name: "FK_umbracoOpenIddictTokens_umbracoOpenIddictApplications_ApplicationId", + column: x => x.ApplicationId, + principalTable: "umbracoOpenIddictApplications", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_umbracoOpenIddictTokens_umbracoOpenIddictAuthorizations_AuthorizationId", + column: x => x.AuthorizationId, + principalTable: "umbracoOpenIddictAuthorizations", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_umbracoOpenIddictApplications_ClientId", + table: "umbracoOpenIddictApplications", + column: "ClientId", + unique: true, + filter: "[ClientId] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_umbracoOpenIddictAuthorizations_ApplicationId_Status_Subject_Type", + table: "umbracoOpenIddictAuthorizations", + columns: new[] { "ApplicationId", "Status", "Subject", "Type" }); + + migrationBuilder.CreateIndex( + name: "IX_umbracoOpenIddictScopes_Name", + table: "umbracoOpenIddictScopes", + column: "Name", + unique: true, + filter: "[Name] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_umbracoOpenIddictTokens_ApplicationId_Status_Subject_Type", + table: "umbracoOpenIddictTokens", + columns: new[] { "ApplicationId", "Status", "Subject", "Type" }); + + migrationBuilder.CreateIndex( + name: "IX_umbracoOpenIddictTokens_AuthorizationId", + table: "umbracoOpenIddictTokens", + column: "AuthorizationId"); + + migrationBuilder.CreateIndex( + name: "IX_umbracoOpenIddictTokens_ReferenceId", + table: "umbracoOpenIddictTokens", + column: "ReferenceId", + unique: true, + filter: "[ReferenceId] IS NOT NULL"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "umbracoOpenIddictScopes"); + + migrationBuilder.DropTable( + name: "umbracoOpenIddictTokens"); + + migrationBuilder.DropTable( + name: "umbracoOpenIddictAuthorizations"); + + migrationBuilder.DropTable( + name: "umbracoOpenIddictApplications"); + } + } +} diff --git a/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Migrations/UmbracoOpenIddictDbContextModelSnapshot.cs b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Migrations/UmbracoOpenIddictDbContextModelSnapshot.cs new file mode 100644 index 0000000000..fcaa36348f --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Migrations/UmbracoOpenIddictDbContextModelSnapshot.cs @@ -0,0 +1,264 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Umbraco.Cms.Persistence.EFCore; + +#nullable disable + +namespace Umbraco.Cms.Persistence.EFCore.SqlServer.Migrations +{ + [DbContext(typeof(UmbracoDbContext))] + partial class UmbracoOpenIddictDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("nvarchar(450)"); + + b.Property("ClientId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("ClientSecret") + .HasColumnType("nvarchar(max)"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ConsentType") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("DisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayNames") + .HasColumnType("nvarchar(max)"); + + b.Property("Permissions") + .HasColumnType("nvarchar(max)"); + + b.Property("PostLogoutRedirectUris") + .HasColumnType("nvarchar(max)"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("RedirectUris") + .HasColumnType("nvarchar(max)"); + + b.Property("Requirements") + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique() + .HasFilter("[ClientId] IS NOT NULL"); + + b.ToTable("umbracoOpenIddictApplications", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("nvarchar(450)"); + + b.Property("ApplicationId") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("Scopes") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("umbracoOpenIddictAuthorizations", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Descriptions") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayNames") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("Resources") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique() + .HasFilter("[Name] IS NOT NULL"); + + b.ToTable("umbracoOpenIddictScopes", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("nvarchar(450)"); + + b.Property("ApplicationId") + .HasColumnType("nvarchar(450)"); + + b.Property("AuthorizationId") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ExpirationDate") + .HasColumnType("datetime2"); + + b.Property("Payload") + .HasColumnType("nvarchar(max)"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("RedemptionDate") + .HasColumnType("datetime2"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorizationId"); + + b.HasIndex("ReferenceId") + .IsUnique() + .HasFilter("[ReferenceId] IS NOT NULL"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("umbracoOpenIddictTokens", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application") + .WithMany("Authorizations") + .HasForeignKey("ApplicationId"); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application") + .WithMany("Tokens") + .HasForeignKey("ApplicationId"); + + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", "Authorization") + .WithMany("Tokens") + .HasForeignKey("AuthorizationId"); + + b.Navigation("Application"); + + b.Navigation("Authorization"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b => + { + b.Navigation("Authorizations"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Navigation("Tokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProvider.cs b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProvider.cs new file mode 100644 index 0000000000..45e431eb8f --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProvider.cs @@ -0,0 +1,33 @@ +using Microsoft.EntityFrameworkCore; +using Umbraco.Cms.Persistence.EFCore.Migrations; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Persistence.EFCore.SqlServer; + +public class SqlServerMigrationProvider : IMigrationProvider +{ + private readonly IDbContextFactory _dbContextFactory; + + public SqlServerMigrationProvider(IDbContextFactory dbContextFactory) => _dbContextFactory = dbContextFactory; + + public string ProviderName => "Microsoft.Data.SqlClient"; + + public async Task MigrateAsync(EFCoreMigration migration) + { + UmbracoDbContext context = await _dbContextFactory.CreateDbContextAsync(); + await context.MigrateDatabaseAsync(GetMigrationType(migration)); + } + + public async Task MigrateAllAsync() + { + UmbracoDbContext context = await _dbContextFactory.CreateDbContextAsync(); + await context.Database.MigrateAsync(); + } + + private static Type GetMigrationType(EFCoreMigration migration) => + migration switch + { + EFCoreMigration.InitialCreate => typeof(Migrations.InitialCreate), + _ => throw new ArgumentOutOfRangeException(nameof(migration), $@"Not expected migration value: {migration}") + }; +} diff --git a/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProviderSetup.cs b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProviderSetup.cs new file mode 100644 index 0000000000..6b161fc47f --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProviderSetup.cs @@ -0,0 +1,14 @@ +using Microsoft.EntityFrameworkCore; +using Umbraco.Cms.Persistence.EFCore.Migrations; + +namespace Umbraco.Cms.Persistence.EFCore.SqlServer; + +public class SqlServerMigrationProviderSetup : IMigrationProviderSetup +{ + public string ProviderName => "Microsoft.Data.SqlClient"; + + public void Setup(DbContextOptionsBuilder builder, string? connectionString) + { + builder.UseSqlServer(connectionString, x => x.MigrationsAssembly(GetType().Assembly.FullName)); + } +} diff --git a/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Umbraco.Cms.Persistence.EFCore.SqlServer.csproj b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Umbraco.Cms.Persistence.EFCore.SqlServer.csproj new file mode 100644 index 0000000000..946c08556f --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Umbraco.Cms.Persistence.EFCore.SqlServer.csproj @@ -0,0 +1,15 @@ + + + Umbraco CMS - EF Core - SqlServer migrations + + false + + + + + + + + + + diff --git a/src/Umbraco.Cms.Persistence.EFCore.Sqlite/EFCoreSqliteComposer.cs b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/EFCoreSqliteComposer.cs new file mode 100644 index 0000000000..afa3237db5 --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/EFCoreSqliteComposer.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Persistence.EFCore.Migrations; + +namespace Umbraco.Cms.Persistence.EFCore.Sqlite; + +public class EFCoreSqliteComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + } +} diff --git a/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Migrations/20230622183638_InitialCreate.Designer.cs b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Migrations/20230622183638_InitialCreate.Designer.cs new file mode 100644 index 0000000000..611f1c31cb --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Migrations/20230622183638_InitialCreate.Designer.cs @@ -0,0 +1,258 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Umbraco.Cms.Persistence.EFCore.Sqlite.Migrations +{ + [DbContext(typeof(UmbracoDbContext))] + [Migration("20230622183638_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.7"); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ClientId") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("ClientSecret") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ConsentType") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("DisplayName") + .HasColumnType("TEXT"); + + b.Property("DisplayNames") + .HasColumnType("TEXT"); + + b.Property("Permissions") + .HasColumnType("TEXT"); + + b.Property("PostLogoutRedirectUris") + .HasColumnType("TEXT"); + + b.Property("Properties") + .HasColumnType("TEXT"); + + b.Property("RedirectUris") + .HasColumnType("TEXT"); + + b.Property("Requirements") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique(); + + b.ToTable("umbracoOpenIddictApplications", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ApplicationId") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Properties") + .HasColumnType("TEXT"); + + b.Property("Scopes") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("TEXT"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("umbracoOpenIddictAuthorizations", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("Descriptions") + .HasColumnType("TEXT"); + + b.Property("DisplayName") + .HasColumnType("TEXT"); + + b.Property("DisplayNames") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("Properties") + .HasColumnType("TEXT"); + + b.Property("Resources") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("umbracoOpenIddictScopes", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ApplicationId") + .HasColumnType("TEXT"); + + b.Property("AuthorizationId") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("ExpirationDate") + .HasColumnType("TEXT"); + + b.Property("Payload") + .HasColumnType("TEXT"); + + b.Property("Properties") + .HasColumnType("TEXT"); + + b.Property("RedemptionDate") + .HasColumnType("TEXT"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("TEXT"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AuthorizationId"); + + b.HasIndex("ReferenceId") + .IsUnique(); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("umbracoOpenIddictTokens", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application") + .WithMany("Authorizations") + .HasForeignKey("ApplicationId"); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application") + .WithMany("Tokens") + .HasForeignKey("ApplicationId"); + + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", "Authorization") + .WithMany("Tokens") + .HasForeignKey("AuthorizationId"); + + b.Navigation("Application"); + + b.Navigation("Authorization"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b => + { + b.Navigation("Authorizations"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Navigation("Tokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Migrations/20230622183638_InitialCreate.cs b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Migrations/20230622183638_InitialCreate.cs new file mode 100644 index 0000000000..ea1b21ac3f --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Migrations/20230622183638_InitialCreate.cs @@ -0,0 +1,163 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Umbraco.Cms.Persistence.EFCore.Sqlite.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "umbracoOpenIddictApplications", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + ClientId = table.Column(type: "TEXT", maxLength: 100, nullable: true), + ClientSecret = table.Column(type: "TEXT", nullable: true), + ConcurrencyToken = table.Column(type: "TEXT", maxLength: 50, nullable: true), + ConsentType = table.Column(type: "TEXT", maxLength: 50, nullable: true), + DisplayName = table.Column(type: "TEXT", nullable: true), + DisplayNames = table.Column(type: "TEXT", nullable: true), + Permissions = table.Column(type: "TEXT", nullable: true), + PostLogoutRedirectUris = table.Column(type: "TEXT", nullable: true), + Properties = table.Column(type: "TEXT", nullable: true), + RedirectUris = table.Column(type: "TEXT", nullable: true), + Requirements = table.Column(type: "TEXT", nullable: true), + Type = table.Column(type: "TEXT", maxLength: 50, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_umbracoOpenIddictApplications", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "umbracoOpenIddictScopes", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + ConcurrencyToken = table.Column(type: "TEXT", maxLength: 50, nullable: true), + Description = table.Column(type: "TEXT", nullable: true), + Descriptions = table.Column(type: "TEXT", nullable: true), + DisplayName = table.Column(type: "TEXT", nullable: true), + DisplayNames = table.Column(type: "TEXT", nullable: true), + Name = table.Column(type: "TEXT", maxLength: 200, nullable: true), + Properties = table.Column(type: "TEXT", nullable: true), + Resources = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_umbracoOpenIddictScopes", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "umbracoOpenIddictAuthorizations", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + ApplicationId = table.Column(type: "TEXT", nullable: true), + ConcurrencyToken = table.Column(type: "TEXT", maxLength: 50, nullable: true), + CreationDate = table.Column(type: "TEXT", nullable: true), + Properties = table.Column(type: "TEXT", nullable: true), + Scopes = table.Column(type: "TEXT", nullable: true), + Status = table.Column(type: "TEXT", maxLength: 50, nullable: true), + Subject = table.Column(type: "TEXT", maxLength: 400, nullable: true), + Type = table.Column(type: "TEXT", maxLength: 50, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_umbracoOpenIddictAuthorizations", x => x.Id); + table.ForeignKey( + name: "FK_umbracoOpenIddictAuthorizations_umbracoOpenIddictApplications_ApplicationId", + column: x => x.ApplicationId, + principalTable: "umbracoOpenIddictApplications", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "umbracoOpenIddictTokens", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + ApplicationId = table.Column(type: "TEXT", nullable: true), + AuthorizationId = table.Column(type: "TEXT", nullable: true), + ConcurrencyToken = table.Column(type: "TEXT", maxLength: 50, nullable: true), + CreationDate = table.Column(type: "TEXT", nullable: true), + ExpirationDate = table.Column(type: "TEXT", nullable: true), + Payload = table.Column(type: "TEXT", nullable: true), + Properties = table.Column(type: "TEXT", nullable: true), + RedemptionDate = table.Column(type: "TEXT", nullable: true), + ReferenceId = table.Column(type: "TEXT", maxLength: 100, nullable: true), + Status = table.Column(type: "TEXT", maxLength: 50, nullable: true), + Subject = table.Column(type: "TEXT", maxLength: 400, nullable: true), + Type = table.Column(type: "TEXT", maxLength: 50, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_umbracoOpenIddictTokens", x => x.Id); + table.ForeignKey( + name: "FK_umbracoOpenIddictTokens_umbracoOpenIddictApplications_ApplicationId", + column: x => x.ApplicationId, + principalTable: "umbracoOpenIddictApplications", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_umbracoOpenIddictTokens_umbracoOpenIddictAuthorizations_AuthorizationId", + column: x => x.AuthorizationId, + principalTable: "umbracoOpenIddictAuthorizations", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_umbracoOpenIddictApplications_ClientId", + table: "umbracoOpenIddictApplications", + column: "ClientId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_umbracoOpenIddictAuthorizations_ApplicationId_Status_Subject_Type", + table: "umbracoOpenIddictAuthorizations", + columns: new[] { "ApplicationId", "Status", "Subject", "Type" }); + + migrationBuilder.CreateIndex( + name: "IX_umbracoOpenIddictScopes_Name", + table: "umbracoOpenIddictScopes", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_umbracoOpenIddictTokens_ApplicationId_Status_Subject_Type", + table: "umbracoOpenIddictTokens", + columns: new[] { "ApplicationId", "Status", "Subject", "Type" }); + + migrationBuilder.CreateIndex( + name: "IX_umbracoOpenIddictTokens_AuthorizationId", + table: "umbracoOpenIddictTokens", + column: "AuthorizationId"); + + migrationBuilder.CreateIndex( + name: "IX_umbracoOpenIddictTokens_ReferenceId", + table: "umbracoOpenIddictTokens", + column: "ReferenceId", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "umbracoOpenIddictScopes"); + + migrationBuilder.DropTable( + name: "umbracoOpenIddictTokens"); + + migrationBuilder.DropTable( + name: "umbracoOpenIddictAuthorizations"); + + migrationBuilder.DropTable( + name: "umbracoOpenIddictApplications"); + } + } +} diff --git a/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Migrations/UmbracoOpenIddictDbContextModelSnapshot.cs b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Migrations/UmbracoOpenIddictDbContextModelSnapshot.cs new file mode 100644 index 0000000000..da82993433 --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Migrations/UmbracoOpenIddictDbContextModelSnapshot.cs @@ -0,0 +1,256 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Umbraco.Cms.Persistence.EFCore; + +#nullable disable + +namespace Umbraco.Cms.Persistence.EFCore.Sqlite.Migrations +{ + [DbContext(typeof(UmbracoDbContext))] + partial class UmbracoOpenIddictDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.7"); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ClientId") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("ClientSecret") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ConsentType") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("DisplayName") + .HasColumnType("TEXT"); + + b.Property("DisplayNames") + .HasColumnType("TEXT"); + + b.Property("Permissions") + .HasColumnType("TEXT"); + + b.Property("PostLogoutRedirectUris") + .HasColumnType("TEXT"); + + b.Property("Properties") + .HasColumnType("TEXT"); + + b.Property("RedirectUris") + .HasColumnType("TEXT"); + + b.Property("Requirements") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique(); + + b.ToTable("umbracoOpenIddictApplications", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ApplicationId") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Properties") + .HasColumnType("TEXT"); + + b.Property("Scopes") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("TEXT"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("umbracoOpenIddictAuthorizations", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("Descriptions") + .HasColumnType("TEXT"); + + b.Property("DisplayName") + .HasColumnType("TEXT"); + + b.Property("DisplayNames") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("Properties") + .HasColumnType("TEXT"); + + b.Property("Resources") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("umbracoOpenIddictScopes", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ApplicationId") + .HasColumnType("TEXT"); + + b.Property("AuthorizationId") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("ExpirationDate") + .HasColumnType("TEXT"); + + b.Property("Payload") + .HasColumnType("TEXT"); + + b.Property("Properties") + .HasColumnType("TEXT"); + + b.Property("RedemptionDate") + .HasColumnType("TEXT"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("TEXT"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AuthorizationId"); + + b.HasIndex("ReferenceId") + .IsUnique(); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("umbracoOpenIddictTokens", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application") + .WithMany("Authorizations") + .HasForeignKey("ApplicationId"); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application") + .WithMany("Tokens") + .HasForeignKey("ApplicationId"); + + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", "Authorization") + .WithMany("Tokens") + .HasForeignKey("AuthorizationId"); + + b.Navigation("Application"); + + b.Navigation("Authorization"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b => + { + b.Navigation("Authorizations"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Navigation("Tokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProvider.cs b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProvider.cs new file mode 100644 index 0000000000..b3b9897f80 --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProvider.cs @@ -0,0 +1,40 @@ +using Microsoft.EntityFrameworkCore; +using Umbraco.Cms.Persistence.EFCore.Migrations; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Persistence.EFCore.Sqlite; + +public class SqliteMigrationProvider : IMigrationProvider +{ + private readonly IDbContextFactory _dbContextFactory; + + public SqliteMigrationProvider(IDbContextFactory dbContextFactory) + => _dbContextFactory = dbContextFactory; + + public string ProviderName => "Microsoft.Data.Sqlite"; + + public async Task MigrateAsync(EFCoreMigration migration) + { + UmbracoDbContext context = await _dbContextFactory.CreateDbContextAsync(); + await context.MigrateDatabaseAsync(GetMigrationType(migration)); + } + + public async Task MigrateAllAsync() + { + UmbracoDbContext context = await _dbContextFactory.CreateDbContextAsync(); + + if (context.Database.CurrentTransaction is not null) + { + throw new InvalidOperationException("Cannot migrate all when a transaction is active."); + } + + await context.Database.MigrateAsync(); + } + + private static Type GetMigrationType(EFCoreMigration migration) => + migration switch + { + EFCoreMigration.InitialCreate => typeof(Migrations.InitialCreate), + _ => throw new ArgumentOutOfRangeException(nameof(migration), $@"Not expected migration value: {migration}") + }; +} diff --git a/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProviderSetup.cs b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProviderSetup.cs new file mode 100644 index 0000000000..4cba457768 --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProviderSetup.cs @@ -0,0 +1,14 @@ +using Microsoft.EntityFrameworkCore; +using Umbraco.Cms.Persistence.EFCore.Migrations; + +namespace Umbraco.Cms.Persistence.EFCore.Sqlite; + +public class SqliteMigrationProviderSetup : IMigrationProviderSetup +{ + public string ProviderName => "Microsoft.Data.Sqlite"; + + public void Setup(DbContextOptionsBuilder builder, string? connectionString) + { + builder.UseSqlite(connectionString, x => x.MigrationsAssembly(GetType().Assembly.FullName)); + } +} diff --git a/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Umbraco.Cms.Persistence.EFCore.Sqlite.csproj b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Umbraco.Cms.Persistence.EFCore.Sqlite.csproj new file mode 100644 index 0000000000..f95f1cd1e1 --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Umbraco.Cms.Persistence.EFCore.Sqlite.csproj @@ -0,0 +1,15 @@ + + + Umbraco CMS - EF Core - Sqlite migrations + + false + + + + + + + + + + diff --git a/src/Umbraco.Cms.Persistence.EFCore/Composition/UmbracoEFCoreComposer.cs b/src/Umbraco.Cms.Persistence.EFCore/Composition/UmbracoEFCoreComposer.cs new file mode 100644 index 0000000000..7d5bf0dd11 --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore/Composition/UmbracoEFCoreComposer.cs @@ -0,0 +1,56 @@ +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Infrastructure.Migrations; +using Umbraco.Cms.Infrastructure.Migrations.Notifications; +using Umbraco.Cms.Persistence.EFCore; + +namespace Umbraco.Cms.Persistence.EFCore.Composition; + +public class UmbracoEFCoreComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.Services.AddSingleton(); + + builder.AddNotificationAsyncHandler(); + builder.AddNotificationAsyncHandler(); + builder.Services.AddOpenIddict() + + // Register the OpenIddict core components. + .AddCore(options => + { + options + .UseEntityFrameworkCore() + .UseDbContext(); + }); + } +} + + +public class EFCoreCreateTablesNotificationHandler : INotificationAsyncHandler, INotificationAsyncHandler +{ + private readonly IEFCoreMigrationExecutor _iefCoreMigrationExecutor; + + public EFCoreCreateTablesNotificationHandler(IEFCoreMigrationExecutor iefCoreMigrationExecutor) + { + _iefCoreMigrationExecutor = iefCoreMigrationExecutor; + } + + public async Task HandleAsync(UnattendedInstallNotification notification, CancellationToken cancellationToken) + { + await HandleAsync(); + } + + public async Task HandleAsync(DatabaseSchemaAndDataCreatedNotification notification, CancellationToken cancellationToken) + { + await HandleAsync(); + } + + private async Task HandleAsync() + { + await _iefCoreMigrationExecutor.ExecuteAllMigrationsAsync(); + } +} diff --git a/src/Umbraco.Cms.Persistence.EFCore/EfCoreMigrationExecutor.cs b/src/Umbraco.Cms.Persistence.EFCore/EfCoreMigrationExecutor.cs new file mode 100644 index 0000000000..8de8e1f1b8 --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore/EfCoreMigrationExecutor.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Infrastructure.Migrations; +using Umbraco.Cms.Persistence.EFCore.Migrations; + +namespace Umbraco.Cms.Persistence.EFCore; + +public class EfCoreMigrationExecutor : IEFCoreMigrationExecutor +{ + private readonly IEnumerable _migrationProviders; + private readonly IOptions _options; + + // We need to do migrations out side of a scope due to sqlite + public EfCoreMigrationExecutor( + IEnumerable migrationProviders, + IOptions options) + { + _migrationProviders = migrationProviders; + _options = options; + } + + public async Task ExecuteSingleMigrationAsync(EFCoreMigration migration) + { + IMigrationProvider? provider = _migrationProviders.FirstOrDefault(x => x.ProviderName == _options.Value.ProviderName); + + if (provider is not null) + { + await provider.MigrateAsync(migration); + } + } + + public async Task ExecuteAllMigrationsAsync() + { + IMigrationProvider? provider = _migrationProviders.FirstOrDefault(x => x.ProviderName == _options.Value.ProviderName); + + if (provider is not null) + { + await provider.MigrateAllAsync(); + } + } + +} diff --git a/src/Umbraco.Cms.Persistence.EFCore/Extensions/BackOfficeAuthBuilderOpenIddictExtensions.cs b/src/Umbraco.Cms.Persistence.EFCore/Extensions/BackOfficeAuthBuilderOpenIddictExtensions.cs new file mode 100644 index 0000000000..2672b3b849 --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore/Extensions/BackOfficeAuthBuilderOpenIddictExtensions.cs @@ -0,0 +1,19 @@ +using Microsoft.EntityFrameworkCore; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Persistence.EFCore; + +namespace Umbraco.Extensions; + +public static class BackOfficeAuthBuilderOpenIddictExtensions +{ + public static IUmbracoBuilder AddUmbracoEFCoreDbContext(this IUmbracoBuilder builder) + { + builder.Services.AddUmbracoEFCoreContext((options, connectionString, providerName) => + { + // Register the entity sets needed by OpenIddict. + options.UseOpenIddict(); + }); + + return builder; + } +} diff --git a/src/Umbraco.Cms.Persistence.EFCore/Extensions/DbContextExtensions.cs b/src/Umbraco.Cms.Persistence.EFCore/Extensions/DbContextExtensions.cs index 573f57e75f..98a7b5779d 100644 --- a/src/Umbraco.Cms.Persistence.EFCore/Extensions/DbContextExtensions.cs +++ b/src/Umbraco.Cms.Persistence.EFCore/Extensions/DbContextExtensions.cs @@ -2,6 +2,7 @@ using System.Data; using System.Data.Common; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage; namespace Umbraco.Extensions; @@ -50,4 +51,21 @@ public static class DbContextExtensions var result = await dbCommand.ExecuteScalarAsync(); return (T?)result; } + + public static async Task MigrateDatabaseAsync(this DbContext context, Type targetMigration) + { + MigrationAttribute? migrationAttribute = targetMigration.GetCustomAttribute(false); + + if (migrationAttribute is null) + { + throw new ArgumentException("The type does not have a MigrationAttribute", nameof(targetMigration)); + } + + await context.MigrateDatabaseAsync(migrationAttribute.Id); + } + + public static async Task MigrateDatabaseAsync(this DbContext context, string targetMigrationId) + { + await context.GetService().MigrateAsync(targetMigrationId); + } } diff --git a/src/Umbraco.Cms.Persistence.EFCore/Extensions/UmbracoEFCoreServiceCollectionExtensions.cs b/src/Umbraco.Cms.Persistence.EFCore/Extensions/UmbracoEFCoreServiceCollectionExtensions.cs index 4d47e64448..52c187dba3 100644 --- a/src/Umbraco.Cms.Persistence.EFCore/Extensions/UmbracoEFCoreServiceCollectionExtensions.cs +++ b/src/Umbraco.Cms.Persistence.EFCore/Extensions/UmbracoEFCoreServiceCollectionExtensions.cs @@ -1,8 +1,11 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.DistributedLocking; using Umbraco.Cms.Persistence.EFCore.Locking; +using Umbraco.Cms.Persistence.EFCore.Migrations; using Umbraco.Cms.Persistence.EFCore.Scoping; namespace Umbraco.Extensions; @@ -11,6 +14,55 @@ public static class UmbracoEFCoreServiceCollectionExtensions { public delegate void DefaultEFCoreOptionsAction(DbContextOptionsBuilder options, string? providerName, string? connectionString); + public static IServiceCollection AddUmbracoEFCoreContext(this IServiceCollection services, DefaultEFCoreOptionsAction? defaultEFCoreOptionsAction = null) + where T : DbContext + { + defaultEFCoreOptionsAction ??= DefaultOptionsAction; + + services.AddDbContext( + (provider, builder) => SetupDbContext(defaultEFCoreOptionsAction, provider, builder), + optionsLifetime: ServiceLifetime.Transient); + + + + services.AddDbContextFactory((provider, builder) => SetupDbContext(defaultEFCoreOptionsAction, provider, builder)); + + services.AddUnique, AmbientEFCoreScopeStack>(); + services.AddUnique, EFCoreScopeAccessor>(); + services.AddUnique, EFCoreScopeProvider>(); + services.AddSingleton>(); + services.AddSingleton>(); + + return services; + } + + private static void SetupDbContext(DefaultEFCoreOptionsAction defaultEFCoreOptionsAction, IServiceProvider provider, DbContextOptionsBuilder builder) + { + ConnectionStrings connectionStrings = GetConnectionStringAndProviderName(provider); + IEnumerable migrationProviders = provider.GetServices(); + IMigrationProviderSetup? migrationProvider = + migrationProviders.FirstOrDefault(x => x.ProviderName == connectionStrings.ProviderName); + migrationProvider?.Setup(builder, connectionStrings.ConnectionString); + defaultEFCoreOptionsAction(builder, connectionStrings.ConnectionString, connectionStrings.ProviderName); + } + + private static ConnectionStrings GetConnectionStringAndProviderName(IServiceProvider serviceProvider) + { + string? connectionString = null; + string? providerName = null; + + ConnectionStrings connectionStrings = serviceProvider.GetRequiredService>().CurrentValue; + + // Replace data directory + string? dataDirectory = AppDomain.CurrentDomain.GetData(Constants.System.DataDirectoryName)?.ToString(); + if (string.IsNullOrEmpty(dataDirectory) is false) + { + connectionStrings.ConnectionString = connectionStrings.ConnectionString?.Replace(Constants.System.DataDirectoryPlaceholder, dataDirectory); + } + + return connectionStrings; + } + public static IServiceCollection AddUmbracoEFCoreContext(this IServiceCollection services, string connectionString, string providerName, DefaultEFCoreOptionsAction? defaultEFCoreOptionsAction = null) where T : DbContext { diff --git a/src/Umbraco.Cms.Persistence.EFCore/Migrations/IMigrationProvider.cs b/src/Umbraco.Cms.Persistence.EFCore/Migrations/IMigrationProvider.cs new file mode 100644 index 0000000000..175a8f2ee6 --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore/Migrations/IMigrationProvider.cs @@ -0,0 +1,10 @@ +namespace Umbraco.Cms.Persistence.EFCore.Migrations; + +public interface IMigrationProvider +{ + string ProviderName { get; } + + Task MigrateAsync(EFCoreMigration migration); + + Task MigrateAllAsync(); +} diff --git a/src/Umbraco.Cms.Persistence.EFCore/Migrations/IMigrationProviderSetup.cs b/src/Umbraco.Cms.Persistence.EFCore/Migrations/IMigrationProviderSetup.cs new file mode 100644 index 0000000000..09206d0eee --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore/Migrations/IMigrationProviderSetup.cs @@ -0,0 +1,10 @@ +using Microsoft.EntityFrameworkCore; + +namespace Umbraco.Cms.Persistence.EFCore.Migrations; + +public interface IMigrationProviderSetup +{ + string ProviderName { get; } + + void Setup(DbContextOptionsBuilder builder, string? connectionString); +} diff --git a/src/Umbraco.Cms.Persistence.EFCore/Umbraco.Cms.Persistence.EFCore.csproj b/src/Umbraco.Cms.Persistence.EFCore/Umbraco.Cms.Persistence.EFCore.csproj index c73eb3c3ed..f8e3851ccd 100644 --- a/src/Umbraco.Cms.Persistence.EFCore/Umbraco.Cms.Persistence.EFCore.csproj +++ b/src/Umbraco.Cms.Persistence.EFCore/Umbraco.Cms.Persistence.EFCore.csproj @@ -8,7 +8,6 @@ - diff --git a/src/Umbraco.Cms.Persistence.EFCore/UmbracoDbContext.cs b/src/Umbraco.Cms.Persistence.EFCore/UmbracoDbContext.cs new file mode 100644 index 0000000000..2c940602ac --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore/UmbracoDbContext.cs @@ -0,0 +1,33 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata; +using Umbraco.Cms.Core; + +namespace Umbraco.Cms.Persistence.EFCore; + +/// +/// To autogenerate migrations use the following commands +/// and insure the 'src/Umbraco.Web.UI/appsettings.json' have a connection string set with the right provider. +/// +/// dotnet ef migrations add %Name% -s src/Umbraco.Web.UI -p src/Umbraco.Cms.Persistence.EFCore.SqlServer -- --provider SqlServer +/// dotnet ef migrations add %Name% -s src/Umbraco.Web.UI -p src/Umbraco.Cms.Persistence.EFCore.Sqlite -- --provider Sqlite +/// +/// To find documentation about this way of working with the context see +/// https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/providers?tabs=dotnet-core-cli#using-one-context-type +/// +public class UmbracoDbContext : DbContext +{ + public UmbracoDbContext(DbContextOptions options) + : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + foreach (IMutableEntityType entity in modelBuilder.Model.GetEntityTypes()) + { + entity.SetTableName(Constants.DatabaseSchema.TableNamePrefix + entity.GetTableName()); + } + } +} diff --git a/src/Umbraco.Infrastructure/Migrations/EFCoreMigration.cs b/src/Umbraco.Infrastructure/Migrations/EFCoreMigration.cs new file mode 100644 index 0000000000..8086b68f24 --- /dev/null +++ b/src/Umbraco.Infrastructure/Migrations/EFCoreMigration.cs @@ -0,0 +1,6 @@ +namespace Umbraco.Cms.Persistence.EFCore.Migrations; + +public enum EFCoreMigration +{ + InitialCreate = 0 +} diff --git a/src/Umbraco.Infrastructure/Migrations/IEFCoreMigrationExecutor.cs b/src/Umbraco.Infrastructure/Migrations/IEFCoreMigrationExecutor.cs new file mode 100644 index 0000000000..e61468e979 --- /dev/null +++ b/src/Umbraco.Infrastructure/Migrations/IEFCoreMigrationExecutor.cs @@ -0,0 +1,10 @@ +using Umbraco.Cms.Persistence.EFCore.Migrations; + +namespace Umbraco.Cms.Infrastructure.Migrations; + +public interface IEFCoreMigrationExecutor +{ + Task ExecuteSingleMigrationAsync(EFCoreMigration efCoreMigration); + + Task ExecuteAllMigrationsAsync(); +} diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index cd9266d45e..bfa196a136 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -291,6 +291,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install using (var scope = _scopeProvider.CreateCoreScope()) { var result = CreateSchemaAndData(scope); + scope.Notifications.Publish(new DatabaseSchemaAndDataCreatedNotification()); scope.Complete(); return result; } diff --git a/src/Umbraco.Infrastructure/Migrations/Notifications/DatabaseSchemaAndDataCreatedNotification.cs b/src/Umbraco.Infrastructure/Migrations/Notifications/DatabaseSchemaAndDataCreatedNotification.cs new file mode 100644 index 0000000000..77ef6aaaea --- /dev/null +++ b/src/Umbraco.Infrastructure/Migrations/Notifications/DatabaseSchemaAndDataCreatedNotification.cs @@ -0,0 +1,8 @@ +using Umbraco.Cms.Core.Notifications; + +namespace Umbraco.Cms.Infrastructure.Migrations.Notifications; + +public class DatabaseSchemaAndDataCreatedNotification : INotification +{ + +} diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs index ba9437a34d..141200f5f5 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs @@ -80,5 +80,6 @@ public class UmbracoPlan : MigrationPlan // To 12.1.0 To("{1187192D-EDB5-4619-955D-91D48D738871}"); + To("{47DE85CE-1E16-42A0-8AF6-3EC3BCEF5471}"); } } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_12_1_0/AddOpenIddict.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_12_1_0/AddOpenIddict.cs new file mode 100644 index 0000000000..3bf188deff --- /dev/null +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_12_1_0/AddOpenIddict.cs @@ -0,0 +1,20 @@ +using Umbraco.Cms.Persistence.EFCore.Migrations; + +namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_12_1_0; + +public class AddOpenIddict : UnscopedMigrationBase +{ + private readonly IEFCoreMigrationExecutor _iefCoreMigrationExecutor; + + public AddOpenIddict(IMigrationContext context, IEFCoreMigrationExecutor iefCoreMigrationExecutor) + : base(context) + { + _iefCoreMigrationExecutor = iefCoreMigrationExecutor; + } + + protected override void Migrate() + { + _iefCoreMigrationExecutor.ExecuteSingleMigrationAsync(EFCoreMigration.InitialCreate).GetAwaiter().GetResult(); + } +} + diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 4be13cb615..bc05a391cc 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -16,6 +16,12 @@ + + + all + + + true diff --git a/umbraco.sln b/umbraco.sln index f6bd2d1719..b06bf09586 100644 --- a/umbraco.sln +++ b/umbraco.sln @@ -153,6 +153,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Cms.Imaging.ImageSh EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Cms.Persistence.EFCore", "src\Umbraco.Cms.Persistence.EFCore\Umbraco.Cms.Persistence.EFCore.csproj", "{9046F56E-4AC3-4603-A6A3-3ACCF632997E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Cms.Persistence.EFCore.Sqlite", "src\Umbraco.Cms.Persistence.EFCore.Sqlite\Umbraco.Cms.Persistence.EFCore.Sqlite.csproj", "{8B4771F0-8EC2-4761-BBCE-DDE073DB3B7A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Cms.Persistence.EFCore.SqlServer", "src\Umbraco.Cms.Persistence.EFCore.SqlServer\Umbraco.Cms.Persistence.EFCore.SqlServer.csproj", "{9276C3F0-0DC9-46C9-BF32-9EE79D92AE02}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -311,6 +315,18 @@ Global {35E3DA10-5549-41DE-B7ED-CC29355BA9FD}.Release|Any CPU.Build.0 = Release|Any CPU {35E3DA10-5549-41DE-B7ED-CC29355BA9FD}.SkipTests|Any CPU.ActiveCfg = Debug|Any CPU {35E3DA10-5549-41DE-B7ED-CC29355BA9FD}.SkipTests|Any CPU.Build.0 = Debug|Any CPU + {8B4771F0-8EC2-4761-BBCE-DDE073DB3B7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8B4771F0-8EC2-4761-BBCE-DDE073DB3B7A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8B4771F0-8EC2-4761-BBCE-DDE073DB3B7A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8B4771F0-8EC2-4761-BBCE-DDE073DB3B7A}.Release|Any CPU.Build.0 = Release|Any CPU + {8B4771F0-8EC2-4761-BBCE-DDE073DB3B7A}.SkipTests|Any CPU.ActiveCfg = Debug|Any CPU + {8B4771F0-8EC2-4761-BBCE-DDE073DB3B7A}.SkipTests|Any CPU.Build.0 = Debug|Any CPU + {9276C3F0-0DC9-46C9-BF32-9EE79D92AE02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9276C3F0-0DC9-46C9-BF32-9EE79D92AE02}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9276C3F0-0DC9-46C9-BF32-9EE79D92AE02}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9276C3F0-0DC9-46C9-BF32-9EE79D92AE02}.Release|Any CPU.Build.0 = Release|Any CPU + {9276C3F0-0DC9-46C9-BF32-9EE79D92AE02}.SkipTests|Any CPU.ActiveCfg = Debug|Any CPU + {9276C3F0-0DC9-46C9-BF32-9EE79D92AE02}.SkipTests|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE