Merge remote-tracking branch 'origin/v8/dev' into netcore/dev
# Conflicts: # src/Umbraco.Core/IO/SystemDirectories.cs # src/Umbraco.Core/Udi.cs # src/Umbraco.Core/Umbraco.Core.csproj
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
using NPoco;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.Models
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Snapshot of the <see cref="ContentTypeDto"/> as it was at version 8.0
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is required during migrations the schema of this table changed and running SQL against the new table would result in errors
|
||||
/// </remarks>
|
||||
[TableName(TableName)]
|
||||
[PrimaryKey("pk")]
|
||||
[ExplicitColumns]
|
||||
internal class ContentTypeDto80
|
||||
{
|
||||
public const string TableName = Constants.DatabaseSchema.Tables.ContentType;
|
||||
|
||||
[Column("pk")]
|
||||
[PrimaryKeyColumn(IdentitySeed = 535)]
|
||||
public int PrimaryKey { get; set; }
|
||||
|
||||
[Column("nodeId")]
|
||||
[ForeignKey(typeof(NodeDto))]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_cmsContentType")]
|
||||
public int NodeId { get; set; }
|
||||
|
||||
[Column("alias")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public string Alias { get; set; }
|
||||
|
||||
[Column("icon")]
|
||||
[Index(IndexTypes.NonClustered)]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public string Icon { get; set; }
|
||||
|
||||
[Column("thumbnail")]
|
||||
[Constraint(Default = "folder.png")]
|
||||
public string Thumbnail { get; set; }
|
||||
|
||||
[Column("description")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[Length(1500)]
|
||||
public string Description { get; set; }
|
||||
|
||||
[Column("isContainer")]
|
||||
[Constraint(Default = "0")]
|
||||
public bool IsContainer { get; set; }
|
||||
|
||||
[Column("allowAtRoot")]
|
||||
[Constraint(Default = "0")]
|
||||
public bool AllowAtRoot { get; set; }
|
||||
|
||||
[Column("variations")]
|
||||
[Constraint(Default = "1" /*ContentVariation.InvariantNeutral*/)]
|
||||
public byte Variations { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public NodeDto NodeDto { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
using NPoco;
|
||||
using System;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Snapshot of the <see cref="PropertyDataDto"/> as it was at version 8.0
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is required during migrations the schema of this table changed and running SQL against the new table would result in errors
|
||||
/// </remarks>
|
||||
[TableName(TableName)]
|
||||
[PrimaryKey("id")]
|
||||
[ExplicitColumns]
|
||||
internal class PropertyDataDto80
|
||||
{
|
||||
public const string TableName = Constants.DatabaseSchema.Tables.PropertyData;
|
||||
public const int VarcharLength = 512;
|
||||
public const int SegmentLength = 256;
|
||||
|
||||
private decimal? _decimalValue;
|
||||
|
||||
// pk, not used at the moment (never updating)
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("versionId")]
|
||||
[ForeignKey(typeof(ContentVersionDto))]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_" + TableName + "_VersionId", ForColumns = "versionId,propertyTypeId,languageId,segment")]
|
||||
public int VersionId { get; set; }
|
||||
|
||||
[Column("propertyTypeId")]
|
||||
[ForeignKey(typeof(PropertyTypeDto80))]
|
||||
[Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_PropertyTypeId")]
|
||||
public int PropertyTypeId { get; set; }
|
||||
|
||||
[Column("languageId")]
|
||||
[ForeignKey(typeof(LanguageDto))]
|
||||
[Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_LanguageId")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public int? LanguageId { get; set; }
|
||||
|
||||
[Column("segment")]
|
||||
[Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_Segment")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[Length(SegmentLength)]
|
||||
public string Segment { get; set; }
|
||||
|
||||
[Column("intValue")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public int? IntegerValue { get; set; }
|
||||
|
||||
[Column("decimalValue")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public decimal? DecimalValue
|
||||
{
|
||||
get => _decimalValue;
|
||||
set => _decimalValue = value?.Normalize();
|
||||
}
|
||||
|
||||
[Column("dateValue")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public DateTime? DateValue { get; set; }
|
||||
|
||||
[Column("varcharValue")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[Length(VarcharLength)]
|
||||
public string VarcharValue { get; set; }
|
||||
|
||||
[Column("textValue")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[SpecialDbType(SpecialDbTypes.NTEXT)]
|
||||
public string TextValue { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
[Reference(ReferenceType.OneToOne, ColumnName = "PropertyTypeId")]
|
||||
public PropertyTypeDto80 PropertyTypeDto { get; set; }
|
||||
|
||||
[Ignore]
|
||||
public object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IntegerValue.HasValue)
|
||||
return IntegerValue.Value;
|
||||
|
||||
if (DecimalValue.HasValue)
|
||||
return DecimalValue.Value;
|
||||
|
||||
if (DateValue.HasValue)
|
||||
return DateValue.Value;
|
||||
|
||||
if (!string.IsNullOrEmpty(VarcharValue))
|
||||
return VarcharValue;
|
||||
|
||||
if (!string.IsNullOrEmpty(TextValue))
|
||||
return TextValue;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public PropertyDataDto80 Clone(int versionId)
|
||||
{
|
||||
return new PropertyDataDto80
|
||||
{
|
||||
VersionId = versionId,
|
||||
PropertyTypeId = PropertyTypeId,
|
||||
LanguageId = LanguageId,
|
||||
Segment = Segment,
|
||||
IntegerValue = IntegerValue,
|
||||
DecimalValue = DecimalValue,
|
||||
DateValue = DateValue,
|
||||
VarcharValue = VarcharValue,
|
||||
TextValue = TextValue,
|
||||
PropertyTypeDto = PropertyTypeDto
|
||||
};
|
||||
}
|
||||
|
||||
protected bool Equals(PropertyDataDto other)
|
||||
{
|
||||
return Id == other.Id;
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
return
|
||||
!ReferenceEquals(null, other) // other is not null
|
||||
&& (ReferenceEquals(this, other) // and either ref-equals, or same id
|
||||
|| other is PropertyDataDto pdata && pdata.Id == Id);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
// ReSharper disable once NonReadonlyMemberInGetHashCode
|
||||
return Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using NPoco;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Snapshot of the <see cref="PropertyTypeDto"/> as it was at version 8.0
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is required during migrations before 8.6 since the schema has changed and running SQL against the new table would result in errors
|
||||
/// </remarks>
|
||||
[TableName(Constants.DatabaseSchema.Tables.PropertyType)]
|
||||
[PrimaryKey("id")]
|
||||
[ExplicitColumns]
|
||||
internal class PropertyTypeDto80
|
||||
{
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(IdentitySeed = 50)]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("dataTypeId")]
|
||||
[ForeignKey(typeof(DataTypeDto), Column = "nodeId")]
|
||||
public int DataTypeId { get; set; }
|
||||
|
||||
[Column("contentTypeId")]
|
||||
[ForeignKey(typeof(ContentTypeDto), Column = "nodeId")]
|
||||
public int ContentTypeId { get; set; }
|
||||
|
||||
[Column("propertyTypeGroupId")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[ForeignKey(typeof(PropertyTypeGroupDto))]
|
||||
public int? PropertyTypeGroupId { get; set; }
|
||||
|
||||
[Index(IndexTypes.NonClustered, Name = "IX_cmsPropertyTypeAlias")]
|
||||
[Column("Alias")]
|
||||
public string Alias { get; set; }
|
||||
|
||||
[Column("Name")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Column("sortOrder")]
|
||||
[Constraint(Default = "0")]
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
[Column("mandatory")]
|
||||
[Constraint(Default = "0")]
|
||||
public bool Mandatory { get; set; }
|
||||
|
||||
[Column("validationRegExp")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public string ValidationRegExp { get; set; }
|
||||
|
||||
[Column("Description")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[Length(2000)]
|
||||
public string Description { get; set; }
|
||||
|
||||
[Column("variations")]
|
||||
[Constraint(Default = "1" /*ContentVariation.InvariantNeutral*/)]
|
||||
public byte Variations { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
[Reference(ReferenceType.OneToOne, ColumnName = "DataTypeId")]
|
||||
public DataTypeDto DataTypeDto { get; set; }
|
||||
|
||||
[Column("UniqueID")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Constraint(Default = SystemMethods.NewGuid)]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_cmsPropertyTypeUniqueID")]
|
||||
public Guid UniqueId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_6_0
|
||||
{
|
||||
public class MissingDictionaryIndex : MigrationBase
|
||||
{
|
||||
public MissingDictionaryIndex(IMigrationContext context)
|
||||
: base(context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an index to the foreign key column <c>parent</c> on <c>DictionaryDto</c>'s table
|
||||
/// if it doesn't already exist
|
||||
/// </summary>
|
||||
public override void Migrate()
|
||||
{
|
||||
var indexName = "IX_" + DictionaryDto.TableName + "_Parent";
|
||||
|
||||
if (!IndexExists(indexName))
|
||||
{
|
||||
Create
|
||||
.Index(indexName)
|
||||
.OnTable(DictionaryDto.TableName)
|
||||
.OnColumn("parent")
|
||||
.Ascending()
|
||||
.WithOptions().NonClustered()
|
||||
.Do();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ namespace Umbraco.Core
|
||||
/// <remarks>An Udi can be fully qualified or "closed" eg umb://document/{guid} or "open" eg umb://document.</remarks>
|
||||
[TypeConverter(typeof(UdiTypeConverter))]
|
||||
public abstract class Udi : IComparable<Udi>
|
||||
{
|
||||
public Uri UriValue { get; }
|
||||
{
|
||||
public Uri UriValue { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Udi class.
|
||||
@@ -35,7 +35,7 @@ namespace Umbraco.Core
|
||||
UriValue = uriValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity type part of the identifier.
|
||||
@@ -54,7 +54,7 @@ namespace Umbraco.Core
|
||||
return UriValue.AbsoluteUri;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a root Udi for an entity type.
|
||||
@@ -114,7 +114,7 @@ namespace Umbraco.Core
|
||||
|
||||
if (udiType == UdiType.GuidUdi)
|
||||
return new GuidUdi(uri);
|
||||
if (udiType == UdiType.GuidUdi)
|
||||
if (udiType == UdiType.StringUdi)
|
||||
return new StringUdi(uri);
|
||||
|
||||
throw new ArgumentException(string.Format("Uri \"{0}\" is not a valid udi.", uri));
|
||||
@@ -166,6 +166,6 @@ namespace Umbraco.Core
|
||||
return (udi1 == udi2) == false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
@@ -84,10 +85,18 @@ namespace Umbraco.Core.Migrations
|
||||
|
||||
protected void ReplaceColumn<T>(string tableName, string currentName, string newName)
|
||||
{
|
||||
AddColumn<T>(tableName, newName, out var sqls);
|
||||
Execute.Sql($"UPDATE {SqlSyntax.GetQuotedTableName(tableName)} SET {SqlSyntax.GetQuotedColumnName(newName)}={SqlSyntax.GetQuotedColumnName(currentName)}").Do();
|
||||
foreach (var sql in sqls) Execute.Sql(sql).Do();
|
||||
Delete.Column(currentName).FromTable(tableName).Do();
|
||||
if (DatabaseType.IsSqlCe())
|
||||
{
|
||||
AddColumn<T>(tableName, newName, out var sqls);
|
||||
Execute.Sql($"UPDATE {SqlSyntax.GetQuotedTableName(tableName)} SET {SqlSyntax.GetQuotedColumnName(newName)}={SqlSyntax.GetQuotedColumnName(currentName)}").Do();
|
||||
foreach (var sql in sqls) Execute.Sql(sql).Do();
|
||||
Delete.Column(currentName).FromTable(tableName).Do();
|
||||
}
|
||||
else
|
||||
{
|
||||
Execute.Sql(SqlSyntax.FormatColumnRename(tableName, currentName, newName)).Do();
|
||||
AlterColumn<T>(tableName, newName);
|
||||
}
|
||||
}
|
||||
|
||||
protected bool TableExists(string tableName)
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Umbraco.Core.Migrations.Upgrade.Common
|
||||
{
|
||||
// remove those that may already have keys
|
||||
Delete.KeysAndIndexes(Constants.DatabaseSchema.Tables.KeyValue).Do();
|
||||
Delete.KeysAndIndexes(Constants.DatabaseSchema.Tables.PropertyData).Do();
|
||||
|
||||
// re-create *all* keys and indexes
|
||||
foreach (var x in DatabaseSchemaCreator.OrderedTables)
|
||||
|
||||
@@ -193,6 +193,9 @@ namespace Umbraco.Core.Migrations.Upgrade
|
||||
To<MissingContentVersionsIndexes>("{EE288A91-531B-4995-8179-1D62D9AA3E2E}");
|
||||
To<AddMainDomLock>("{2AB29964-02A1-474D-BD6B-72148D2A53A2}");
|
||||
|
||||
|
||||
To<MissingDictionaryIndex>("{a78e3369-8ea3-40ec-ad3f-5f76929d2b20}");
|
||||
|
||||
//FINAL
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,8 +75,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
var labelPropertyTypes = Database.Fetch<PropertyTypeDto>(Sql()
|
||||
.Select<PropertyTypeDto>(x => x.Id, x => x.Alias)
|
||||
.From<PropertyTypeDto>()
|
||||
.Where<PropertyTypeDto>(x => x.DataTypeId == Constants.DataTypes.LabelString)
|
||||
);
|
||||
.Where<PropertyTypeDto>(x => x.DataTypeId == Constants.DataTypes.LabelString));
|
||||
|
||||
var intPropertyAliases = new[] { Constants.Conventions.Media.Width, Constants.Conventions.Media.Height, Constants.Conventions.Member.FailedPasswordAttempts };
|
||||
var bigintPropertyAliases = new[] { Constants.Conventions.Media.Bytes };
|
||||
@@ -101,16 +100,18 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
foreach (var value in values)
|
||||
Database.Execute(Sql()
|
||||
.Update<PropertyDataDto>(u => u
|
||||
.Set(x => x.IntegerValue, string.IsNullOrWhiteSpace(value.VarcharValue) ? (int?) null : int.Parse(value.VarcharValue, NumberStyles.Any, CultureInfo.InvariantCulture))
|
||||
.Set(x => x.TextValue, null))
|
||||
.Set(x => x.IntegerValue, string.IsNullOrWhiteSpace(value.VarcharValue) ? (int?)null : int.Parse(value.VarcharValue, NumberStyles.Any, CultureInfo.InvariantCulture))
|
||||
.Set(x => x.TextValue, null)
|
||||
.Set(x => x.VarcharValue, null))
|
||||
.Where<PropertyDataDto>(x => x.Id == value.Id));
|
||||
|
||||
values = Database.Fetch<PropertyDataValue>(Sql().Select<PropertyDataDto>(x => x.Id, x => x.VarcharValue).From<PropertyDataDto>().WhereIn<PropertyDataDto>(x => x.PropertyTypeId, dtPropertyTypes));
|
||||
foreach (var value in values)
|
||||
Database.Execute(Sql()
|
||||
.Update<PropertyDataDto>(u => u
|
||||
.Set(x => x.DateValue, string.IsNullOrWhiteSpace(value.VarcharValue) ? (DateTime?) null : DateTime.Parse(value.VarcharValue, CultureInfo.InvariantCulture, DateTimeStyles.None))
|
||||
.Set(x => x.TextValue, null))
|
||||
.Set(x => x.DateValue, string.IsNullOrWhiteSpace(value.VarcharValue) ? (DateTime?)null : DateTime.Parse(value.VarcharValue, CultureInfo.InvariantCulture, DateTimeStyles.None))
|
||||
.Set(x => x.TextValue, null)
|
||||
.Set(x => x.VarcharValue, null))
|
||||
.Where<PropertyDataDto>(x => x.Id == value.Id));
|
||||
|
||||
// anything that's custom... ppl will have to figure it out manually, there isn't much we can do about it
|
||||
|
||||
@@ -4,8 +4,10 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_0_0.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
@@ -47,14 +49,14 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
}
|
||||
}
|
||||
|
||||
var propertyTypes = Database.Fetch<PropertyTypeDto>(Sql().Select<PropertyTypeDto>().From<PropertyTypeDto>());
|
||||
var propertyTypes = Database.Fetch<PropertyTypeDto80>(Sql().Select<PropertyTypeDto80>().From<PropertyTypeDto80>());
|
||||
foreach (var dto in propertyTypes)
|
||||
{
|
||||
dto.Variations = GetNewValue(dto.Variations);
|
||||
Database.Update(dto);
|
||||
}
|
||||
|
||||
var contentTypes = Database.Fetch<ContentTypeDto>(Sql().Select<ContentTypeDto>().From<ContentTypeDto>());
|
||||
var contentTypes = Database.Fetch<ContentTypeDto80>(Sql().Select<ContentTypeDto80>().From<ContentTypeDto80>());
|
||||
foreach (var dto in contentTypes)
|
||||
{
|
||||
dto.Variations = GetNewValue(dto.Variations);
|
||||
@@ -62,57 +64,11 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
}
|
||||
}
|
||||
|
||||
// we *need* to use this private DTO here, which does *not* have extra properties, which would kill the migration
|
||||
// we *need* to use these private DTOs here, which does *not* have extra properties, which would kill the migration
|
||||
|
||||
[TableName(TableName)]
|
||||
[PrimaryKey("pk")]
|
||||
[ExplicitColumns]
|
||||
private class ContentTypeDto
|
||||
{
|
||||
public const string TableName = Constants.DatabaseSchema.Tables.ContentType;
|
||||
|
||||
|
||||
[Column("pk")]
|
||||
[PrimaryKeyColumn(IdentitySeed = 535)]
|
||||
public int PrimaryKey { get; set; }
|
||||
|
||||
[Column("nodeId")]
|
||||
[ForeignKey(typeof(NodeDto))]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_cmsContentType")]
|
||||
public int NodeId { get; set; }
|
||||
|
||||
[Column("alias")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public string Alias { get; set; }
|
||||
|
||||
[Column("icon")]
|
||||
[Index(IndexTypes.NonClustered)]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public string Icon { get; set; }
|
||||
|
||||
[Column("thumbnail")]
|
||||
[Constraint(Default = "folder.png")]
|
||||
public string Thumbnail { get; set; }
|
||||
|
||||
[Column("description")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[Length(1500)]
|
||||
public string Description { get; set; }
|
||||
|
||||
[Column("isContainer")]
|
||||
[Constraint(Default = "0")]
|
||||
public bool IsContainer { get; set; }
|
||||
|
||||
[Column("allowAtRoot")]
|
||||
[Constraint(Default = "0")]
|
||||
public bool AllowAtRoot { get; set; }
|
||||
|
||||
[Column("variations")]
|
||||
[Constraint(Default = "1" /*ContentVariation.InvariantNeutral*/)]
|
||||
public byte Variations { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public NodeDto NodeDto { get; set; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+5
-6
@@ -2,8 +2,7 @@
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_0_0.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
@@ -34,11 +33,11 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
}
|
||||
|
||||
var sqlPropertyTpes = Sql()
|
||||
.Select<PropertyTypeDto>()
|
||||
.From<PropertyTypeDto>()
|
||||
.Where<PropertyTypeDto>(x => dataTypeIds.Contains(x.DataTypeId));
|
||||
.Select<PropertyTypeDto80>()
|
||||
.From<PropertyTypeDto80>()
|
||||
.Where<PropertyTypeDto80>(x => dataTypeIds.Contains(x.DataTypeId));
|
||||
|
||||
var propertyTypeIds = Database.Fetch<PropertyTypeDto>(sqlPropertyTpes).Select(x => x.Id).ToList();
|
||||
var propertyTypeIds = Database.Fetch<PropertyTypeDto80>(sqlPropertyTpes).Select(x => x.Id).ToList();
|
||||
|
||||
if (propertyTypeIds.Count == 0) return;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
{
|
||||
@@ -17,14 +18,24 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
|
||||
AddColumn<MediaVersionDto>("id", out var sqls);
|
||||
|
||||
// SQLCE does not support UPDATE...FROM
|
||||
var temp2 = Database.Fetch<dynamic>($@"SELECT v.versionId, v.id
|
||||
if (Database.DatabaseType.IsSqlCe())
|
||||
{
|
||||
// SQLCE does not support UPDATE...FROM
|
||||
var versions = Database.Fetch<dynamic>($@"SELECT v.versionId, v.id
|
||||
FROM cmsContentVersion v
|
||||
JOIN umbracoNode n on v.contentId=n.id
|
||||
WHERE n.nodeObjectType='{Constants.ObjectTypes.Media}'");
|
||||
foreach (var t in temp2)
|
||||
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.MediaVersion} SET id={t.id} WHERE versionId='{t.versionId}'").Do();
|
||||
|
||||
foreach (var t in versions)
|
||||
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.MediaVersion} SET id={t.id} WHERE versionId='{t.versionId}'").Do();
|
||||
}
|
||||
else
|
||||
{
|
||||
Database.Execute($@"UPDATE {Constants.DatabaseSchema.Tables.MediaVersion} SET id=v.id
|
||||
FROM {Constants.DatabaseSchema.Tables.MediaVersion} m
|
||||
JOIN cmsContentVersion v on m.versionId = v.versionId
|
||||
JOIN umbracoNode n on v.contentId=n.id
|
||||
WHERE n.nodeObjectType='{Constants.ObjectTypes.Media}'");
|
||||
}
|
||||
foreach (var sql in sqls)
|
||||
Execute.Sql(sql).Do();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Migrations.Install;
|
||||
@@ -19,6 +20,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
public override void Migrate()
|
||||
{
|
||||
MigratePropertyData();
|
||||
CreatePropertyDataIndexes();
|
||||
MigrateContentAndPropertyTypes();
|
||||
MigrateContent();
|
||||
MigrateVersions();
|
||||
@@ -74,10 +76,20 @@ HAVING COUNT(v2.id) <> 1").Any())
|
||||
{
|
||||
Alter.Table(PreTables.PropertyData).AddColumn("versionId2").AsInt32().Nullable().Do();
|
||||
|
||||
// SQLCE does not support UPDATE...FROM
|
||||
var temp = Database.Fetch<dynamic>($"SELECT id, versionId FROM {PreTables.ContentVersion}");
|
||||
foreach (var t in temp)
|
||||
Database.Execute($"UPDATE {PreTables.PropertyData} SET versionId2=@v2 WHERE versionId=@v1", new { v1 = t.versionId, v2 = t.id });
|
||||
if (Database.DatabaseType.IsSqlCe())
|
||||
{
|
||||
// SQLCE does not support UPDATE...FROM
|
||||
var versions = Database.Fetch<dynamic>($"SELECT id, versionId FROM {PreTables.ContentVersion}");
|
||||
foreach (var t in versions)
|
||||
Database.Execute($"UPDATE {PreTables.PropertyData} SET versionId2=@v2 WHERE versionId=@v1", new { v1 = t.versionId, v2 = t.id });
|
||||
}
|
||||
else
|
||||
{
|
||||
Database.Execute($@"UPDATE {PreTables.PropertyData} SET versionId2={PreTables.ContentVersion}.id
|
||||
FROM {PreTables.ContentVersion}
|
||||
INNER JOIN {PreTables.PropertyData} ON {PreTables.ContentVersion}.versionId = {PreTables.PropertyData}.versionId");
|
||||
}
|
||||
|
||||
Delete.Column("versionId").FromTable(PreTables.PropertyData).Do();
|
||||
ReplaceColumn<PropertyDataDto>(PreTables.PropertyData, "versionId2", "versionId");
|
||||
}
|
||||
@@ -90,6 +102,22 @@ HAVING COUNT(v2.id) <> 1").Any())
|
||||
Rename.Table(PreTables.PropertyData).To(Constants.DatabaseSchema.Tables.PropertyData).Do();
|
||||
}
|
||||
|
||||
private void CreatePropertyDataIndexes()
|
||||
{
|
||||
// Creates a temporary index on umbracoPropertyData to speed up other migrations which update property values.
|
||||
// It will be removed in CreateKeysAndIndexes before the normal indexes for the table are created
|
||||
var tableDefinition = Persistence.DatabaseModelDefinitions.DefinitionFactory.GetTableDefinition(typeof(PropertyDataDto), SqlSyntax);
|
||||
Execute.Sql(SqlSyntax.FormatPrimaryKey(tableDefinition)).Do();
|
||||
Create.Index("IX_umbracoPropertyData_Temp").OnTable(PropertyDataDto.TableName)
|
||||
.WithOptions().Unique()
|
||||
.WithOptions().NonClustered()
|
||||
.OnColumn("versionId").Ascending()
|
||||
.OnColumn("propertyTypeId").Ascending()
|
||||
.OnColumn("languageId").Ascending()
|
||||
.OnColumn("segment").Ascending()
|
||||
.Do();
|
||||
}
|
||||
|
||||
private void MigrateContentAndPropertyTypes()
|
||||
{
|
||||
if (!ColumnExists(PreTables.ContentType, "variations"))
|
||||
@@ -153,22 +181,40 @@ HAVING COUNT(v2.id) <> 1").Any())
|
||||
ReplaceColumn<ContentVersionDto>(PreTables.ContentVersion, "ContentId", "nodeId");
|
||||
|
||||
// populate contentVersion text, current and userId columns for documents
|
||||
// SQLCE does not support UPDATE...FROM
|
||||
var temp1 = Database.Fetch<dynamic>($"SELECT versionId, text, newest, documentUser FROM {PreTables.Document}");
|
||||
foreach (var t in temp1)
|
||||
Database.Execute($@"UPDATE {PreTables.ContentVersion} SET text=@text, {SqlSyntax.GetQuotedColumnName("current")}=@current, userId=@userId WHERE versionId=@versionId",
|
||||
new { text = t.text, current = t.newest, userId=t.documentUser, versionId=t.versionId });
|
||||
if (Database.DatabaseType.IsSqlCe())
|
||||
{
|
||||
// SQLCE does not support UPDATE...FROM
|
||||
var documents = Database.Fetch<dynamic>($"SELECT versionId, text, published, newest, documentUser FROM {PreTables.Document}");
|
||||
foreach (var t in documents)
|
||||
Database.Execute($@"UPDATE {PreTables.ContentVersion} SET text=@text, {SqlSyntax.GetQuotedColumnName("current")}=@current, userId=@userId WHERE versionId=@versionId",
|
||||
new { text = t.text, current = t.newest && !t.published, userId = t.documentUser, versionId = t.versionId });
|
||||
}
|
||||
else
|
||||
{
|
||||
Database.Execute($@"UPDATE {PreTables.ContentVersion} SET text=d.text, {SqlSyntax.GetQuotedColumnName("current")}=(d.newest & ~d.published), userId=d.documentUser
|
||||
FROM {PreTables.ContentVersion} v INNER JOIN {PreTables.Document} d ON d.versionId = v.versionId");
|
||||
}
|
||||
|
||||
// populate contentVersion text and current columns for non-documents, userId is default
|
||||
// SQLCE does not support UPDATE...FROM
|
||||
var temp2 = Database.Fetch<dynamic>($@"SELECT cver.versionId, n.text
|
||||
if (Database.DatabaseType.IsSqlCe())
|
||||
{
|
||||
// SQLCE does not support UPDATE...FROM
|
||||
var otherContent = Database.Fetch<dynamic>($@"SELECT cver.versionId, n.text
|
||||
FROM {PreTables.ContentVersion} cver
|
||||
JOIN {SqlSyntax.GetQuotedTableName(Constants.DatabaseSchema.Tables.Node)} n ON cver.nodeId=n.id
|
||||
WHERE cver.versionId NOT IN (SELECT versionId FROM {SqlSyntax.GetQuotedTableName(PreTables.Document)})");
|
||||
|
||||
foreach (var t in temp2)
|
||||
Database.Execute($@"UPDATE {PreTables.ContentVersion} SET text=@text, {SqlSyntax.GetQuotedColumnName("current")}=1, userId=0 WHERE versionId=@versionId",
|
||||
new { text = t.text, versionId=t.versionId });
|
||||
foreach (var t in otherContent)
|
||||
Database.Execute($@"UPDATE {PreTables.ContentVersion} SET text=@text, {SqlSyntax.GetQuotedColumnName("current")}=1, userId=0 WHERE versionId=@versionId",
|
||||
new { text = t.text, versionId = t.versionId });
|
||||
}
|
||||
else
|
||||
{
|
||||
Database.Execute($@"UPDATE {PreTables.ContentVersion} SET text=n.text, {SqlSyntax.GetQuotedColumnName("current")}=1, userId=0
|
||||
FROM {PreTables.ContentVersion} cver
|
||||
JOIN {SqlSyntax.GetQuotedTableName(Constants.DatabaseSchema.Tables.Node)} n ON cver.nodeId=n.id
|
||||
WHERE cver.versionId NOT IN (SELECT versionId FROM {SqlSyntax.GetQuotedTableName(PreTables.Document)})");
|
||||
}
|
||||
|
||||
// create table
|
||||
Create.Table<DocumentVersionDto>(withoutKeysAndIndexes: true).Do();
|
||||
@@ -179,36 +225,42 @@ SELECT cver.id, doc.templateId, doc.published
|
||||
FROM {SqlSyntax.GetQuotedTableName(PreTables.ContentVersion)} cver
|
||||
JOIN {SqlSyntax.GetQuotedTableName(PreTables.Document)} doc ON doc.nodeId=cver.nodeId AND doc.versionId=cver.versionId");
|
||||
|
||||
|
||||
// need to add extra rows for where published=newest
|
||||
// 'cos INSERT above has inserted the 'published' document version
|
||||
// and v8 always has a 'edited' document version too
|
||||
var temp3 = Database.Fetch<dynamic>($@"SELECT doc.nodeId, doc.updateDate, doc.documentUser, doc.text, doc.templateId, cver.id versionId
|
||||
Database.Execute($@"
|
||||
INSERT INTO {SqlSyntax.GetQuotedTableName(PreTables.ContentVersion)} (nodeId, versionId, versionDate, userId, {SqlSyntax.GetQuotedColumnName("current")}, text)
|
||||
SELECT doc.nodeId, NEWID(), doc.updateDate, doc.documentUser, 1, doc.text
|
||||
FROM {SqlSyntax.GetQuotedTableName(PreTables.Document)} doc
|
||||
JOIN {SqlSyntax.GetQuotedTableName(PreTables.ContentVersion)} cver ON doc.nodeId=cver.nodeId AND doc.versionId=cver.versionId
|
||||
WHERE doc.newest=1 AND doc.published=1");
|
||||
var getIdentity = "@@@@IDENTITY";
|
||||
foreach (var t in temp3)
|
||||
{
|
||||
Database.Execute($@"INSERT INTO {SqlSyntax.GetQuotedTableName(PreTables.ContentVersion)} (nodeId, versionId, versionDate, userId, {SqlSyntax.GetQuotedColumnName("current")}, text)
|
||||
VALUES (@nodeId, @versionId, @versionDate, @userId, 1, @text)", new { nodeId=t.nodeId, versionId=Guid.NewGuid(), versionDate=t.updateDate, userId=t.documentUser, text=t.text });
|
||||
var id = Database.ExecuteScalar<int>("SELECT " + getIdentity);
|
||||
Database.Execute($"UPDATE {SqlSyntax.GetQuotedTableName(PreTables.ContentVersion)} SET {SqlSyntax.GetQuotedColumnName("current")}=0 WHERE nodeId=@0 AND id<>@1", (int) t.nodeId, id);
|
||||
Database.Execute($@"INSERT INTO {SqlSyntax.GetQuotedTableName(Constants.DatabaseSchema.Tables.DocumentVersion)} (id, templateId, published)
|
||||
VALUES (@id, @templateId, 0)", new { id=id, templateId=t.templateId });
|
||||
|
||||
var versionId = (int) t.versionId;
|
||||
var pdatas = Database.Fetch<PropertyDataDto>(Sql().Select<PropertyDataDto>().From<PropertyDataDto>().Where<PropertyDataDto>(x => x.VersionId == versionId));
|
||||
foreach (var pdata in pdatas)
|
||||
{
|
||||
pdata.VersionId = id;
|
||||
Database.Insert(pdata);
|
||||
}
|
||||
}
|
||||
Database.Execute($@"
|
||||
INSERT INTO {SqlSyntax.GetQuotedTableName(Constants.DatabaseSchema.Tables.DocumentVersion)} (id, templateId, published)
|
||||
SELECT cverNew.id, doc.templateId, 0
|
||||
FROM {SqlSyntax.GetQuotedTableName(PreTables.Document)} doc
|
||||
JOIN {SqlSyntax.GetQuotedTableName(PreTables.ContentVersion)} cverNew ON doc.nodeId = cverNew.nodeId
|
||||
WHERE doc.newest=1 AND doc.published=1 AND cverNew.{SqlSyntax.GetQuotedColumnName("current")} = 1");
|
||||
|
||||
Database.Execute($@"
|
||||
INSERT INTO {SqlSyntax.GetQuotedTableName(PropertyDataDto.TableName)} (propertytypeid,languageId,segment,textValue,varcharValue,decimalValue,intValue,dateValue,versionId)
|
||||
SELECT propertytypeid,languageId,segment,textValue,varcharValue,decimalValue,intValue,dateValue,cverNew.id
|
||||
FROM {SqlSyntax.GetQuotedTableName(PreTables.Document)} doc
|
||||
JOIN {SqlSyntax.GetQuotedTableName(PreTables.ContentVersion)} cver ON doc.nodeId=cver.nodeId AND doc.versionId=cver.versionId
|
||||
JOIN {SqlSyntax.GetQuotedTableName(PreTables.ContentVersion)} cverNew ON doc.nodeId = cverNew.nodeId
|
||||
JOIN {SqlSyntax.GetQuotedTableName(PropertyDataDto.TableName)} pd ON pd.versionId=cver.id
|
||||
WHERE doc.newest=1 AND doc.published=1 AND cverNew.{SqlSyntax.GetQuotedColumnName("current")} = 1");
|
||||
|
||||
|
||||
// reduce document to 1 row per content
|
||||
Database.Execute($@"DELETE FROM {PreTables.Document}
|
||||
WHERE versionId NOT IN (SELECT (versionId) FROM {PreTables.ContentVersion} WHERE {SqlSyntax.GetQuotedColumnName("current")} = 1) AND (published<>1 OR newest<>1)");
|
||||
|
||||
// ensure that documents with a published version are marked as published
|
||||
Database.Execute($@"UPDATE {PreTables.Document} SET published=1 WHERE nodeId IN (
|
||||
SELECT nodeId FROM {PreTables.ContentVersion} cv INNER JOIN {Constants.DatabaseSchema.Tables.DocumentVersion} dv ON dv.id = cv.id WHERE dv.published=1)");
|
||||
|
||||
// drop some document columns
|
||||
Delete.Column("text").FromTable(PreTables.Document).Do();
|
||||
Delete.Column("templateId").FromTable(PreTables.Document).Do();
|
||||
@@ -223,7 +275,7 @@ WHERE versionId NOT IN (SELECT (versionId) FROM {PreTables.ContentVersion} WHERE
|
||||
if (!ColumnExists(PreTables.Document, "edited"))
|
||||
{
|
||||
AddColumn<DocumentDto>(PreTables.Document, "edited", out var sqls);
|
||||
Database.Execute($"UPDATE {SqlSyntax.GetQuotedTableName(PreTables.Document)} SET edited=0");
|
||||
Database.Execute($"UPDATE {SqlSyntax.GetQuotedTableName(PreTables.Document)} SET edited=~published");
|
||||
foreach (var sql in sqls) Database.Execute(sql);
|
||||
}
|
||||
|
||||
@@ -240,11 +292,15 @@ JOIN {Constants.DatabaseSchema.Tables.PropertyData} v1 ON cv1.id=v1.versionId
|
||||
JOIN {PreTables.ContentVersion} cv2 ON n.id=cv2.nodeId
|
||||
JOIN {Constants.DatabaseSchema.Tables.DocumentVersion} dv ON cv2.id=dv.id AND dv.published=1
|
||||
JOIN {Constants.DatabaseSchema.Tables.PropertyData} v2 ON cv2.id=v2.versionId
|
||||
WHERE v1.propertyTypeId=v2.propertyTypeId AND v1.languageId=v2.languageId AND v1.segment=v2.segment");
|
||||
WHERE v1.propertyTypeId=v2.propertyTypeId
|
||||
AND (v1.languageId=v2.languageId OR (v1.languageId IS NULL AND v2.languageId IS NULL))
|
||||
AND (v1.segment=v2.segment OR (v1.segment IS NULL AND v2.segment IS NULL))");
|
||||
|
||||
var updatedIds = new HashSet<int>();
|
||||
foreach (var t in temp)
|
||||
if (t.intValue1 != t.intValue2 || t.decimalValue1 != t.decimalValue2 || t.dateValue1 != t.dateValue2 || t.varcharValue1 != t.varcharValue2 || t.textValue1 != t.textValue2)
|
||||
Database.Execute("UPDATE {SqlSyntax.GetQuotedTableName(PreTables.Document)} SET edited=1 WHERE nodeId=@nodeIdd", new { t.id });
|
||||
if (updatedIds.Add((int)t.id))
|
||||
Database.Execute($"UPDATE {SqlSyntax.GetQuotedTableName(PreTables.Document)} SET edited=1 WHERE nodeId=@nodeId", new { nodeId = t.id });
|
||||
|
||||
// drop more columns
|
||||
Delete.Column("versionId").FromTable(PreTables.ContentVersion).Do();
|
||||
|
||||
+23
-10
@@ -5,6 +5,7 @@ using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Migrations.PostMigrations;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_0_0.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Services;
|
||||
@@ -27,15 +28,15 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
var sqlPropertyData = Sql()
|
||||
.Select<PropertyDataDto>(r => r.Select(x => x.PropertyTypeDto, r1 => r1.Select(x => x.DataTypeDto)))
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<PropertyTypeDto>().On<PropertyDataDto, PropertyTypeDto>((left, right) => left.PropertyTypeId == right.Id)
|
||||
.InnerJoin<DataTypeDto>().On<PropertyTypeDto, DataTypeDto>((left, right) => left.DataTypeId == right.NodeId)
|
||||
.Select<PropertyDataDto80>(r => r.Select(x => x.PropertyTypeDto, r1 => r1.Select(x => x.DataTypeDto)))
|
||||
.From<PropertyDataDto80>()
|
||||
.InnerJoin<PropertyTypeDto80>().On<PropertyDataDto80, PropertyTypeDto80>((left, right) => left.PropertyTypeId == right.Id)
|
||||
.InnerJoin<DataTypeDto>().On<PropertyTypeDto80, DataTypeDto>((left, right) => left.DataTypeId == right.NodeId)
|
||||
.Where<DataTypeDto>(x =>
|
||||
x.EditorAlias == Constants.PropertyEditors.Aliases.TinyMce ||
|
||||
x.EditorAlias == Constants.PropertyEditors.Aliases.Grid);
|
||||
|
||||
var properties = Database.Fetch<PropertyDataDto>(sqlPropertyData);
|
||||
var properties = Database.Fetch<PropertyDataDto80>(sqlPropertyData);
|
||||
|
||||
var exceptions = new List<Exception>();
|
||||
foreach (var property in properties)
|
||||
@@ -43,6 +44,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
|
||||
var value = property.TextValue;
|
||||
if (string.IsNullOrWhiteSpace(value)) continue;
|
||||
|
||||
|
||||
bool propertyChanged = false;
|
||||
if (property.PropertyTypeDto.DataTypeDto.EditorAlias == Constants.PropertyEditors.Aliases.Grid)
|
||||
{
|
||||
try
|
||||
@@ -55,7 +58,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
|
||||
var controlValue = control["value"];
|
||||
if (controlValue?.Type == JTokenType.String)
|
||||
{
|
||||
control["value"] = UpdateMediaUrls(mediaLinkPattern, controlValue.Value<string>());
|
||||
control["value"] = UpdateMediaUrls(mediaLinkPattern, controlValue.Value<string>(), out var controlChanged);
|
||||
propertyChanged |= controlChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,10 +80,11 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
|
||||
}
|
||||
else
|
||||
{
|
||||
property.TextValue = UpdateMediaUrls(mediaLinkPattern, value);
|
||||
property.TextValue = UpdateMediaUrls(mediaLinkPattern, value, out propertyChanged);
|
||||
}
|
||||
|
||||
Database.Update(property);
|
||||
if (propertyChanged)
|
||||
Database.Update(property);
|
||||
}
|
||||
|
||||
|
||||
@@ -91,10 +96,14 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
|
||||
Context.AddPostMigration<RebuildPublishedSnapshot>();
|
||||
}
|
||||
|
||||
private string UpdateMediaUrls(Regex mediaLinkPattern, string value)
|
||||
private string UpdateMediaUrls(Regex mediaLinkPattern, string value, out bool changed)
|
||||
{
|
||||
return mediaLinkPattern.Replace(value, match =>
|
||||
bool matched = false;
|
||||
|
||||
var result = mediaLinkPattern.Replace(value, match =>
|
||||
{
|
||||
matched = true;
|
||||
|
||||
// match groups:
|
||||
// - 1 = from the beginning of the a tag until href attribute value begins
|
||||
// - 2 = the href attribute value excluding the querystring (if present)
|
||||
@@ -106,6 +115,10 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
|
||||
? match.Value
|
||||
: $"{match.Groups[1].Value}/{{localLink:{media.GetUdi()}}}{match.Groups[3].Value}";
|
||||
});
|
||||
|
||||
changed = matched;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-9
@@ -4,21 +4,30 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_6_0
|
||||
{
|
||||
public class MissingContentVersionsIndexes : MigrationBase
|
||||
{
|
||||
private const string IndexName = "IX_" + ContentVersionDto.TableName + "_NodeId";
|
||||
|
||||
public MissingContentVersionsIndexes(IMigrationContext context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
Create
|
||||
.Index("IX_" + ContentVersionDto.TableName + "_NodeId")
|
||||
.OnTable(ContentVersionDto.TableName)
|
||||
.OnColumn("nodeId")
|
||||
.Ascending()
|
||||
.OnColumn("current")
|
||||
.Ascending()
|
||||
.WithOptions().NonClustered()
|
||||
.Do();
|
||||
// We must check before we create an index because if we are upgrading from v7 we force re-create all
|
||||
// indexes in the whole DB and then this would throw
|
||||
|
||||
if (!IndexExists(IndexName))
|
||||
{
|
||||
Create
|
||||
.Index(IndexName)
|
||||
.OnTable(ContentVersionDto.TableName)
|
||||
.OnColumn("nodeId")
|
||||
.Ascending()
|
||||
.OnColumn("current")
|
||||
.Ascending()
|
||||
.WithOptions().NonClustered()
|
||||
.Do();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@ using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Dtos
|
||||
{
|
||||
[TableName(Constants.DatabaseSchema.Tables.DictionaryEntry)]
|
||||
[TableName(TableName)]
|
||||
[PrimaryKey("pk")]
|
||||
[ExplicitColumns]
|
||||
internal class DictionaryDto
|
||||
{
|
||||
public const string TableName = Constants.DatabaseSchema.Tables.DictionaryEntry;
|
||||
[Column("pk")]
|
||||
[PrimaryKeyColumn]
|
||||
public int PrimaryKey { get; set; }
|
||||
@@ -21,6 +22,7 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
[Column("parent")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[ForeignKey(typeof(DictionaryDto), Column = "id")]
|
||||
[Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_Parent")]
|
||||
public Guid? Parent { get; set; }
|
||||
|
||||
[Column("key")]
|
||||
|
||||
+3
-3
@@ -15221,9 +15221,9 @@
|
||||
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
|
||||
},
|
||||
"tinymce": {
|
||||
"version": "4.9.2",
|
||||
"resolved": "https://registry.npmjs.org/tinymce/-/tinymce-4.9.2.tgz",
|
||||
"integrity": "sha512-ZRoTGG4GAsOI73QPSNkabO7nkoYw9H6cglRB44W2mMkxSiqxYi8WJlgkUphk0fDqo6ZD6r3E+NSP4UHxF2lySg=="
|
||||
"version": "4.9.7",
|
||||
"resolved": "https://registry.npmjs.org/tinymce/-/tinymce-4.9.7.tgz",
|
||||
"integrity": "sha512-cj0HvUuniTuIjOAJdRt5BUfeQqM5yHjbA2NOub9HUHXlCrT9OwD9WBPU6tGlaPC2l2I4eGoOnT8llosZRdQU5Q=="
|
||||
},
|
||||
"tmp": {
|
||||
"version": "0.0.33",
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
"npm": "6.13.6",
|
||||
"signalr": "2.4.0",
|
||||
"spectrum-colorpicker": "1.8.0",
|
||||
"tinymce": "4.9.2",
|
||||
"tinymce": "4.9.7",
|
||||
"typeahead.js": "0.11.1",
|
||||
"underscore": "1.9.1"
|
||||
},
|
||||
|
||||
+1
@@ -130,6 +130,7 @@
|
||||
view: "default",
|
||||
content: labels.doctypeChangeWarning,
|
||||
submitButtonLabelKey: "general_continue",
|
||||
submitButtonStyle: "warning",
|
||||
closeButtonLabelKey: "general_cancel",
|
||||
submit: function () {
|
||||
openDocTypeEditor(documentType);
|
||||
|
||||
+3
-3
@@ -58,9 +58,9 @@
|
||||
/** Called when the component has linked all elements, this is when the form controller is available */
|
||||
function postLink() {
|
||||
//set the content to dirty if the header changes
|
||||
unsubscribe.push($scope.$watch("contentHeaderForm.$dirty",
|
||||
function(newValue, oldValue) {
|
||||
if (newValue === true) {
|
||||
unsubscribe.push($scope.$watch("vm.editor.content.name",
|
||||
function (newValue, oldValue) {
|
||||
if (newValue !== oldValue) {
|
||||
vm.editor.content.isDirty = true;
|
||||
}
|
||||
}));
|
||||
|
||||
+2
-1
@@ -14,7 +14,8 @@ function treeSearchBox(localizationService, searchService, $q) {
|
||||
section: "@",
|
||||
datatypeKey: "@",
|
||||
hideSearchCallback: "=",
|
||||
searchCallback: "="
|
||||
searchCallback: "=",
|
||||
autoFocus: "="
|
||||
},
|
||||
restrict: "E", // restrict to an element
|
||||
replace: true, // replace the html element with the template
|
||||
|
||||
@@ -308,6 +308,8 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
var src = imgUrl + "?width=" + newSize.width + "&height=" + newSize.height;
|
||||
editor.dom.setAttrib(imageDomElement, 'data-mce-src', src);
|
||||
}
|
||||
|
||||
editor.execCommand("mceAutoResize", false, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -672,7 +672,8 @@
|
||||
}
|
||||
|
||||
.imagecropper .umb-sortable-thumbnails li .crop-name,
|
||||
.imagecropper .umb-sortable-thumbnails li .crop-size {
|
||||
.imagecropper .umb-sortable-thumbnails li .crop-size,
|
||||
.imagecropper .umb-sortable-thumbnails li .crop-annotation {
|
||||
display: block;
|
||||
text-align: left;
|
||||
font-size: 13px;
|
||||
@@ -684,17 +685,28 @@
|
||||
margin: 10px 0 5px;
|
||||
}
|
||||
|
||||
.imagecropper .umb-sortable-thumbnails li .crop-size {
|
||||
.imagecropper .umb-sortable-thumbnails li .crop-size,
|
||||
.imagecropper .umb-sortable-thumbnails li .crop-annotation {
|
||||
font-size: 10px;
|
||||
font-style: italic;
|
||||
margin: 0 0 5px;
|
||||
}
|
||||
|
||||
.imagecropper .umb-sortable-thumbnails li .crop-annotation {
|
||||
color: @gray-6;
|
||||
}
|
||||
|
||||
.btn-crop-delete {
|
||||
display: block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.imagecropper .cropList-container {
|
||||
h5 {
|
||||
margin-left: 10px;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
//
|
||||
// folder-browser
|
||||
// --------------------------------------------------
|
||||
|
||||
+7
-6
@@ -16,7 +16,7 @@ function IconPickerController($scope, iconHelper, localizationService) {
|
||||
vm.close = close;
|
||||
|
||||
vm.colors = [
|
||||
{ name: "Black", value: "color-black" },
|
||||
{ name: "Black", value: "color-black", default: true },
|
||||
{ name: "Blue Grey", value: "color-blue-grey" },
|
||||
{ name: "Grey", value: "color-grey" },
|
||||
{ name: "Brown", value: "color-brown" },
|
||||
@@ -49,7 +49,7 @@ function IconPickerController($scope, iconHelper, localizationService) {
|
||||
});
|
||||
|
||||
// set a default color if nothing is passed in
|
||||
vm.color = $scope.model.color ? findColor($scope.model.color) : vm.colors[0];
|
||||
vm.color = $scope.model.color ? findColor($scope.model.color) : vm.colors.find(x => x.default);
|
||||
|
||||
// if an icon is passed in - preselect it
|
||||
vm.icon = $scope.model.icon ? $scope.model.icon : undefined;
|
||||
@@ -71,12 +71,13 @@ function IconPickerController($scope, iconHelper, localizationService) {
|
||||
}
|
||||
|
||||
function findColor(value) {
|
||||
return _.findWhere(vm.colors, {value: value});
|
||||
return vm.colors.find(x => x.value === value);
|
||||
}
|
||||
|
||||
function selectColor(color, $index, $event) {
|
||||
$scope.model.color = color.value;
|
||||
vm.color = color;
|
||||
function selectColor(color) {
|
||||
let newColor = (color || vm.colors.find(x => x.default));
|
||||
$scope.model.color = newColor.value;
|
||||
vm.color = newColor;
|
||||
}
|
||||
|
||||
function close() {
|
||||
|
||||
+8
-2
@@ -1,7 +1,7 @@
|
||||
//used for the media picker dialog
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Editors.MediaPickerController",
|
||||
function ($scope, $timeout, mediaResource, entityResource, userService, mediaHelper, mediaTypeHelper, eventsService, treeService, localStorageService, localizationService) {
|
||||
function ($scope, mediaResource, entityResource, userService, mediaHelper, mediaTypeHelper, eventsService, treeService, localStorageService, localizationService, editorService, umbSessionStorage) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -37,6 +37,11 @@ angular.module("umbraco")
|
||||
$scope.cropSize = dialogOptions.cropSize;
|
||||
$scope.lastOpenedNode = localStorageService.get("umbLastOpenedMediaNodeId");
|
||||
$scope.lockedFolder = true;
|
||||
$scope.allowMediaEdit = dialogOptions.allowMediaEdit ? dialogOptions.allowMediaEdit : false;
|
||||
|
||||
$scope.filterOptions = {
|
||||
excludeSubFolders: umbSessionStorage.get("mediaPickerExcludeSubFolders") || false
|
||||
};
|
||||
|
||||
var userStartNodes = [];
|
||||
|
||||
@@ -392,6 +397,7 @@ angular.module("umbraco")
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
umbSessionStorage.set("mediaPickerExcludeSubFolders", $scope.filterOptions.excludeSubFolders);
|
||||
// Make sure to activate the changeSearch function everytime the toggle is clicked
|
||||
changeSearch();
|
||||
}
|
||||
@@ -404,7 +410,7 @@ angular.module("umbraco")
|
||||
|
||||
function searchMedia() {
|
||||
vm.loading = true;
|
||||
entityResource.getPagedDescendants($scope.currentFolder.id, "Media", vm.searchOptions)
|
||||
entityResource.getPagedDescendants($scope.filterOptions.excludeSubFolders ? $scope.currentFolder.id : $scope.startNodeId, "Media", vm.searchOptions)
|
||||
.then(function (data) {
|
||||
// update image data to work with image grid
|
||||
angular.forEach(data.items, function (mediaItem) {
|
||||
|
||||
+4
-5
@@ -32,10 +32,10 @@
|
||||
|
||||
<div class="form-search__toggle">
|
||||
<umb-checkbox
|
||||
model="showChilds"
|
||||
model="filterOptions.excludeSubFolders"
|
||||
on-change="vm.toggle()"
|
||||
text="Include subfolders in search"
|
||||
label-key="general_includeFromsubFolders">
|
||||
label-key="general_excludeFromSubFolders">
|
||||
</umb-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
@@ -112,9 +112,8 @@
|
||||
disable-folder-select={{disableFolderSelect}}
|
||||
only-images={{onlyImages}}
|
||||
only-folders={{onlyFolders}}
|
||||
include-sub-folders={{showChilds}}
|
||||
current-folder-id="{{currentFolder.id}}"
|
||||
allow-open-folder="!disableFolderSelect">
|
||||
include-sub-folders={{!filterOptions.excludeSubFolders}}
|
||||
current-folder-id="{{currentFolder.id}}">
|
||||
</umb-media-grid>
|
||||
|
||||
|
||||
|
||||
+9
@@ -64,6 +64,8 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController",
|
||||
|
||||
var currentNode = $scope.model.currentNode;
|
||||
|
||||
var previouslyFocusedElement = null;
|
||||
|
||||
function initDialogTree() {
|
||||
vm.dialogTreeApi.callbacks.treeLoaded(treeLoadedHandler);
|
||||
// TODO: Also deal with unexpanding!!
|
||||
@@ -487,6 +489,7 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController",
|
||||
}
|
||||
|
||||
function openMiniListView(node) {
|
||||
previouslyFocusedElement = document.activeElement;
|
||||
vm.miniListView = node;
|
||||
}
|
||||
|
||||
@@ -650,6 +653,12 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController",
|
||||
|
||||
function closeMiniListView() {
|
||||
vm.miniListView = undefined;
|
||||
if (previouslyFocusedElement) {
|
||||
$timeout(function () {
|
||||
previouslyFocusedElement.focus();
|
||||
previouslyFocusedElement = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function listViewItemsLoaded(items) {
|
||||
|
||||
+2
-1
@@ -37,7 +37,8 @@
|
||||
search-from-name="{{vm.searchInfo.searchFromName}}"
|
||||
show-search="{{vm.searchInfo.showSearch}}"
|
||||
datatype-key="{{vm.searchInfo.dataTypeKey}}"
|
||||
section="{{vm.section}}">
|
||||
section="{{vm.section}}"
|
||||
auto-focus="true">
|
||||
</umb-tree-search-box>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
ng-model="term"
|
||||
class="umb-search-field search-query -full-width-input"
|
||||
placeholder="{{searchPlaceholderText}}"
|
||||
focus-when="{{showSearch}}">
|
||||
umb-auto-focus="{{autoFocus ? 'true' : 'false'}}">
|
||||
<h4 ng-if="showSearch && searchFromName">
|
||||
<small><localize key="general_search">Search</localize>: </small>
|
||||
{{searchFromName}}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
ng-model="search"
|
||||
ng-change="searchMiniListView(search, miniListView)"
|
||||
prevent-enter-submit
|
||||
umb-auto-focus
|
||||
no-dirty-check>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
<umb-load-indicator ng-if="vm.loading"></umb-load-indicator>
|
||||
|
||||
<div class="umb-pane" ng-show="!vm.loading">
|
||||
|
||||
<div class="umb-pane" ng-show="!vm.loading" role="dialog" aria-labelledby="content_rights_title" aria-describedby="content_rights_description">
|
||||
|
||||
<form name="permissionsForm">
|
||||
|
||||
<div ng-show="vm.saveError">
|
||||
@@ -23,8 +23,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5><localize key="defaultdialogs_permissionsSet">Set permissions for</localize> {{ currentNode.name }}</h5>
|
||||
<p class="abstract" style="margin-bottom: 20px;"><localize key="defaultdialogs_permissionsHelp"></localize></p>
|
||||
<h5 id="content_rights_title"><localize key="defaultdialogs_permissionsSet">Set permissions for</localize> {{ currentNode.name }}</h5>
|
||||
<p id="content_rights_description" class="abstract" style="margin-bottom: 20px;"><localize key="defaultdialogs_permissionsHelp"></localize></p>
|
||||
|
||||
<div style="position: relative; display: inline-block; margin-bottom: 20px;">
|
||||
<umb-button
|
||||
|
||||
+5
@@ -13,6 +13,7 @@ angular.module('umbraco')
|
||||
$scope.clear = clear;
|
||||
$scope.reset = reset;
|
||||
$scope.close = close;
|
||||
$scope.isCustomCrop = isCustomCrop;
|
||||
$scope.focalPointChanged = focalPointChanged;
|
||||
//declare a special method which will be called whenever the value has changed from the server
|
||||
$scope.model.onValueChanged = onValueChanged;
|
||||
@@ -201,6 +202,10 @@ angular.module('umbraco')
|
||||
$scope.imageCropperForm.$setDirty();
|
||||
};
|
||||
|
||||
function isCustomCrop(crop) {
|
||||
return !!crop.coordinates;
|
||||
}
|
||||
|
||||
var unsubscribe = $scope.$on("formSubmitting", function () {
|
||||
$scope.currentCrop = null;
|
||||
$scope.currentPoint = null;
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
<div class="crop-information">
|
||||
<span class="crop-name crop-text">{{value.alias}}</span>
|
||||
<span class="crop-size crop-text">{{value.width}}px x {{value.height}}px</span>
|
||||
<span class="crop-annotation crop-text"><localize key="imagecropper_customCrop" ng-show="isCustomCrop(value)">User defined</localize> </span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -661,7 +661,7 @@
|
||||
<key alias="icon">Ikon</key>
|
||||
<key alias="id">Id</key>
|
||||
<key alias="import">Importer</key>
|
||||
<key alias="includeFromsubFolders">Inkludér undermapper i søgning</key>
|
||||
<key alias="excludeFromSubFolders">Søg kun i denne mappe</key>
|
||||
<key alias="info">Info</key>
|
||||
<key alias="innerMargin">Indre margen</key>
|
||||
<key alias="insert">Indsæt</key>
|
||||
@@ -1086,6 +1086,7 @@ Mange hilsner fra Umbraco robotten
|
||||
<key alias="addCrop">Tilføj ny beskæring</key>
|
||||
<key alias="updateEditCrop">Acceptér</key>
|
||||
<key alias="undoEditCrop">Fortryd</key>
|
||||
<key alias="customCrop">Brugerdefineret</key>
|
||||
</area>
|
||||
<area alias="rollback">
|
||||
<key alias="headline">Vælg en version at sammenligne med den nuværende version</key>
|
||||
|
||||
@@ -674,7 +674,7 @@
|
||||
<key alias="icon">Icon</key>
|
||||
<key alias="id">Id</key>
|
||||
<key alias="import">Import</key>
|
||||
<key alias="includeFromsubFolders">Include subfolders in search</key>
|
||||
<key alias="excludeFromSubFolders">Search only this folder</key>
|
||||
<key alias="info">Info</key>
|
||||
<key alias="innerMargin">Inner margin</key>
|
||||
<key alias="insert">Insert</key>
|
||||
@@ -1318,6 +1318,7 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="addCrop">Add new crop</key>
|
||||
<key alias="updateEditCrop">Done</key>
|
||||
<key alias="undoEditCrop">Undo edits</key>
|
||||
<key alias="customCrop">User defined</key>
|
||||
</area>
|
||||
<area alias="rollback">
|
||||
<key alias="headline">Select a version to compare with the current version</key>
|
||||
|
||||
@@ -676,7 +676,7 @@
|
||||
<key alias="icon">Icon</key>
|
||||
<key alias="id">Id</key>
|
||||
<key alias="import">Import</key>
|
||||
<key alias="includeFromsubFolders">Include subfolders in search</key>
|
||||
<key alias="excludeFromSubFolders">Search only this folder</key>
|
||||
<key alias="info">Info</key>
|
||||
<key alias="innerMargin">Inner margin</key>
|
||||
<key alias="insert">Insert</key>
|
||||
@@ -1316,11 +1316,12 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="externalLinkPlaceholder">Enter the link</key>
|
||||
</area>
|
||||
<area alias="imagecropper">
|
||||
<key alias="reset">Reset crop</key>
|
||||
<key alias="reset">Reset crop</key>
|
||||
<key alias="saveCrop">Save crop</key>
|
||||
<key alias="addCrop">Add new crop</key>
|
||||
<key alias="updateEditCrop">Done</key>
|
||||
<key alias="undoEditCrop">Undo edits</key>
|
||||
<key alias="updateEditCrop">Done</key>
|
||||
<key alias="undoEditCrop">Undo edits</key>
|
||||
<key alias="customCrop">User defined</key>
|
||||
</area>
|
||||
<area alias="rollback">
|
||||
<key alias="headline">Select a version to compare with the current version</key>
|
||||
|
||||
@@ -241,6 +241,14 @@
|
||||
By default you can call any content Id in the url and show the content with that id, for example:
|
||||
http://mysite.com/1092 or http://mysite.com/1092.aspx would render the content with id 1092. Setting
|
||||
this setting to true stops that behavior
|
||||
@disableRedirectUrlTracking
|
||||
When the URL changes for content, redirects are automatically created for redirect handling within the
|
||||
request pipeline. Setting this setting to true stops the automatic creation of redirects. Note that this
|
||||
does not stop the request pipeline from handling any previously created redirects.
|
||||
@urlProviderMode
|
||||
By default Umbraco automatically figures out if internal URLs should be rendered as relative or absolute,
|
||||
depending on the current request and the configured domains. By setting this setting to "Relative" or
|
||||
"Absolute" you can force Umbraco to always render URLs as either relative or absolute.
|
||||
@umbracoApplicationUrl
|
||||
The url of the Umbraco application. By default, Umbraco will figure it out from the first request.
|
||||
Configure it here if you need anything specific. Needs to be a complete url with scheme and umbraco
|
||||
|
||||
@@ -197,7 +197,9 @@ namespace Umbraco.Web.Editors
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
var template = Services.FileService.CreateTemplateWithIdentity(display.Name, display.Alias, display.Content, master);
|
||||
// we need to pass the template name as alias to keep the template file casing consistent with templates created with content
|
||||
// - see comment in FileService.CreateTemplateForContentType for additional details
|
||||
var template = Services.FileService.CreateTemplateWithIdentity(display.Name, display.Name, display.Content, master);
|
||||
Mapper.Map(template, display);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
using System.Web.UI;
|
||||
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
/// <summary>
|
||||
/// A formless page for use with the rendering a control in a page via Server.Execute.
|
||||
/// This ignores the check to check for a form control on the page.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// UmbracoHelper currently uses this for rendering macros but could be used anywhere we want when rendering
|
||||
/// a page with Server.Execute.
|
||||
/// SD: I have a custom MVC engine that uses this in my own internal libs if we want to pull it out which is called ViewManager
|
||||
/// and works really well for things like this.
|
||||
/// </remarks>
|
||||
internal class FormlessPage : Page
|
||||
{
|
||||
public override void VerifyRenderingInServerForm(Control control) { }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.Icon = source.ContentType.Icon;
|
||||
target.Id = source.Id;
|
||||
target.IsBlueprint = source.Blueprint;
|
||||
target.IsChildOfListView = DermineIsChildOfListView(source);
|
||||
target.IsChildOfListView = DetermineIsChildOfListView(source);
|
||||
target.IsContainer = source.ContentType.IsContainer;
|
||||
target.IsElement = source.ContentType.IsElement;
|
||||
target.Key = source.Key;
|
||||
@@ -217,7 +217,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
return source.CultureInfos.TryGetValue(culture, out var name) && !name.Name.IsNullOrWhiteSpace() ? name.Name : $"({source.Name})";
|
||||
}
|
||||
|
||||
private bool DermineIsChildOfListView(IContent source)
|
||||
private bool DetermineIsChildOfListView(IContent source)
|
||||
{
|
||||
// map the IsChildOfListView (this is actually if it is a descendant of a list view!)
|
||||
var parent = _contentService.GetParent(source);
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.CreateDate = source.CreateDate;
|
||||
target.Icon = source.ContentType.Icon;
|
||||
target.Id = source.Id;
|
||||
target.IsChildOfListView = DermineIsChildOfListView(source);
|
||||
target.IsChildOfListView = DetermineIsChildOfListView(source);
|
||||
target.Key = source.Key;
|
||||
target.MediaLink = string.Join(",", source.GetUrls(_umbracoSettingsSection.Content, _logger, _propertyEditorCollection));
|
||||
target.Name = source.Name;
|
||||
@@ -101,7 +101,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.VariesByCulture = source.ContentType.VariesByCulture();
|
||||
}
|
||||
|
||||
private bool DermineIsChildOfListView(IMedia source)
|
||||
private bool DetermineIsChildOfListView(IMedia source)
|
||||
{
|
||||
// map the IsChildOfListView (this is actually if it is a descendant of a list view!)
|
||||
var parent = _mediaService.GetParent(source);
|
||||
|
||||
@@ -114,6 +114,19 @@ namespace Umbraco.Web.Security
|
||||
return SignInStatus.LockedOut;
|
||||
}
|
||||
|
||||
// We need to verify that the user belongs to one or more groups that define content and media start nodes.
|
||||
// To do so we have to create the user claims identity and validate the calculated start nodes.
|
||||
var userIdentity = await CreateUserIdentityAsync(user);
|
||||
if (userIdentity is UmbracoBackOfficeIdentity backOfficeIdentity)
|
||||
{
|
||||
if (backOfficeIdentity.StartContentNodes.Length == 0 || backOfficeIdentity.StartMediaNodes.Length == 0)
|
||||
{
|
||||
_logger.WriteCore(TraceEventType.Information, 0,
|
||||
$"Login attempt failed for username {userName} from IP address {_request.RemoteIpAddress}, no content and/or media start nodes could be found for any of the user's groups", null, null);
|
||||
return SignInStatus.Failure;
|
||||
}
|
||||
}
|
||||
|
||||
await UserManager.ResetAccessFailedCountAsync(user.Id);
|
||||
return await SignInOrTwoFactor(user, isPersistent);
|
||||
}
|
||||
|
||||
@@ -13,14 +13,10 @@ namespace Umbraco.Web.Templates
|
||||
this._getMediaUrl = getMediaUrl;
|
||||
}
|
||||
|
||||
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
|
||||
public HtmlImageSourceParser(IUmbracoContextAccessor umbracoContextAccessor)
|
||||
{
|
||||
if (umbracoContextAccessor?.UmbracoContext?.UrlProvider == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_getMediaUrl = (guid) => umbracoContextAccessor.UmbracoContext.UrlProvider.GetMediaUrl(guid);
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
}
|
||||
|
||||
private static readonly Regex ResolveImgPattern = new Regex(@"(<img[^>]*src="")([^""\?]*)((?:\?[^""]*)?""[^>]*data-udi="")([^""]*)(""[^>]*>)",
|
||||
@@ -29,7 +25,7 @@ namespace Umbraco.Web.Templates
|
||||
private static readonly Regex DataUdiAttributeRegex = new Regex(@"data-udi=\\?(?:""|')(?<udi>umb://[A-z0-9\-]+/[A-z0-9]+)\\?(?:""|')",
|
||||
RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
|
||||
|
||||
private readonly Func<Guid, string> _getMediaUrl;
|
||||
private Func<Guid, string> _getMediaUrl;
|
||||
|
||||
/// <summary>
|
||||
/// Parses out media UDIs from an html string based on 'data-udi' html attributes
|
||||
@@ -57,12 +53,8 @@ namespace Umbraco.Web.Templates
|
||||
/// <remarks>Umbraco image tags are identified by their data-udi attributes</remarks>
|
||||
public string EnsureImageSources(string text)
|
||||
{
|
||||
// no point in doing any processing if we don't have
|
||||
// a function to retrieve Urls
|
||||
if (_getMediaUrl == null)
|
||||
{
|
||||
return text;
|
||||
}
|
||||
if(_getMediaUrl == null)
|
||||
_getMediaUrl = (guid) => _umbracoContextAccessor.UmbracoContext.UrlProvider.GetMediaUrl(guid);
|
||||
|
||||
return ResolveImgPattern.Replace(text, match =>
|
||||
{
|
||||
|
||||
@@ -644,9 +644,6 @@
|
||||
<Compile Include="Mvc\UmbracoViewPageOfTModel.cs" />
|
||||
<Compile Include="PublishedContentExtensions.cs" />
|
||||
<Compile Include="ExamineExtensions.cs" />
|
||||
<Compile Include="FormlessPage.cs">
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Compile>
|
||||
<Compile Include="HtmlHelperRenderExtensions.cs" />
|
||||
<Compile Include="Scheduling\SchedulerComponent.cs" />
|
||||
<Compile Include="ModelStateExtensions.cs" />
|
||||
|
||||
Reference in New Issue
Block a user