Merge remote-tracking branch 'origin/v13/dev' into v14/dev

# Conflicts:
#	src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs

# Ignored Conflicts (Umbraco.Web.UI.Client is completly replaced in v14)
#	src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbtour/umbtourstep.directive.js
#	src/Umbraco.Web.UI.Client/src/views/components/application/umb-tour.html
#	src/Umbraco.Web.UI.Client/src/views/components/application/umbtour/umb-tour-step-content.html
#	src/Umbraco.Web.UI.Client/src/views/components/application/umbtour/umb-tour-step-counter.html
#	src/Umbraco.Web.UI.Client/src/views/components/application/umbtour/umb-tour-step-header.html
#	src/Umbraco.Web.UI.Client~HEAD
#	src/Umbraco.Web.UI.Login/package-lock.json
#	src/Umbraco.Web.UI.Login/package.json
This commit is contained in:
Sven Geusens
2024-04-05 14:14:45 +02:00
4 changed files with 198 additions and 12 deletions

View File

@@ -174,15 +174,17 @@ public static class ContentRepositoryExtensions
foreach (IProperty property in content.Properties)
{
// each property type may or may not support the variation
if (!property.PropertyType?.SupportsVariation(culture, "*", true) ?? false)
if ((!property.PropertyType?.SupportsVariation(culture, "*", true) ?? false) &&
!(property.PropertyType?.Variations == ContentVariation.Nothing))
{
continue;
}
foreach (IPropertyValue pvalue in property.Values)
{
if ((property.PropertyType?.SupportsVariation(pvalue.Culture, pvalue.Segment, true) ?? false) &&
(culture == "*" || (pvalue.Culture?.InvariantEquals(culture) ?? false)))
if (((property.PropertyType?.SupportsVariation(pvalue.Culture, pvalue.Segment, true) ?? false) &&
(culture == "*" || (pvalue.Culture?.InvariantEquals(culture) ?? false))) ||
property.PropertyType?.Variations == ContentVariation.Nothing)
{
property.SetValue(null, pvalue.Culture, pvalue.Segment);
}
@@ -193,7 +195,8 @@ public static class ContentRepositoryExtensions
IPropertyCollection otherProperties = other.Properties;
foreach (IProperty otherProperty in otherProperties)
{
if (!otherProperty?.PropertyType?.SupportsVariation(culture, "*", true) ?? true)
if ((!otherProperty?.PropertyType?.SupportsVariation(culture, "*", true) ?? true) &&
!(otherProperty?.PropertyType?.Variations == ContentVariation.Nothing))
{
continue;
}
@@ -203,8 +206,9 @@ public static class ContentRepositoryExtensions
{
foreach (IPropertyValue pvalue in otherProperty.Values)
{
if (otherProperty.PropertyType.SupportsVariation(pvalue.Culture, pvalue.Segment, true) &&
(culture == "*" || (pvalue.Culture?.InvariantEquals(culture) ?? false)))
if (((otherProperty?.PropertyType.SupportsVariation(pvalue.Culture, pvalue.Segment, true) ?? false) &&
(culture == "*" ||(pvalue.Culture?.InvariantEquals(culture) ?? false))) ||
otherProperty?.PropertyType?.Variations == ContentVariation.Nothing)
{
var value = published ? pvalue.PublishedValue : pvalue.EditedValue;
content.SetValue(alias, value, pvalue.Culture, pvalue.Segment);

View File

@@ -10,12 +10,12 @@ public enum RefreshMethodType
// that enum should get merged somehow with MessageType and renamed somehow
// but at the moment it is exposed in CacheRefresher webservice through RefreshInstruction
// so for the time being we keep it as-is for backward compatibility reasons
RefreshAll,
RefreshByGuid,
RefreshById,
RefreshByIds,
RefreshByJson,
RemoveById,
RefreshAll = 0,
RefreshByGuid = 1,
RefreshById = 2,
RefreshByIds = 3,
RefreshByJson = 4,
RemoveById = 5,
// would adding values break backward compatibility?
// RemoveByIds

View File

@@ -62,6 +62,7 @@ public class UmbracoPlan : MigrationPlan
To<V_13_0_0.ChangeWebhookRequestObjectColumnToNvarcharMax>("{F74CDA0C-7AAA-48C8-94C6-C6EC3C06F599}");
To<V_13_0_0.ChangeWebhookUrlColumnsToNvarcharMax>("{21C42760-5109-4C03-AB4F-7EA53577D1F5}");
To<V_13_0_0.AddExceptionOccured>("{6158F3A3-4902-4201-835E-1ED7F810B2D8}");
To<V_13_3_0.AlignUpgradedDatabase>("{985AF2BA-69D3-4DBA-95E0-AD3FA7459FA7}");
// To 14.0.0
To<V_14_0_0.AddPropertyEditorUiAliasColumn>("{419827A0-4FCE-464B-A8F3-247C6092AF55}");

View File

@@ -0,0 +1,181 @@
using NPoco;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
using ColumnInfo = Umbraco.Cms.Infrastructure.Persistence.SqlSyntax.ColumnInfo;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_13_3_0;
/// <summary>
/// We see some differences between an updated database and a fresh one,
/// the purpose of this migration is to align the two.
/// </summary>
public class AlignUpgradedDatabase : MigrationBase
{
public AlignUpgradedDatabase(IMigrationContext context)
: base(context)
{
}
protected override void Migrate()
{
// We ignore SQLite since it's considered a development DB
if (DatabaseType == DatabaseType.SQLite)
{
return;
}
ColumnInfo[] columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
Tuple<string, string, string, bool>[] indexes = SqlSyntax.GetDefinedIndexes(Database).ToArray();
DropCacheInstructionDefaultConstraint(columns);
AlignContentVersionTable(columns);
UpdateExternalLoginIndexes(indexes);
AlignNodeTable(columns);
MakeRelationTypeIndexUnique(indexes);
RemoveUserGroupDefault(columns);
MakeWebhookUrlNotNullable(columns);
MakeWebhookLogUrlNotNullable(columns);
}
private void MakeIndexUnique<TDto>(string tableName, string indexName, IEnumerable<Tuple<string, string, string, bool>> indexes)
{
// Let's only mess with the indexes if we have to.
// Indexes are in format TableName, IndexName, ColumnName, IsUnique
Tuple<string, string, string, bool>? loginProviderIndex = indexes.FirstOrDefault(x =>
x.Item1 == tableName && x.Item2 == indexName);
// Item4 == IsUnique
if (loginProviderIndex?.Item4 is false)
{
// The recommended way to change an index from non-unique to unique is to drop and recreate it.
DeleteIndex<TDto>(indexName);
CreateIndex<TDto>(indexName);
}
}
private void RemoveDefaultConstraint(string tableName, string columnName, IEnumerable<ColumnInfo> columns)
{
ColumnInfo? targetColumn = columns
.FirstOrDefault(x => x.TableName == tableName && x.ColumnName == columnName);
if (targetColumn is null)
{
throw new InvalidOperationException($"Could not find {columnName} column on {tableName} table.");
}
if (targetColumn.ColumnDefault is null)
{
return;
}
Delete.DefaultConstraint()
.OnTable(tableName)
.OnColumn(columnName)
.Do();
}
private void RenameColumn(string tableName, string oldColumnName, string newColumnName, IEnumerable<ColumnInfo> columns)
{
ColumnInfo? targetColumn = columns
.FirstOrDefault(x => x.TableName == tableName && x.ColumnName == oldColumnName);
if (targetColumn is null)
{
// The column was not found I.E. the column is correctly named
return;
}
Rename.Column(oldColumnName)
.OnTable(tableName)
.To(newColumnName)
.Do();
}
private void MakeNvarCharColumnNotNullable(string tableName, string columnName, IEnumerable<ColumnInfo> columns)
{
ColumnInfo? targetColumn = columns.FirstOrDefault(x => x.TableName == tableName && x.ColumnName == columnName);
if (targetColumn is null)
{
throw new InvalidOperationException($"Could not find {columnName} column in {tableName} table.");
}
if (targetColumn.IsNullable is false)
{
return;
}
Alter.Table(tableName)
.AlterColumn(columnName)
.AsCustom("nvarchar(max)")
.NotNullable()
.Do();
}
private void DropCacheInstructionDefaultConstraint(IEnumerable<ColumnInfo> columns)
=> RemoveDefaultConstraint("umbracoCacheInstruction", "jsonInstruction", columns);
private void AlignContentVersionTable(ColumnInfo[] columns)
{
// We need to do this to ensure we don't try to rename the constraint if it doesn't exist.
const string tableName = "umbracoContentVersion";
const string columnName = "VersionDate";
ColumnInfo? versionDateColumn = columns
.FirstOrDefault(x => x is { TableName: tableName, ColumnName: columnName });
if (versionDateColumn is null)
{
// The column was not found I.E. the column is correctly named
return;
}
RenameColumn(tableName, columnName, "versionDate", columns);
// Renames the default constraint for the column,
// apparently the content version table used to be prefixed with cms and not umbraco
// We don't have a fluid way to rename the default constraint so we have to use raw SQL
// This should be okay though since we are only running this migration on SQL Server
Sql<ISqlContext> renameConstraintQuery = Database.SqlContext.Sql(
"EXEC sp_rename N'DF_cmsContentVersion_VersionDate', N'DF_umbracoContentVersion_versionDate', N'OBJECT'");
Database.Execute(renameConstraintQuery);
}
private void UpdateExternalLoginIndexes(IEnumerable<Tuple<string, string, string, bool>> indexes)
{
const string userMemberOrKeyIndexName = "IX_umbracoExternalLogin_userOrMemberKey";
MakeIndexUnique<ExternalLoginDto>("umbracoExternalLogin", "IX_umbracoExternalLogin_LoginProvider", indexes);
if (IndexExists(userMemberOrKeyIndexName))
{
return;
}
CreateIndex<ExternalLoginDto>(userMemberOrKeyIndexName);
}
private void AlignNodeTable(ColumnInfo[] columns)
{
const string tableName = "umbracoNode";
RenameColumn(tableName, "parentID", "parentId", columns);
RenameColumn(tableName, "uniqueID", "uniqueId", columns);
const string extraIndexName = "IX_umbracoNode_ParentId";
if (IndexExists(extraIndexName))
{
DeleteIndex<NodeDto>(extraIndexName);
}
}
private void MakeRelationTypeIndexUnique(Tuple<string, string, string, bool>[] indexes)
=> MakeIndexUnique<RelationTypeDto>("umbracoRelationType", "IX_umbracoRelationType_alias", indexes);
private void RemoveUserGroupDefault(ColumnInfo[] columns)
=> RemoveDefaultConstraint("umbracoUserGroup", "hasAccessToAllLanguages", columns);
private void MakeWebhookUrlNotNullable(ColumnInfo[] columns)
=> MakeNvarCharColumnNotNullable("umbracoWebhook", "url", columns);
private void MakeWebhookLogUrlNotNullable(ColumnInfo[] columns)
=> MakeNvarCharColumnNotNullable("umbracoWebhookLog", "url", columns);
}