Merge remote-tracking branch 'origin/v12/dev' into v14/dev
# Conflicts: # src/Umbraco.Core/Services/ContentService.cs # src/Umbraco.Infrastructure/CompatibilitySuppressions.xml # src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs # src/Umbraco.Web.BackOffice/Controllers/MediaController.cs
This commit is contained in:
9
.github/README.md
vendored
9
.github/README.md
vendored
@@ -1,4 +1,11 @@
|
||||
# [Umbraco CMS](https://umbraco.com) · [](../LICENSE.md) [](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=75) [](CONTRIBUTING.md) [](https://twitter.com/intent/follow?screen_name=umbraco) [](https://discord.gg/umbraco) [](https://github.com/codespaces/new?hide_repo_select=true&ref=v11%2Fcontrib&repo=10601208&machine=basicLinux32gb&devcontainer_path=.devcontainer%2Fdevcontainer.json&location=WestEurope)
|
||||
# [Umbraco CMS](https://umbraco.com)
|
||||
|
||||
[](../LICENSE.md)
|
||||
[](CONTRIBUTING.md)
|
||||
[](https://twitter.com/intent/follow?screen_name=umbraco)
|
||||
[](https://discord.gg/umbraco)
|
||||
[](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=301)
|
||||
[](https://github.com/codespaces/new?hide_repo_select=true&ref=contrib&repo=10601208&machine=basicLinux32gb&devcontainer_path=.devcontainer%2Fdevcontainer.json&location=WestEurope)
|
||||
|
||||
Umbraco is the friendliest, most flexible and fastest growing ASP.NET CMS, and used by more than 500,000 websites worldwide. Our mission is to help you deliver delightful digital experiences by making Umbraco friendly, simpler and social.
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
<PackageReference Include="OpenIddict.AspNetCore" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Cms.Persistence.EFCore.Sqlite\Umbraco.Cms.Persistence.EFCore.Sqlite.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Cms.Persistence.EFCore.SqlServer\Umbraco.Cms.Persistence.EFCore.SqlServer.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Cms.Persistence.EFCore\Umbraco.Cms.Persistence.EFCore.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Web.Common\Umbraco.Web.Common.csproj" />
|
||||
|
||||
|
||||
@@ -58,7 +58,8 @@ public class ByRouteContentApiController : ContentApiItemControllerBase
|
||||
path = WebUtility.UrlDecode(path);
|
||||
}
|
||||
|
||||
path = path.EnsureStartsWith("/");
|
||||
path = path.TrimStart("/");
|
||||
path = path.Length == 0 ? "/" : path;
|
||||
|
||||
IPublishedContent? contentItem = GetContent(path);
|
||||
if (contentItem is not null)
|
||||
|
||||
@@ -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<ConfigureUmbracoDeliveryApiSwaggerGenOptions>();
|
||||
builder.AddUmbracoApiOpenApiUI();
|
||||
|
||||
builder.AddUmbracoEFCoreDbContext();
|
||||
builder
|
||||
.Services
|
||||
.AddControllers()
|
||||
@@ -47,3 +47,4 @@ public static class UmbracoBuilderExtensions
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JsonPatch.Net" Version="2.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.2" />
|
||||
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="4.4.0" />
|
||||
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="4.5.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -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<IMigrationProvider, SqlServerMigrationProvider>();
|
||||
builder.Services.AddSingleton<IMigrationProviderSetup, SqlServerMigrationProviderSetup>();
|
||||
}
|
||||
}
|
||||
266
src/Umbraco.Cms.Persistence.EFCore.SqlServer/Migrations/20230622184303_InitialCreate.Designer.cs
generated
Normal file
266
src/Umbraco.Cms.Persistence.EFCore.SqlServer/Migrations/20230622184303_InitialCreate.Designer.cs
generated
Normal file
@@ -0,0 +1,266 @@
|
||||
// <auto-generated />
|
||||
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
|
||||
{
|
||||
/// <inheritdoc />
|
||||
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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("ClientSecret")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("ConsentType")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DisplayNames")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Permissions")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PostLogoutRedirectUris")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("RedirectUris")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Requirements")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<DateTime?>("CreationDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Scopes")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("Subject")
|
||||
.HasMaxLength(400)
|
||||
.HasColumnType("nvarchar(400)");
|
||||
|
||||
b.Property<string>("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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Descriptions")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DisplayNames")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("AuthorizationId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<DateTime?>("CreationDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("ExpirationDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Payload")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("RedemptionDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("ReferenceId")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("Subject")
|
||||
.HasMaxLength(400)
|
||||
.HasColumnType("nvarchar(400)");
|
||||
|
||||
b.Property<string>("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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Umbraco.Cms.Persistence.EFCore.SqlServer.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitialCreate : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "umbracoOpenIddictApplications",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
ClientId = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||
ClientSecret = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
ConcurrencyToken = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
|
||||
ConsentType = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
|
||||
DisplayName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
DisplayNames = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Permissions = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
PostLogoutRedirectUris = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Properties = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
RedirectUris = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Requirements = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Type = table.Column<string>(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<string>(type: "nvarchar(450)", nullable: false),
|
||||
ConcurrencyToken = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
|
||||
Description = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Descriptions = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
DisplayName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
DisplayNames = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
|
||||
Properties = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Resources = table.Column<string>(type: "nvarchar(max)", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_umbracoOpenIddictScopes", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "umbracoOpenIddictAuthorizations",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
ApplicationId = table.Column<string>(type: "nvarchar(450)", nullable: true),
|
||||
ConcurrencyToken = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
|
||||
CreationDate = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
Properties = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Scopes = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Status = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
|
||||
Subject = table.Column<string>(type: "nvarchar(400)", maxLength: 400, nullable: true),
|
||||
Type = table.Column<string>(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<string>(type: "nvarchar(450)", nullable: false),
|
||||
ApplicationId = table.Column<string>(type: "nvarchar(450)", nullable: true),
|
||||
AuthorizationId = table.Column<string>(type: "nvarchar(450)", nullable: true),
|
||||
ConcurrencyToken = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
|
||||
CreationDate = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
ExpirationDate = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
Payload = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Properties = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
RedemptionDate = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
ReferenceId = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||
Status = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
|
||||
Subject = table.Column<string>(type: "nvarchar(400)", maxLength: 400, nullable: true),
|
||||
Type = table.Column<string>(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");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "umbracoOpenIddictScopes");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "umbracoOpenIddictTokens");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "umbracoOpenIddictAuthorizations");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "umbracoOpenIddictApplications");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
// <auto-generated />
|
||||
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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("ClientSecret")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("ConsentType")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DisplayNames")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Permissions")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PostLogoutRedirectUris")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("RedirectUris")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Requirements")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<DateTime?>("CreationDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Scopes")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("Subject")
|
||||
.HasMaxLength(400)
|
||||
.HasColumnType("nvarchar(400)");
|
||||
|
||||
b.Property<string>("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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Descriptions")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DisplayNames")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("AuthorizationId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<DateTime?>("CreationDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("ExpirationDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Payload")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("RedemptionDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("ReferenceId")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("Subject")
|
||||
.HasMaxLength(400)
|
||||
.HasColumnType("nvarchar(400)");
|
||||
|
||||
b.Property<string>("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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<UmbracoDbContext> _dbContextFactory;
|
||||
|
||||
public SqlServerMigrationProvider(IDbContextFactory<UmbracoDbContext> 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}")
|
||||
};
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Title>Umbraco CMS - EF Core - SqlServer migrations</Title>
|
||||
<!-- TODO: Enable when final version is shipped (because there's currently no previous version) -->
|
||||
<EnablePackageValidation>false</EnablePackageValidation>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Cms.Persistence.EFCore\Umbraco.Cms.Persistence.EFCore.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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<IMigrationProvider, SqliteMigrationProvider>();
|
||||
builder.Services.AddSingleton<IMigrationProviderSetup, SqliteMigrationProviderSetup>();
|
||||
}
|
||||
}
|
||||
258
src/Umbraco.Cms.Persistence.EFCore.Sqlite/Migrations/20230622183638_InitialCreate.Designer.cs
generated
Normal file
258
src/Umbraco.Cms.Persistence.EFCore.Sqlite/Migrations/20230622183638_InitialCreate.Designer.cs
generated
Normal file
@@ -0,0 +1,258 @@
|
||||
// <auto-generated />
|
||||
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
|
||||
{
|
||||
/// <inheritdoc />
|
||||
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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClientSecret")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConsentType")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DisplayNames")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Permissions")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PostLogoutRedirectUris")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RedirectUris")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Requirements")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("CreationDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Scopes")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Subject")
|
||||
.HasMaxLength(400)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Descriptions")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DisplayNames")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Resources")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Name")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("umbracoOpenIddictScopes", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AuthorizationId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("CreationDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("ExpirationDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Payload")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("RedemptionDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ReferenceId")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Subject")
|
||||
.HasMaxLength(400)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Umbraco.Cms.Persistence.EFCore.Sqlite.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitialCreate : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "umbracoOpenIddictApplications",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "TEXT", nullable: false),
|
||||
ClientId = table.Column<string>(type: "TEXT", maxLength: 100, nullable: true),
|
||||
ClientSecret = table.Column<string>(type: "TEXT", nullable: true),
|
||||
ConcurrencyToken = table.Column<string>(type: "TEXT", maxLength: 50, nullable: true),
|
||||
ConsentType = table.Column<string>(type: "TEXT", maxLength: 50, nullable: true),
|
||||
DisplayName = table.Column<string>(type: "TEXT", nullable: true),
|
||||
DisplayNames = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Permissions = table.Column<string>(type: "TEXT", nullable: true),
|
||||
PostLogoutRedirectUris = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Properties = table.Column<string>(type: "TEXT", nullable: true),
|
||||
RedirectUris = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Requirements = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Type = table.Column<string>(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<string>(type: "TEXT", nullable: false),
|
||||
ConcurrencyToken = table.Column<string>(type: "TEXT", maxLength: 50, nullable: true),
|
||||
Description = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Descriptions = table.Column<string>(type: "TEXT", nullable: true),
|
||||
DisplayName = table.Column<string>(type: "TEXT", nullable: true),
|
||||
DisplayNames = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Name = table.Column<string>(type: "TEXT", maxLength: 200, nullable: true),
|
||||
Properties = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Resources = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_umbracoOpenIddictScopes", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "umbracoOpenIddictAuthorizations",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "TEXT", nullable: false),
|
||||
ApplicationId = table.Column<string>(type: "TEXT", nullable: true),
|
||||
ConcurrencyToken = table.Column<string>(type: "TEXT", maxLength: 50, nullable: true),
|
||||
CreationDate = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
Properties = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Scopes = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Status = table.Column<string>(type: "TEXT", maxLength: 50, nullable: true),
|
||||
Subject = table.Column<string>(type: "TEXT", maxLength: 400, nullable: true),
|
||||
Type = table.Column<string>(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<string>(type: "TEXT", nullable: false),
|
||||
ApplicationId = table.Column<string>(type: "TEXT", nullable: true),
|
||||
AuthorizationId = table.Column<string>(type: "TEXT", nullable: true),
|
||||
ConcurrencyToken = table.Column<string>(type: "TEXT", maxLength: 50, nullable: true),
|
||||
CreationDate = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
ExpirationDate = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
Payload = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Properties = table.Column<string>(type: "TEXT", nullable: true),
|
||||
RedemptionDate = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
ReferenceId = table.Column<string>(type: "TEXT", maxLength: 100, nullable: true),
|
||||
Status = table.Column<string>(type: "TEXT", maxLength: 50, nullable: true),
|
||||
Subject = table.Column<string>(type: "TEXT", maxLength: 400, nullable: true),
|
||||
Type = table.Column<string>(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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "umbracoOpenIddictScopes");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "umbracoOpenIddictTokens");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "umbracoOpenIddictAuthorizations");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "umbracoOpenIddictApplications");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
// <auto-generated />
|
||||
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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClientSecret")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConsentType")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DisplayNames")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Permissions")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PostLogoutRedirectUris")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RedirectUris")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Requirements")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("CreationDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Scopes")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Subject")
|
||||
.HasMaxLength(400)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("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<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Descriptions")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DisplayNames")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Resources")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Name")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("umbracoOpenIddictScopes", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AuthorizationId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("CreationDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("ExpirationDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Payload")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("RedemptionDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ReferenceId")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Subject")
|
||||
.HasMaxLength(400)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<UmbracoDbContext> _dbContextFactory;
|
||||
|
||||
public SqliteMigrationProvider(IDbContextFactory<UmbracoDbContext> 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}")
|
||||
};
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Title>Umbraco CMS - EF Core - Sqlite migrations</Title>
|
||||
<!-- TODO: Enable when final version is shipped (because there's currently no previous version) -->
|
||||
<EnablePackageValidation>false</EnablePackageValidation>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Cms.Persistence.EFCore\Umbraco.Cms.Persistence.EFCore.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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<IEFCoreMigrationExecutor, EfCoreMigrationExecutor>();
|
||||
|
||||
builder.AddNotificationAsyncHandler<DatabaseSchemaAndDataCreatedNotification, EFCoreCreateTablesNotificationHandler>();
|
||||
builder.AddNotificationAsyncHandler<UnattendedInstallNotification, EFCoreCreateTablesNotificationHandler>();
|
||||
builder.Services.AddOpenIddict()
|
||||
|
||||
// Register the OpenIddict core components.
|
||||
.AddCore(options =>
|
||||
{
|
||||
options
|
||||
.UseEntityFrameworkCore()
|
||||
.UseDbContext<UmbracoDbContext>();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class EFCoreCreateTablesNotificationHandler : INotificationAsyncHandler<DatabaseSchemaAndDataCreatedNotification>, INotificationAsyncHandler<UnattendedInstallNotification>
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -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<IMigrationProvider> _migrationProviders;
|
||||
private readonly IOptions<ConnectionStrings> _options;
|
||||
|
||||
// We need to do migrations out side of a scope due to sqlite
|
||||
public EfCoreMigrationExecutor(
|
||||
IEnumerable<IMigrationProvider> migrationProviders,
|
||||
IOptions<ConnectionStrings> 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<UmbracoDbContext>((options, connectionString, providerName) =>
|
||||
{
|
||||
// Register the entity sets needed by OpenIddict.
|
||||
options.UseOpenIddict();
|
||||
});
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -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<MigrationAttribute>(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<IMigrator>().MigrateAsync(targetMigrationId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<T>(this IServiceCollection services, DefaultEFCoreOptionsAction? defaultEFCoreOptionsAction = null)
|
||||
where T : DbContext
|
||||
{
|
||||
defaultEFCoreOptionsAction ??= DefaultOptionsAction;
|
||||
|
||||
services.AddDbContext<T>(
|
||||
(provider, builder) => SetupDbContext(defaultEFCoreOptionsAction, provider, builder),
|
||||
optionsLifetime: ServiceLifetime.Transient);
|
||||
|
||||
|
||||
|
||||
services.AddDbContextFactory<T>((provider, builder) => SetupDbContext(defaultEFCoreOptionsAction, provider, builder));
|
||||
|
||||
services.AddUnique<IAmbientEFCoreScopeStack<T>, AmbientEFCoreScopeStack<T>>();
|
||||
services.AddUnique<IEFCoreScopeAccessor<T>, EFCoreScopeAccessor<T>>();
|
||||
services.AddUnique<IEFCoreScopeProvider<T>, EFCoreScopeProvider<T>>();
|
||||
services.AddSingleton<IDistributedLockingMechanism, SqliteEFCoreDistributedLockingMechanism<T>>();
|
||||
services.AddSingleton<IDistributedLockingMechanism, SqlServerEFCoreDistributedLockingMechanism<T>>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static void SetupDbContext(DefaultEFCoreOptionsAction defaultEFCoreOptionsAction, IServiceProvider provider, DbContextOptionsBuilder builder)
|
||||
{
|
||||
ConnectionStrings connectionStrings = GetConnectionStringAndProviderName(provider);
|
||||
IEnumerable<IMigrationProviderSetup> migrationProviders = provider.GetServices<IMigrationProviderSetup>();
|
||||
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<IOptionsMonitor<ConnectionStrings>>().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<T>(this IServiceCollection services, string connectionString, string providerName, DefaultEFCoreOptionsAction? defaultEFCoreOptionsAction = null)
|
||||
where T : DbContext
|
||||
{
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Cms.Persistence.EFCore.Migrations;
|
||||
|
||||
public interface IMigrationProvider
|
||||
{
|
||||
string ProviderName { get; }
|
||||
|
||||
Task MigrateAsync(EFCoreMigration migration);
|
||||
|
||||
Task MigrateAllAsync();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -8,7 +8,6 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.7" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.7" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.7" />
|
||||
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
33
src/Umbraco.Cms.Persistence.EFCore/UmbracoDbContext.cs
Normal file
33
src/Umbraco.Cms.Persistence.EFCore/UmbracoDbContext.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Persistence.EFCore;
|
||||
|
||||
/// <remarks>
|
||||
/// 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
|
||||
/// </remarks>
|
||||
public class UmbracoDbContext : DbContext
|
||||
{
|
||||
public UmbracoDbContext(DbContextOptions<UmbracoDbContext> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,6 @@ public sealed class ApiContentBuilder : ApiContentBuilderBase<IApiContent>, IApi
|
||||
{
|
||||
}
|
||||
|
||||
protected override IApiContent Create(IPublishedContent content, Guid id, string name, string contentType, IApiContentRoute route, IDictionary<string, object?> properties)
|
||||
=> new ApiContent(id, name, contentType, route, properties);
|
||||
protected override IApiContent Create(IPublishedContent content, string name, IApiContentRoute route, IDictionary<string, object?> properties)
|
||||
=> new ApiContent(content.Key, name, content.ContentType.Alias, content.CreateDate, content.UpdateDate, route, properties);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public abstract class ApiContentBuilderBase<T>
|
||||
_outputExpansionStrategyAccessor = outputExpansionStrategyAccessor;
|
||||
}
|
||||
|
||||
protected abstract T Create(IPublishedContent content, Guid id, string name, string contentType, IApiContentRoute route, IDictionary<string, object?> properties);
|
||||
protected abstract T Create(IPublishedContent content, string name, IApiContentRoute route, IDictionary<string, object?> properties);
|
||||
|
||||
public virtual T? Build(IPublishedContent content)
|
||||
{
|
||||
@@ -34,9 +34,7 @@ public abstract class ApiContentBuilderBase<T>
|
||||
|
||||
return Create(
|
||||
content,
|
||||
content.Key,
|
||||
_apiContentNameProvider.GetName(content),
|
||||
content.ContentType.Alias,
|
||||
route,
|
||||
properties);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public sealed class ApiContentResponseBuilder : ApiContentBuilderBase<IApiConten
|
||||
: base(apiContentNameProvider, apiContentRouteBuilder, outputExpansionStrategyAccessor)
|
||||
=> _apiContentRouteBuilder = apiContentRouteBuilder;
|
||||
|
||||
protected override IApiContentResponse Create(IPublishedContent content, Guid id, string name, string contentType, IApiContentRoute route, IDictionary<string, object?> properties)
|
||||
protected override IApiContentResponse Create(IPublishedContent content, string name, IApiContentRoute route, IDictionary<string, object?> properties)
|
||||
{
|
||||
var routesByCulture = new Dictionary<string, IApiContentRoute>();
|
||||
|
||||
@@ -35,6 +35,6 @@ public sealed class ApiContentResponseBuilder : ApiContentBuilderBase<IApiConten
|
||||
routesByCulture[publishedCultureInfo.Culture] = cultureRoute;
|
||||
}
|
||||
|
||||
return new ApiContentResponse(id, name, contentType, route, properties, routesByCulture);
|
||||
return new ApiContentResponse(content.Key, name, content.ContentType.Alias, content.CreateDate, content.UpdateDate, route, properties, routesByCulture);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<key alias="setPermissions">Sæt rettigheder</key>
|
||||
<key alias="unlock">Lås op</key>
|
||||
<key alias="createblueprint">Opret indholdsskabelon</key>
|
||||
<key alias="resendInvite">Gensend Invitation</key>
|
||||
<key alias="resendInvite">Gensend invitation</key>
|
||||
<key alias="defaultValue">Standardværdi</key>
|
||||
</area>
|
||||
<area alias="actionCategories">
|
||||
|
||||
@@ -2059,7 +2059,7 @@
|
||||
<key alias="usergroup">Benutzergruppe</key>
|
||||
<key alias="userInvited">wurde eingeladen</key>
|
||||
<key alias="userInvitedSuccessHelp">Eine Einladung mit Anweisungen zur Anmeldung im Umbraco-Back-Office wurde dem neuen Benutzer zugeschickt.</key>
|
||||
<key alias="userinviteWelcomeMessage">Hallo und Willkommen bei Umbraco! In nur einer Minute sind Sie bereit loszulegen, Sie müssen nur ein Kennwort festlegen und optinal Ihrem Avatar ein Bild hinzufügen.</key>
|
||||
<key alias="userinviteWelcomeMessage">Hallo und Willkommen bei Umbraco! In nur einer Minute sind Sie bereit loszulegen, Sie müssen nur ein Kennwort festlegen und optional Ihrem Avatar ein Bild hinzufügen.</key>
|
||||
<key alias="userinviteExpiredMessage">Willkommen bei Umbraco! Bedauerlicherweise ist Ihre Einladung verfallen. Bitte kontaktieren Sie Ihren Administrator und bitten Sie ihn, diese erneut zu schicken.</key>
|
||||
<key alias="userinviteAvatarMessage">Laden Sie ein Foto von sich hoch, um es anderen Benutzern zu erleichtern, sie zu erkennen. Klicken Sie auf den Kreis oben, um Ihr Foto hochzuladen.</key>
|
||||
<key alias="writer">Autor</key>
|
||||
|
||||
@@ -488,7 +488,7 @@
|
||||
<key alias="insertlink">Insert link</key>
|
||||
<key alias="insertMacro">Click to add a Macro</key>
|
||||
<key alias="inserttable">Insert table</key>
|
||||
<key alias="languagedeletewarning">This will delete the language</key>
|
||||
<key alias="languagedeletewarning">This will delete the language and all content related to the language</key>
|
||||
<key alias="languageChangeWarning">Changing the culture for a language may be an expensive operation and will result
|
||||
in the content cache and indexes being rebuilt
|
||||
</key>
|
||||
@@ -2275,7 +2275,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
|
||||
<key alias="items">items</key>
|
||||
<key alias="urls">URL(s)</key>
|
||||
<key alias="urlsSelected">URL(s) selected</key>
|
||||
<key alias="itemsSelected">items selected</key>
|
||||
<key alias="itemsSelected">item(s) selected</key>
|
||||
<key alias="invalidDate">Invalid date</key>
|
||||
<key alias="invalidNumber">Not a number</key>
|
||||
<key alias="invalidNumberStepSize">Not a valid numeric step size</key>
|
||||
|
||||
@@ -503,7 +503,7 @@
|
||||
<key alias="insertlink">Insert link</key>
|
||||
<key alias="insertMacro">Click to add a Macro</key>
|
||||
<key alias="inserttable">Insert table</key>
|
||||
<key alias="languagedeletewarning">This will delete the language</key>
|
||||
<key alias="languagedeletewarning">This will delete the language and all content related to the language</key>
|
||||
<key alias="languageChangeWarning">Changing the culture for a language may be an expensive operation and will result
|
||||
in the content cache and indexes being rebuilt
|
||||
</key>
|
||||
@@ -2371,7 +2371,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
|
||||
<key alias="items">items</key>
|
||||
<key alias="urls">URL(s)</key>
|
||||
<key alias="urlsSelected">URL(s) selected</key>
|
||||
<key alias="itemsSelected">items selected</key>
|
||||
<key alias="itemsSelected">item(s) selected</key>
|
||||
<key alias="invalidDate">Invalid date</key>
|
||||
<key alias="invalidNumber">Not a number</key>
|
||||
<key alias="invalidNumberStepSize">Not a valid numeric step size</key>
|
||||
|
||||
2829
src/Umbraco.Core/EmbeddedResources/Lang/hr.xml
Normal file
2829
src/Umbraco.Core/EmbeddedResources/Lang/hr.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,14 +2,20 @@ namespace Umbraco.Cms.Core.Models.DeliveryApi;
|
||||
|
||||
public class ApiContent : ApiElement, IApiContent
|
||||
{
|
||||
public ApiContent(Guid id, string name, string contentType, IApiContentRoute route, IDictionary<string, object?> properties)
|
||||
public ApiContent(Guid id, string name, string contentType, DateTime createDate, DateTime updateDate, IApiContentRoute route, IDictionary<string, object?> properties)
|
||||
: base(id, contentType, properties)
|
||||
{
|
||||
Name = name;
|
||||
CreateDate = createDate;
|
||||
UpdateDate = updateDate;
|
||||
Route = route;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public DateTime CreateDate { get; }
|
||||
|
||||
public DateTime UpdateDate { get; }
|
||||
|
||||
public IApiContentRoute Route { get; }
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ namespace Umbraco.Cms.Core.Models.DeliveryApi;
|
||||
|
||||
public class ApiContentResponse : ApiContent, IApiContentResponse
|
||||
{
|
||||
public ApiContentResponse(Guid id, string name, string contentType, IApiContentRoute route, IDictionary<string, object?> properties, IDictionary<string, IApiContentRoute> cultures)
|
||||
: base(id, name, contentType, route, properties)
|
||||
public ApiContentResponse(Guid id, string name, string contentType, DateTime createDate, DateTime updateDate, IApiContentRoute route, IDictionary<string, object?> properties, IDictionary<string, IApiContentRoute> cultures)
|
||||
: base(id, name, contentType, createDate, updateDate, route, properties)
|
||||
=> Cultures = cultures;
|
||||
|
||||
// a little DX; by default this dictionary will be serialized as the first part of the response due to the inner workings of the serializer.
|
||||
|
||||
@@ -4,5 +4,9 @@ public interface IApiContent : IApiElement
|
||||
{
|
||||
string? Name { get; }
|
||||
|
||||
public DateTime CreateDate { get; }
|
||||
|
||||
public DateTime UpdateDate { get; }
|
||||
|
||||
IApiContentRoute Route { get; }
|
||||
}
|
||||
|
||||
@@ -2587,7 +2587,8 @@ public class ContentService : RepositoryService, IContentService
|
||||
IContent[] contents = _documentRepository.Get(query).ToArray();
|
||||
|
||||
var emptyingRecycleBinNotification = new ContentEmptyingRecycleBinNotification(contents, eventMessages);
|
||||
if (scope.Notifications.PublishCancelable(emptyingRecycleBinNotification))
|
||||
var deletingContentNotification = new ContentDeletingNotification(contents, eventMessages);
|
||||
if (scope.Notifications.PublishCancelable(emptyingRecycleBinNotification) || scope.Notifications.PublishCancelable(deletingContentNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return OperationResult.Cancel(eventMessages);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -16,7 +16,8 @@ public static class ContentServiceExtensions
|
||||
{
|
||||
#region RTE Anchor values
|
||||
|
||||
private static readonly Regex AnchorRegex = new("<a id=\"(.*?)\">", RegexOptions.Compiled);
|
||||
private static readonly Regex AnchorRegex = new(@"<a id=\\*""(.*?)\\*"">", RegexOptions.Compiled);
|
||||
private static readonly string[] _propertyTypesWithRte = new[] { Constants.PropertyEditors.Aliases.TinyMce, Constants.PropertyEditors.Aliases.BlockList, Constants.PropertyEditors.Aliases.BlockGrid };
|
||||
|
||||
public static IEnumerable<IContent>? GetByIds(this IContentService contentService, IEnumerable<Udi> ids)
|
||||
{
|
||||
@@ -67,14 +68,17 @@ public static class ContentServiceExtensions
|
||||
public static IEnumerable<string> GetAnchorValuesFromRTEs(this IContentService contentService, int id, string? culture = "*")
|
||||
{
|
||||
var result = new List<string>();
|
||||
|
||||
culture = culture is not "*" ? culture : null;
|
||||
|
||||
IContent? content = contentService.GetById(id);
|
||||
|
||||
if (content is not null)
|
||||
if (content is null)
|
||||
{
|
||||
foreach (IProperty contentProperty in content.Properties)
|
||||
{
|
||||
if (contentProperty.PropertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases
|
||||
.TinyMce))
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (IProperty contentProperty in content.Properties.Where(s => _propertyTypesWithRte.Contains(s.PropertyType.PropertyEditorAlias)))
|
||||
{
|
||||
var value = contentProperty.GetValue(culture)?.ToString();
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
@@ -82,8 +86,6 @@ public static class ContentServiceExtensions
|
||||
result.AddRange(contentService.GetAnchorValuesFromRTEContent(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -96,7 +98,7 @@ public static class ContentServiceExtensions
|
||||
MatchCollection matches = AnchorRegex.Matches(rteContent);
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
result.Add(match.Value.Split(Constants.CharArrays.DoubleQuote)[1]);
|
||||
result.Add(match.Groups[1].Value);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -41,6 +41,7 @@ public class UmbracoContentIndex : UmbracoExamineIndex, IUmbracoContentIndex
|
||||
if (namedOptions.Validator is IContentValueSetValidator contentValueSetValidator)
|
||||
{
|
||||
PublishedValuesOnly = contentValueSetValidator.PublishedValuesOnly;
|
||||
SupportProtectedContent = contentValueSetValidator.SupportProtectedContent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ public abstract class UmbracoExamineIndex : LuceneIndex, IUmbracoIndex, IIndexDi
|
||||
|
||||
public bool PublishedValuesOnly { get; protected set; } = false;
|
||||
|
||||
public bool SupportProtectedContent { get; protected set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// override to check if we can actually initialize.
|
||||
/// </summary>
|
||||
|
||||
@@ -337,4 +337,18 @@
|
||||
<Right>lib/net7.0/Umbraco.Infrastructure.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0006</DiagnosticId>
|
||||
<Target>M:Umbraco.Cms.Infrastructure.Search.IUmbracoIndexingHandler.RemoveProtectedContent</Target>
|
||||
<Left>lib/net7.0/Umbraco.Infrastructure.dll</Left>
|
||||
<Right>lib/net7.0/Umbraco.Infrastructure.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0006</DiagnosticId>
|
||||
<Target>P:Umbraco.Cms.Infrastructure.Examine.IUmbracoIndex.SupportProtectedContent</Target>
|
||||
<Left>lib/net7.0/Umbraco.Infrastructure.dll</Left>
|
||||
<Right>lib/net7.0/Umbraco.Infrastructure.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
</Suppressions>
|
||||
@@ -59,6 +59,7 @@ public static partial class UmbracoBuilderExtensions
|
||||
builder.Services.AddSingleton<ExamineIndexRebuilder>();
|
||||
|
||||
builder.AddNotificationHandler<ContentCacheRefresherNotification, ContentIndexingNotificationHandler>();
|
||||
builder.AddNotificationHandler<PublicAccessCacheRefresherNotification, ContentIndexingNotificationHandler>();
|
||||
builder.AddNotificationHandler<ContentTypeCacheRefresherNotification, ContentTypeIndexingNotificationHandler>();
|
||||
builder.AddNotificationHandler<ContentCacheRefresherNotification, DeliveryApiContentIndexingNotificationHandler>();
|
||||
builder.AddNotificationHandler<ContentTypeCacheRefresherNotification, DeliveryApiContentIndexingNotificationHandler>();
|
||||
|
||||
@@ -41,6 +41,7 @@ public class ContentValueSetValidator : ValueSetValidator, IContentValueSetValid
|
||||
_scopeProvider = scopeProvider;
|
||||
}
|
||||
|
||||
[Obsolete("This constructor is obsolete, the IScopeProvider will change to Infrastructure.Scoping.ScopeProvider instead, this will be removed in Umbraco 14.")]
|
||||
public ContentValueSetValidator(
|
||||
bool publishedValuesOnly,
|
||||
bool supportProtectedContent,
|
||||
|
||||
@@ -4,6 +4,7 @@ using Examine.Search;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.HostedServices;
|
||||
using Umbraco.Cms.Infrastructure.Search;
|
||||
using Umbraco.Extensions;
|
||||
@@ -25,6 +26,7 @@ internal class ExamineUmbracoIndexingHandler : IUmbracoIndexingHandler
|
||||
private readonly IPublishedContentValueSetBuilder _publishedContentValueSetBuilder;
|
||||
private readonly ICoreScopeProvider _scopeProvider;
|
||||
private readonly ExamineIndexingMainDomHandler _mainDomHandler;
|
||||
private readonly IPublicAccessService _publicAccessService;
|
||||
|
||||
public ExamineUmbracoIndexingHandler(
|
||||
ILogger<ExamineUmbracoIndexingHandler> logger,
|
||||
@@ -35,7 +37,8 @@ internal class ExamineUmbracoIndexingHandler : IUmbracoIndexingHandler
|
||||
IPublishedContentValueSetBuilder publishedContentValueSetBuilder,
|
||||
IValueSetBuilder<IMedia> mediaValueSetBuilder,
|
||||
IValueSetBuilder<IMember> memberValueSetBuilder,
|
||||
ExamineIndexingMainDomHandler mainDomHandler)
|
||||
ExamineIndexingMainDomHandler mainDomHandler,
|
||||
IPublicAccessService publicAccessService)
|
||||
{
|
||||
_logger = logger;
|
||||
_scopeProvider = scopeProvider;
|
||||
@@ -46,6 +49,7 @@ internal class ExamineUmbracoIndexingHandler : IUmbracoIndexingHandler
|
||||
_mediaValueSetBuilder = mediaValueSetBuilder;
|
||||
_memberValueSetBuilder = memberValueSetBuilder;
|
||||
_mainDomHandler = mainDomHandler;
|
||||
_publicAccessService = publicAccessService;
|
||||
_enabled = new Lazy<bool>(IsEnabled);
|
||||
}
|
||||
|
||||
@@ -122,6 +126,20 @@ internal class ExamineUmbracoIndexingHandler : IUmbracoIndexingHandler
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RemoveProtectedContent()
|
||||
{
|
||||
var actions = DeferredActions.Get(_scopeProvider);
|
||||
if (actions != null)
|
||||
{
|
||||
actions.Add(new DeferredRemoveProtectedContent(_backgroundTaskQueue, this, _publicAccessService));
|
||||
}
|
||||
else
|
||||
{
|
||||
DeferredRemoveProtectedContent.Execute(_backgroundTaskQueue, this, _publicAccessService);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DeleteDocumentsForContentTypes(IReadOnlyCollection<int> removedContentTypes)
|
||||
{
|
||||
@@ -391,5 +409,50 @@ internal class ExamineUmbracoIndexingHandler : IUmbracoIndexingHandler
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all protected content from applicable indexes on a background thread
|
||||
/// </summary>
|
||||
private class DeferredRemoveProtectedContent : IDeferredAction
|
||||
{
|
||||
private readonly IBackgroundTaskQueue _backgroundTaskQueue;
|
||||
private readonly ExamineUmbracoIndexingHandler _examineUmbracoIndexingHandler;
|
||||
private readonly IPublicAccessService _publicAccessService;
|
||||
|
||||
public DeferredRemoveProtectedContent(IBackgroundTaskQueue backgroundTaskQueue, ExamineUmbracoIndexingHandler examineUmbracoIndexingHandler, IPublicAccessService publicAccessService)
|
||||
{
|
||||
_backgroundTaskQueue = backgroundTaskQueue;
|
||||
_examineUmbracoIndexingHandler = examineUmbracoIndexingHandler;
|
||||
_publicAccessService = publicAccessService;
|
||||
}
|
||||
|
||||
public void Execute() => Execute(_backgroundTaskQueue, _examineUmbracoIndexingHandler, _publicAccessService);
|
||||
|
||||
public static void Execute(IBackgroundTaskQueue backgroundTaskQueue, ExamineUmbracoIndexingHandler examineUmbracoIndexingHandler, IPublicAccessService publicAccessService)
|
||||
=> backgroundTaskQueue.QueueBackgroundWorkItem(cancellationToken =>
|
||||
{
|
||||
using ICoreScope scope = examineUmbracoIndexingHandler._scopeProvider.CreateCoreScope(autoComplete: true);
|
||||
|
||||
var protectedContentIds = publicAccessService.GetAll().Select(entry => entry.ProtectedNodeId).ToArray();
|
||||
if (protectedContentIds.Any() is false)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
foreach (IUmbracoContentIndex index in examineUmbracoIndexingHandler._examineManager.Indexes
|
||||
.OfType<IUmbracoContentIndex>()
|
||||
.Where(x => x is { EnableDefaultEventHandler: true, SupportProtectedContent: false }))
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
index.DeleteFromIndex(protectedContentIds.Select(id => id.ToString()));
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -21,4 +21,12 @@ public interface IUmbracoIndex : IIndex, IIndexStats
|
||||
/// * non-published Variants
|
||||
/// </remarks>
|
||||
bool PublishedValuesOnly { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the index can contain protected content
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To retain backwards compatability, the default value is true
|
||||
/// </remarks>
|
||||
bool SupportProtectedContent { get; }
|
||||
}
|
||||
|
||||
6
src/Umbraco.Infrastructure/Migrations/EFCoreMigration.cs
Normal file
6
src/Umbraco.Infrastructure/Migrations/EFCoreMigration.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Umbraco.Cms.Persistence.EFCore.Migrations;
|
||||
|
||||
public enum EFCoreMigration
|
||||
{
|
||||
InitialCreate = 0
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Umbraco.Cms.Persistence.EFCore.Migrations;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Migrations;
|
||||
|
||||
public interface IEFCoreMigrationExecutor
|
||||
{
|
||||
Task ExecuteSingleMigrationAsync(EFCoreMigration efCoreMigration);
|
||||
|
||||
Task ExecuteAllMigrationsAsync();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Migrations.Notifications;
|
||||
|
||||
public class DatabaseSchemaAndDataCreatedNotification : INotification
|
||||
{
|
||||
|
||||
}
|
||||
@@ -80,6 +80,7 @@ public class UmbracoPlan : MigrationPlan
|
||||
|
||||
// To 12.1.0
|
||||
To<V_12_1_0.TablesIndexesImprovement>("{1187192D-EDB5-4619-955D-91D48D738871}");
|
||||
To<V_12_1_0.AddOpenIddict>("{47DE85CE-1E16-42A0-8AF6-3EC3BCEF5471}");
|
||||
|
||||
// To 14.0.0
|
||||
To<V_13_0_0.AddPropertyEditorUiAliasColumn>("{419827A0-4FCE-464B-A8F3-247C6092AF55}");
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,6 @@ public class MarkdownEditorValueConverter : PropertyValueConverterBase, IDeliver
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var mark = new Markdown();
|
||||
return mark.Transform(markdownString);
|
||||
return markdownString;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,11 @@ public interface IUmbracoIndexingHandler
|
||||
|
||||
void ReIndexForMedia(IMedia sender, bool isPublished);
|
||||
|
||||
/// <summary>
|
||||
/// Removes any content that is flagged as protected
|
||||
/// </summary>
|
||||
void RemoveProtectedContent();
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all documents for the content type Ids
|
||||
/// </summary>
|
||||
|
||||
@@ -9,7 +9,9 @@ using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Search;
|
||||
|
||||
public sealed class ContentIndexingNotificationHandler : INotificationHandler<ContentCacheRefresherNotification>
|
||||
public sealed class ContentIndexingNotificationHandler :
|
||||
INotificationHandler<ContentCacheRefresherNotification>,
|
||||
INotificationHandler<PublicAccessCacheRefresherNotification>
|
||||
{
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IUmbracoIndexingHandler _umbracoIndexingHandler;
|
||||
@@ -158,4 +160,7 @@ public sealed class ContentIndexingNotificationHandler : INotificationHandler<Co
|
||||
_umbracoIndexingHandler.DeleteIndexForEntities(deleteBatch, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(PublicAccessCacheRefresherNotification notification)
|
||||
=> _umbracoIndexingHandler.RemoveProtectedContent();
|
||||
}
|
||||
|
||||
@@ -109,9 +109,9 @@ public class NuCacheContentRepository : RepositoryBase, INuCacheContentRepositor
|
||||
| ContentCacheDataSerializerEntityType.Member);
|
||||
|
||||
// If contentTypeIds, mediaTypeIds and memberTypeIds are null, truncate table as all records will be deleted (as these 3 are the only types in the table).
|
||||
if ((contentTypeIds == null || !contentTypeIds.Any())
|
||||
&& (mediaTypeIds == null || !mediaTypeIds.Any())
|
||||
&& (memberTypeIds == null || !memberTypeIds.Any()))
|
||||
if (contentTypeIds != null && !contentTypeIds.Any()
|
||||
&& mediaTypeIds != null && !mediaTypeIds.Any()
|
||||
&& memberTypeIds != null && !memberTypeIds.Any())
|
||||
{
|
||||
if (Database.DatabaseType == DatabaseType.SqlServer2012)
|
||||
{
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
{
|
||||
"element": "#dialog [data-element='action-documentType']",
|
||||
"title": "Create Document Type",
|
||||
"content": "<p>Click <b>Document Type</b> to create a new document type with a template. The template will be automatically created and set as the default template for this Document Type.</p><p>You will use the template in a later tour to render content.</p>",
|
||||
"content": "<p>Click <b>Document Type with Template</b> to create a new document type with a template. The template will be automatically created and set as the default template for this Document Type.</p><p>You will use the template in a later tour to render content.</p>",
|
||||
"event": "click"
|
||||
},
|
||||
{
|
||||
@@ -197,8 +197,8 @@
|
||||
},
|
||||
{
|
||||
"element": "[data-element~='editor-property-settings'] [data-element='editor-add']",
|
||||
"title": "Add editor",
|
||||
"content": "When you add an editor you choose what the input method for this property will be. Click <b>Add editor</b> to open the editor picker dialog.",
|
||||
"title": "Select editor",
|
||||
"content": "When you select an editor you choose what the input method for this property will be. Click <b>Select editor</b> to open the editor picker dialog.",
|
||||
"event": "click"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using HeyRed.MarkdownSharp;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Actions;
|
||||
@@ -303,6 +305,51 @@ internal class ContentMapDefinition : IMapDefinition
|
||||
{
|
||||
Properties = context.MapEnumerable<IProperty, ContentPropertyDto>(source.Properties).WhereNotNull()
|
||||
};
|
||||
var markdown = new Markdown();
|
||||
var linkCheck = new Regex("<a[^>]+>", RegexOptions.IgnoreCase);
|
||||
var evaluator = new MatchEvaluator(AddRelNoReferrer);
|
||||
foreach (TVariant variant in target.Variants)
|
||||
{
|
||||
foreach (Tab<ContentPropertyDisplay> tab in variant.Tabs)
|
||||
{
|
||||
if (tab.Properties == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (ContentPropertyDisplay property in tab.Properties)
|
||||
{
|
||||
if (string.IsNullOrEmpty(property.Description))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var description = markdown.Transform(property.Description);
|
||||
property.Description = linkCheck.Replace(description, evaluator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string AddRelNoReferrer(Match m)
|
||||
{
|
||||
string result = m.Value;
|
||||
if (!result.Contains("rel=", StringComparison.Ordinal))
|
||||
{
|
||||
result = result.Replace(">", " rel=\"noreferrer\">");
|
||||
}
|
||||
|
||||
if (!result.Contains("class=", StringComparison.Ordinal))
|
||||
{
|
||||
result = result.Replace(">", " class=\"underline\">");
|
||||
}
|
||||
|
||||
if (!result.Contains("target=", StringComparison.Ordinal))
|
||||
{
|
||||
result = result.Replace(">", " target=\"_blank\">");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll -Segment -Language -DisplayName
|
||||
|
||||
@@ -8,7 +8,7 @@ using Umbraco.Cms.Core.Configuration.Models;
|
||||
namespace Umbraco.Cms.Web.BackOffice.Security;
|
||||
|
||||
/// <summary>
|
||||
/// Antiforgery implementation for the Umbraco back office
|
||||
/// Anti-forgery implementation for the Umbraco back office
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a wrapper around the global/default <see cref="IAntiforgery" /> .net service. Because this service is a
|
||||
@@ -33,14 +33,12 @@ public class BackOfficeAntiforgery : IBackOfficeAntiforgery
|
||||
{
|
||||
x.HeaderName = Constants.Web.AngularHeadername;
|
||||
x.Cookie.Name = Constants.Web.CsrfValidationCookieName;
|
||||
x.Cookie.SecurePolicy = globalSettings.CurrentValue.UseHttps ? CookieSecurePolicy.Always : CookieSecurePolicy.SameAsRequest;
|
||||
});
|
||||
ServiceProvider container = services.BuildServiceProvider();
|
||||
_internalAntiForgery = container.GetRequiredService<IAntiforgery>();
|
||||
_globalSettings = globalSettings.CurrentValue;
|
||||
globalSettings.OnChange(x =>
|
||||
{
|
||||
_globalSettings = x;
|
||||
});
|
||||
globalSettings.OnChange(x => _globalSettings = x);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Markdown" Version="2.2.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Buffers;
|
||||
using System.Globalization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -42,7 +43,7 @@ public sealed class JsonDateTimeFormatAttribute : TypeFilterAttribute
|
||||
{
|
||||
var serializerSettings = new JsonSerializerSettings();
|
||||
serializerSettings.Converters.Add(
|
||||
new IsoDateTimeConverter { DateTimeFormat = _format });
|
||||
new IsoDateTimeConverter { DateTimeFormat = _format, Culture = CultureInfo.InvariantCulture });
|
||||
objectResult.Formatters.Clear();
|
||||
objectResult.Formatters.Add(
|
||||
new AngularJsonMediaTypeFormatter(serializerSettings, _arrayPool, _options));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// needs Markdown.Converter.js at the moment
|
||||
// needs Markdown.Converter.js at the moment
|
||||
|
||||
(function () {
|
||||
|
||||
@@ -1590,7 +1590,7 @@
|
||||
};
|
||||
|
||||
// takes the line as entered into the add link/as image dialog and makes
|
||||
// sure the URL and the optinal title are "nice".
|
||||
// sure the URL and the optional title are "nice".
|
||||
function properlyEncoded(linkdef) {
|
||||
return linkdef.replace(/^\s*(.*?)(?:\s+"(.+)")?\s*$/, function (wholematch, link, title) {
|
||||
link = link.replace(/\?.*$/, function (querypart) {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 232 KiB |
BIN
src/Umbraco.Web.UI.Client/src/assets/img/nonodesbg.webp
Normal file
BIN
src/Umbraco.Web.UI.Client/src/assets/img/nonodesbg.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* @ngdoc filter
|
||||
* @name umbraco.filters.simpleMarkdown
|
||||
* @description
|
||||
* Used when rendering a string as Markdown as HTML (i.e. with ng-bind-html). Allows use of **bold**, *italics*,  and [links](url)
|
||||
**/
|
||||
angular.module("umbraco.filters").filter('simpleMarkdown', function () {
|
||||
return function (text) {
|
||||
if (!text) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return text
|
||||
.replace(/\*\*(.*)\*\*/gim, '<b>$1</b>')
|
||||
.replace(/\*(.*)\*/gim, '<i>$1</i>')
|
||||
.replace(/!\[(.*?)\]\((.*?)\)/gim, "<img alt='$1' src='$2' />")
|
||||
.replace(/\[(.*?)\]\((.*?)\)/gim, "<a href='$2' target='_blank' rel='noopener' class='underline'>$1</a>")
|
||||
.replace(/\n/g, '<br />').trim();
|
||||
};
|
||||
});
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* @ngdoc filter
|
||||
* @name umbraco.filters.simpleMarkdown
|
||||
* @description
|
||||
* Used when rendering a string as Markdown as HTML (i.e. with ng-bind-html). Allows use of **bold**, *italics*,  and [links](url)
|
||||
**/
|
||||
angular.module("umbraco.filters").filter('simpleMarkdown', function () {
|
||||
return function (text) {
|
||||
if (!text) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return text
|
||||
.replace(/\*\*(.*)\*\*/gim, '<b>$1</b>')
|
||||
.replace(/\*(.*)\*/gim, '<i>$1</i>')
|
||||
.replace(/!\[(.*?)\]\((.*?)\)/gim, "<img alt='$1' src='$2' />")
|
||||
.replace(/\[(.*?)\]\((.*?)\)/gim, "<a href='$2' target='_blank' class='underline'>$1</a>")
|
||||
.replace(/\n/g, '<br />').trim();
|
||||
};
|
||||
});
|
||||
@@ -243,7 +243,7 @@ a:visited {
|
||||
}
|
||||
|
||||
section {
|
||||
background-image: url(../img/nonodesbg.jpg);
|
||||
background-image: url(../img/nonodesbg.webp);
|
||||
background-position: center center;
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
ng-class="{'trashed': vm.media.trashed}"
|
||||
ng-src="{{vm.thumbnail}}"
|
||||
title="{{vm.media.name}}"
|
||||
alt="{{vm.media.name}}" />
|
||||
alt="{{vm.media.name}}"
|
||||
draggable="false" />
|
||||
|
||||
<umb-file-icon ng-if="vm.loading === false && vm.icon"
|
||||
icon="{{vm.icon}}"
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
|
||||
<umb-property-actions actions="vm.propertyActions"></umb-property-actions>
|
||||
|
||||
<small class="control-description" ng-if="vm.property.description" ng-bind-html="vm.property.description | simpleMarkdown"></small>
|
||||
<small class="control-description" ng-if="vm.property.description" ng-bind-html="vm.property.description"></small>
|
||||
|
||||
<div ng-if="vm.property.extendedDescription">
|
||||
|
||||
<div ng-if="vm.property.extendedDescriptionVisible">
|
||||
<small class="control-description" ng-bind-html="vm.property.extendedDescription | simpleMarkdown"></small>
|
||||
<small class="control-description" ng-bind-html="vm.property.extendedDescription"></small>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-mini btn-link btn-link-reverse p0" ng-click="vm.property.extendedDescriptionVisible = !vm.property.extendedDescriptionVisible">
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<localize key="actions_chooseWhereToImport">Chose where to import</localize>
|
||||
<localize key="dictionaryListCaption">dictionary items</localize>.
|
||||
</strong>
|
||||
(optinal)
|
||||
(optional)
|
||||
</p>
|
||||
|
||||
<umb-tree section="translation"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div>
|
||||
|
||||
<div ng-if="model.language" class="umb-alert umb-alert--warning mb2">
|
||||
<localize key="defaultdialogs_languagedeletewarning">This will delete the language</localize> <strong>{{model.language.name}} [{{model.language.culture}}]</strong>.
|
||||
<localize key="defaultdialogs_languagedeletewarning">This will delete the language and all content related to the language</localize> <strong>{{model.language.name}} [{{model.language.culture}}]</strong>.
|
||||
</div>
|
||||
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize>?
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
$attrs.$observe('readonly', (value) => {
|
||||
vm.readonly = value !== undefined;
|
||||
|
||||
vm.sortableOptions.disabled = vm.readonly;
|
||||
vm.sortableOptions.disabled = vm.readonly || vm.singleBlockMode;
|
||||
vm.blockEditorApi.readonly = vm.readonly;
|
||||
|
||||
if (deleteAllBlocksAction) {
|
||||
@@ -107,11 +107,13 @@
|
||||
|
||||
inlineEditing = vm.model.config.useInlineEditingAsDefault;
|
||||
liveEditing = vm.model.config.useLiveEditing;
|
||||
|
||||
vm.singleBlockMode =
|
||||
vm.model.config.validationLimit.min == 1 &&
|
||||
vm.model.config.validationLimit.max == 1 &&
|
||||
vm.model.config.blocks.length == 1 &&
|
||||
vm.model.config.useSingleBlockMode;
|
||||
|
||||
vm.blockEditorApi.singleBlockMode = vm.singleBlockMode;
|
||||
|
||||
vm.validationLimit = vm.model.config.validationLimit;
|
||||
@@ -134,6 +136,22 @@
|
||||
scopeOfExistence = vm.umbElementEditorContent.getScope();
|
||||
}
|
||||
|
||||
vm.sortableOptions = {
|
||||
axis: "y",
|
||||
containment: "parent",
|
||||
cursor: "grabbing",
|
||||
handle: ".blockelement__draggable-element",
|
||||
cancel: "input,textarea,select,option",
|
||||
classes: ".blockelement--dragging",
|
||||
distance: 5,
|
||||
tolerance: "pointer",
|
||||
scroll: true,
|
||||
disabled: vm.readonly || vm.singleBlockMode,
|
||||
update: function (ev, ui) {
|
||||
setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
copyAllBlocksAction = {
|
||||
labelKey: "clipboard_labelForCopyAllEntries",
|
||||
labelTokens: [vm.model.label],
|
||||
@@ -519,6 +537,7 @@
|
||||
}
|
||||
|
||||
vm.requestShowCreate = requestShowCreate;
|
||||
|
||||
function requestShowCreate(createIndex, mouseEvent) {
|
||||
|
||||
if (vm.blockTypePicker) {
|
||||
@@ -539,12 +558,15 @@
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
vm.requestShowClipboard = requestShowClipboard;
|
||||
|
||||
function requestShowClipboard(createIndex) {
|
||||
showCreateDialog(createIndex, true);
|
||||
}
|
||||
|
||||
vm.showCreateDialog = showCreateDialog;
|
||||
|
||||
function showCreateDialog(createIndex, openClipboard) {
|
||||
|
||||
if (vm.blockTypePicker) {
|
||||
@@ -616,6 +638,7 @@
|
||||
editorService.open(blockPickerModel);
|
||||
|
||||
};
|
||||
|
||||
function userFlowWhenBlockWasCreated(createIndex) {
|
||||
if (vm.layout.length > createIndex) {
|
||||
var blockObject = vm.layout[createIndex].$block;
|
||||
@@ -835,28 +858,13 @@
|
||||
singleBlockMode: vm.singleBlockMode
|
||||
};
|
||||
|
||||
vm.sortableOptions = {
|
||||
axis: "y",
|
||||
containment: "parent",
|
||||
cursor: "grabbing",
|
||||
handle: ".blockelement__draggable-element",
|
||||
cancel: "input,textarea,select,option",
|
||||
classes: ".blockelement--dragging",
|
||||
distance: 5,
|
||||
tolerance: "pointer",
|
||||
scroll: true,
|
||||
disabled: vm.readonly,
|
||||
update: function (ev, ui) {
|
||||
setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
function onAmountOfBlocksChanged() {
|
||||
|
||||
// enable/disable property actions
|
||||
if (copyAllBlocksAction) {
|
||||
copyAllBlocksAction.isDisabled = vm.layout.length === 0;
|
||||
}
|
||||
|
||||
if (deleteAllBlocksAction) {
|
||||
deleteAllBlocksAction.isDisabled = vm.layout.length === 0 || vm.readonly;
|
||||
}
|
||||
|
||||
@@ -103,20 +103,6 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
|
||||
}
|
||||
};
|
||||
|
||||
// sortable options
|
||||
$scope.sortableOptions = {
|
||||
axis: "y",
|
||||
containment: "parent",
|
||||
distance: 10,
|
||||
opacity: 0.7,
|
||||
tolerance: "pointer",
|
||||
scroll: true,
|
||||
zIndex: 6000,
|
||||
update: function (e, ui) {
|
||||
setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
let removeAllEntriesAction = {
|
||||
labelKey: "clipboard_labelForRemoveAllEntries",
|
||||
labelTokens: [],
|
||||
@@ -153,6 +139,21 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
|
||||
$scope.maxNumberOfItems = $scope.model.config.maxNumber ? parseInt($scope.model.config.maxNumber) : 0;
|
||||
}
|
||||
|
||||
// sortable options
|
||||
$scope.sortableOptions = {
|
||||
axis: "y",
|
||||
containment: "parent",
|
||||
distance: 10,
|
||||
opacity: 0.7,
|
||||
tolerance: "pointer",
|
||||
scroll: true,
|
||||
zIndex: 6000,
|
||||
disabled: $scope.readonly || $scope.maxNumberOfItems === 1,
|
||||
update: function (e, ui) {
|
||||
setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
//Umbraco persists boolean for prevalues as "0" or "1" so we need to convert that!
|
||||
$scope.model.config.multiPicker = Object.toBoolean($scope.model.config.multiPicker);
|
||||
$scope.model.config.showOpenButton = Object.toBoolean($scope.model.config.showOpenButton);
|
||||
|
||||
@@ -34,9 +34,9 @@
|
||||
|
||||
<!-- Both min and max items -->
|
||||
<span ng-if="minNumberOfItems && maxNumberOfItems && minNumberOfItems !== maxNumberOfItems">
|
||||
<span ng-if="renderModel.length < maxNumberOfItems">Add between {{minNumberOfItems}} and {{maxNumberOfItems}} items</span>
|
||||
<span ng-if="renderModel.length < maxNumberOfItems">Add between {{minNumberOfItems}} and {{maxNumberOfItems}} item(s)</span>
|
||||
<span ng-if="renderModel.length > maxNumberOfItems">
|
||||
<localize key="validation_maxCount">You can only have</localize> {{maxNumberOfItems}} <localize key="validation_itemsSelected"> items selected</localize>
|
||||
<localize key="validation_maxCount">You can only have</localize> {{maxNumberOfItems}} <localize key="validation_itemsSelected"> item(s) selected</localize>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<span ng-if="minNumberOfItems && maxNumberOfItems && minNumberOfItems === maxNumberOfItems">
|
||||
<span ng-if="renderModel.length < maxNumberOfItems">Add {{minNumberOfItems - renderModel.length}} item(s)</span>
|
||||
<span ng-if="renderModel.length > maxNumberOfItems">
|
||||
<localize key="validation_maxCount">You can only have</localize> {{maxNumberOfItems}} <localize key="validation_itemsSelected"> items selected</localize>
|
||||
<localize key="validation_maxCount">You can only have</localize> {{maxNumberOfItems}} <localize key="validation_itemsSelected"> item(s) selected</localize>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<span ng-if="!minNumberOfItems && maxNumberOfItems">
|
||||
<span ng-if="renderModel.length < maxNumberOfItems">Add up to {{maxNumberOfItems}} items</span>
|
||||
<span ng-if="renderModel.length > maxNumberOfItems">
|
||||
<localize key="validation_maxCount">You can only have</localize> {{maxNumberOfItems}} <localize key="validation_itemsSelected">items selected</localize>
|
||||
<localize key="validation_maxCount">You can only have</localize> {{maxNumberOfItems}} <localize key="validation_itemsSelected">item(s) selected</localize>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -71,12 +71,12 @@
|
||||
|
||||
<div ng-messages="contentPickerForm.minCount.$error" show-validation-on-submit>
|
||||
<div class="help-inline" ng-message="minCount">
|
||||
<localize key="validation_minCount">You need to add at least</localize> {{minNumberOfItems}} <localize key="validation_items">items</localize>
|
||||
<localize key="validation_minCount">You need to add at least</localize> {{minNumberOfItems}} <localize key="validation_items">item(s)</localize>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-messages="contentPickerForm.maxCount.$error" show-validation-on-submit>
|
||||
<div class="help-inline" ng-message="maxCount">
|
||||
<localize key="validation_maxCount">You can only have</localize> {{maxNumberOfItems}} <localize key="validation_itemsSelected">items selected</localize>
|
||||
<localize key="validation_maxCount">You can only have</localize> {{maxNumberOfItems}} <localize key="validation_itemsSelected">item(s) selected</localize>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -49,7 +49,8 @@
|
||||
ng-if="media.$dataURL"
|
||||
ng-src="{{media.$dataURL}}"
|
||||
title="{{media.name}}"
|
||||
alt="{{media.name}}" />
|
||||
alt="{{media.name}}"
|
||||
draggable="false" />
|
||||
|
||||
<umb-file-icon ng-if="!media.$dataURL && media.$icon"
|
||||
icon="{{media.$icon}}"
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
vm.allowEditMedia = !vm.readonly;
|
||||
vm.allowDropMedia = !vm.readonly;
|
||||
|
||||
vm.sortableOptions.disabled = vm.readonly;
|
||||
vm.sortableOptions.disabled = vm.readonly || vm.singleMode;
|
||||
});
|
||||
|
||||
vm.$onInit = function() {
|
||||
@@ -109,6 +109,20 @@
|
||||
unsubscribe.push(mediaUploader.on('uploadSuccess', _handleMediaUploadSuccess));
|
||||
unsubscribe.push(mediaUploader.on('queueCompleted', _handleMediaQueueCompleted));
|
||||
|
||||
vm.sortableOptions = {
|
||||
cursor: "grabbing",
|
||||
handle: "umb-media-card, .umb-media-card",
|
||||
cancel: "input,textarea,select,option",
|
||||
classes: ".umb-media-card--dragging",
|
||||
distance: 5,
|
||||
tolerance: "pointer",
|
||||
scroll: true,
|
||||
disabled: vm.readonly || vm.singleMode,
|
||||
update: function (ev, ui) {
|
||||
setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
copyAllMediasAction = {
|
||||
labelKey: "clipboard_labelForCopyAllEntries",
|
||||
labelTokens: [vm.model.label],
|
||||
@@ -231,7 +245,7 @@
|
||||
function addMediaAt(createIndex, $event) {
|
||||
if (!vm.allowAddMedia) return;
|
||||
|
||||
var mediaPicker = {
|
||||
const mediaPicker = {
|
||||
startNodeId: vm.model.config.startNodeId,
|
||||
startNodeIsVirtual: vm.model.config.startNodeIsVirtual,
|
||||
dataTypeKey: vm.model.dataTypeKey,
|
||||
@@ -392,7 +406,7 @@
|
||||
// make a clone to avoid editing model directly.
|
||||
var mediaEntryClone = Utilities.copy(mediaEntry);
|
||||
|
||||
var mediaEditorModel = {
|
||||
const mediaEditorModel = {
|
||||
$parentScope: $scope, // pass in a $parentScope, this maintains the scope inheritance in infinite editing
|
||||
$parentForm: vm.propertyForm, // pass in a $parentForm, this maintains the FormController hierarchy with the infinite editing view (if it contains a form)
|
||||
createFlow: options.createFlow === true,
|
||||
@@ -502,20 +516,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
vm.sortableOptions = {
|
||||
cursor: "grabbing",
|
||||
handle: "umb-media-card, .umb-media-card",
|
||||
cancel: "input,textarea,select,option",
|
||||
classes: ".umb-media-card--dragging",
|
||||
distance: 5,
|
||||
tolerance: "pointer",
|
||||
scroll: true,
|
||||
disabled: vm.readonly,
|
||||
update: function (ev, ui) {
|
||||
setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
function onAmountOfMediaChanged() {
|
||||
|
||||
// enable/disable property actions
|
||||
|
||||
@@ -21,13 +21,19 @@ function multiUrlPickerController($scope, localizationService, entityResource, i
|
||||
|
||||
$scope.renderModel = [];
|
||||
|
||||
if ($scope.model.config && parseInt($scope.model.config.maxNumber) !== 1 && $scope.umbProperty) {
|
||||
var propertyActions = [
|
||||
if ($scope.model.config) {
|
||||
|
||||
$scope.minNumberOfItems = $scope.model.config.minNumber ? parseInt($scope.model.config.minNumber) : 0;
|
||||
$scope.maxNumberOfItems = $scope.model.config.maxNumber ? parseInt($scope.model.config.maxNumber) : 0;
|
||||
|
||||
if ($scope.umbProperty && $scope.maxNumberOfItems !== 1) {
|
||||
let propertyActions = [
|
||||
removeAllEntriesAction
|
||||
];
|
||||
|
||||
$scope.umbProperty.setPropertyActions(propertyActions);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Array.isArray($scope.model.value)) {
|
||||
$scope.model.value = [];
|
||||
@@ -41,7 +47,7 @@ function multiUrlPickerController($scope, localizationService, entityResource, i
|
||||
tolerance: "pointer",
|
||||
scroll: true,
|
||||
zIndex: 6000,
|
||||
disabled: $scope.readonly,
|
||||
disabled: $scope.readonly || $scope.maxNumberOfItems === 1,
|
||||
update: function () {
|
||||
setDirty();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.MultiUrlPickerController" class="umb-property-editor umb-contentpicker">
|
||||
<div ng-controller="Umbraco.PropertyEditors.MultiUrlPickerController" class="umb-property-editor umb-contentpicker">
|
||||
<p ng-if="(renderModel|filter:{trashed:true}).length == 1"><localize key="contentPicker_pickedTrashedItem">You have picked a content item currently deleted or in the recycle bin</localize></p>
|
||||
<p ng-if="(renderModel|filter:{trashed:true}).length > 1"><localize key="contentPicker_pickedTrashedItems">You have picked content items currently deleted or in the recycle bin</localize></p>
|
||||
|
||||
@@ -29,12 +29,11 @@
|
||||
|
||||
<div class="umb-contentpicker__min-max-help">
|
||||
|
||||
|
||||
<!-- Both min and max items -->
|
||||
<span ng-if="model.config.minNumber && model.config.maxNumber && model.config.minNumber !== model.config.maxNumber">
|
||||
<span ng-if="renderModel.length < model.config.maxNumber">Add between {{model.config.minNumber}} and {{model.config.maxNumber}} items</span>
|
||||
<span ng-if="renderModel.length > model.config.maxNumber">
|
||||
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected"> items selected</localize>
|
||||
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected"> item(s) selected</localize>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
<AdditionalFiles Include="umbraco\UmbracoWebsite\Maintenance.cshtml" />
|
||||
<AdditionalFiles Include="umbraco\UmbracoWebsite\NoNodes.cshtml" />
|
||||
<AdditionalFiles Include="umbraco\UmbracoWebsite\NotFound.cshtml" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.7">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -36,6 +36,7 @@ public class PublishedContentQueryTests : ExamineBaseTest
|
||||
|
||||
public bool EnableDefaultEventHandler => throw new NotImplementedException();
|
||||
public bool PublishedValuesOnly => throw new NotImplementedException();
|
||||
public bool SupportProtectedContent => throw new NotImplementedException();
|
||||
public IEnumerable<string> GetFields() => _fieldNames;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ public class ContentBuilderTests : DeliveryApiTests
|
||||
var urlSegment = "url-segment";
|
||||
var name = "The page";
|
||||
ConfigurePublishedContentMock(content, key, name, urlSegment, contentType.Object, new[] { prop1, prop2 });
|
||||
content.SetupGet(c => c.CreateDate).Returns(new DateTime(2023, 06, 01));
|
||||
content.SetupGet(c => c.UpdateDate).Returns(new DateTime(2023, 07, 12));
|
||||
|
||||
var publishedUrlProvider = new Mock<IPublishedUrlProvider>();
|
||||
publishedUrlProvider
|
||||
@@ -47,6 +49,8 @@ public class ContentBuilderTests : DeliveryApiTests
|
||||
Assert.AreEqual(2, result.Properties.Count);
|
||||
Assert.AreEqual("Delivery API value", result.Properties["deliveryApi"]);
|
||||
Assert.AreEqual("Default value", result.Properties["default"]);
|
||||
Assert.AreEqual(new DateTime(2023, 06, 01), result.CreateDate);
|
||||
Assert.AreEqual(new DateTime(2023, 07, 12), result.UpdateDate);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.DeliveryApi;
|
||||
[TestFixture]
|
||||
public class MarkdownEditorValueConverterTests : PropertyValueConverterTests
|
||||
{
|
||||
[TestCase("hello world", "<p>hello world</p>")]
|
||||
[TestCase("hello *world*", "<p>hello <em>world</em></p>")]
|
||||
[TestCase("hello world", "hello world")]
|
||||
[TestCase("hello *world*", "hello *world*")]
|
||||
[TestCase("", "")]
|
||||
[TestCase(null, "")]
|
||||
[TestCase(123, "")]
|
||||
|
||||
28
umbraco.sln
28
umbraco.sln
@@ -183,6 +183,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "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", "{E8324C85-2854-4E07-8789-2D83DB978339}"
|
||||
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
|
||||
@@ -356,6 +360,30 @@ Global
|
||||
{E8324C85-2854-4E07-8789-2D83DB978339}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E8324C85-2854-4E07-8789-2D83DB978339}.SkipTests|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E8324C85-2854-4E07-8789-2D83DB978339}.SkipTests|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9046F56E-4AC3-4603-A6A3-3ACCF632997E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9046F56E-4AC3-4603-A6A3-3ACCF632997E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9046F56E-4AC3-4603-A6A3-3ACCF632997E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9046F56E-4AC3-4603-A6A3-3ACCF632997E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9046F56E-4AC3-4603-A6A3-3ACCF632997E}.SkipTests|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9046F56E-4AC3-4603-A6A3-3ACCF632997E}.SkipTests|Any CPU.Build.0 = Debug|Any CPU
|
||||
{35E3DA10-5549-41DE-B7ED-CC29355BA9FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{35E3DA10-5549-41DE-B7ED-CC29355BA9FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{35E3DA10-5549-41DE-B7ED-CC29355BA9FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{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
|
||||
|
||||
Reference in New Issue
Block a user