Compare commits

..

8 Commits

Author SHA1 Message Date
Warren Buckley f40b802523 Revert change to en_us.xml 2019-07-03 10:24:25 +01:00
Warren Buckley d8157f2599 Revert "Fix line endings - according to VS19"
This reverts commit 4ebc2d7c29.
2019-07-03 10:23:18 +01:00
Warren Buckley 4ebc2d7c29 Fix line endings - according to VS19 2019-07-03 10:19:54 +01:00
Warren Buckley 7c0933c50b Add margin-right to trash icon next to copy/text 2019-07-03 09:57:22 +01:00
Warren Buckley 90a8c2d2c9 Add in language keys 2019-07-03 09:57:01 +01:00
Warren Buckley 58e241b6cb Add in trash icon & apply correct color from variables 2019-07-03 09:23:19 +01:00
Warren Buckley 69f85926d2 Merge branch 'v8/dev' into v8/feature/recycle-bin-context-message 2019-07-03 09:13:10 +01:00
Warren Buckley 91743833f5 Add a message bar to give context that this node/content item is in the trash/recycle bin 2019-07-02 16:44:07 +01:00
192 changed files with 5220 additions and 4280 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ thoroughly. Then, proceed by filling out the rest of the details in the issue
template below. The more details you can give us, the easier it will be for us
to determine the cause of a problem.
See: https://github.com/umbraco/Umbraco-CMS/blob/v8/dev/.github/CONTRIBUTING.md
See: https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/.github/CONTRIBUTING.md
-->
+2 -2
View File
@@ -18,5 +18,5 @@ using System.Resources;
[assembly: AssemblyVersion("8.0.0")]
// these are FYI and changed automatically
[assembly: AssemblyFileVersion("8.2.0")]
[assembly: AssemblyInformationalVersion("8.2.0")]
[assembly: AssemblyFileVersion("8.1.0")]
[assembly: AssemblyInformationalVersion("8.1.0")]
+22 -25
View File
@@ -67,34 +67,31 @@ namespace Umbraco.Core
: new NamedSemaphoreReleaser(_semaphore2);
}
//NOTE: We don't use the "Async" part of this lock at all
//TODO: Remove this and rename this class something like SystemWideLock, then we can re-instate this logic if we ever need an Async lock again
public Task<IDisposable> LockAsync()
{
var wait = _semaphore != null
? _semaphore.WaitAsync()
: _semaphore2.WaitOneAsync();
//public Task<IDisposable> LockAsync()
//{
// var wait = _semaphore != null
// ? _semaphore.WaitAsync()
// : _semaphore2.WaitOneAsync();
return wait.IsCompleted
? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
: wait.ContinueWith((_, state) => (((AsyncLock) state).CreateReleaser()),
this, CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
// return wait.IsCompleted
// ? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
// : wait.ContinueWith((_, state) => (((AsyncLock) state).CreateReleaser()),
// this, CancellationToken.None,
// TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
//}
public Task<IDisposable> LockAsync(int millisecondsTimeout)
{
var wait = _semaphore != null
? _semaphore.WaitAsync(millisecondsTimeout)
: _semaphore2.WaitOneAsync(millisecondsTimeout);
//public Task<IDisposable> LockAsync(int millisecondsTimeout)
//{
// var wait = _semaphore != null
// ? _semaphore.WaitAsync(millisecondsTimeout)
// : _semaphore2.WaitOneAsync(millisecondsTimeout);
// return wait.IsCompleted
// ? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
// : wait.ContinueWith((_, state) => (((AsyncLock)state).CreateReleaser()),
// this, CancellationToken.None,
// TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
//}
return wait.IsCompleted
? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
: wait.ContinueWith((_, state) => (((AsyncLock)state).CreateReleaser()),
this, CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
public IDisposable Lock()
{
@@ -14,23 +14,6 @@ namespace Umbraco.Core
/// </summary>
public const string InternalGenericPropertiesPrefix = "_umb_";
public static class Legacy
{
public static class Aliases
{
public const string Textbox = "Umbraco.Textbox";
public const string Date = "Umbraco.Date";
public const string ContentPicker2 = "Umbraco.ContentPicker2";
public const string MediaPicker2 = "Umbraco.MediaPicker2";
public const string MemberPicker2 = "Umbraco.MemberPicker2";
public const string MultiNodeTreePicker2 = "Umbraco.MultiNodeTreePicker2";
public const string TextboxMultiple = "Umbraco.TextboxMultiple";
public const string RelatedLinks2 = "Umbraco.RelatedLinks2";
public const string RelatedLinks = "Umbraco.RelatedLinks";
}
}
/// <summary>
/// Defines Umbraco built-in property editor aliases.
/// </summary>
@@ -203,24 +186,6 @@ namespace Umbraco.Core
/// <remarks>Must be a valid <see cref="ValueTypes"/> value.</remarks>
public const string DataValueType = "umbracoDataValueType";
}
/// <summary>
/// Defines Umbraco's built-in property editor groups.
/// </summary>
public static class Groups
{
public const string Common = "Common";
public const string Lists = "Lists";
public const string Media = "Media";
public const string People = "People";
public const string Pickers = "Pickers";
public const string RichContent = "Rich Content";
}
}
}
}
+1 -2
View File
@@ -10,8 +10,6 @@ namespace Umbraco.Core
///</summary>
public static class EnumerableExtensions
{
internal static bool IsCollectionEmpty<T>(this IReadOnlyCollection<T> list) => list == null || list.Count == 0;
internal static bool HasDuplicates<T>(this IEnumerable<T> items, bool includeNull)
{
var hs = new HashSet<T>();
@@ -114,6 +112,7 @@ namespace Umbraco.Core
}
}
/// <summary>
/// Returns true if all items in the other collection exist in this collection
/// </summary>
+1 -6
View File
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Web.Hosting;
@@ -114,7 +113,7 @@ namespace Umbraco.Core
lock (_locko)
{
_logger.Debug<MainDom>("Signaled ({Signaled}) ({SignalSource})", _signaled ? "again" : "first", source);
_logger.Debug<MainDom>("Signaled {Signaled} ({SignalSource})", _signaled ? "(again)" : string.Empty, source);
if (_signaled) return;
if (_isMainDom == false) return; // probably not needed
_signaled = true;
@@ -172,7 +171,6 @@ namespace Umbraco.Core
// if more than 1 instance reach that point, one will get the lock
// and the other one will timeout, which is accepted
//TODO: This can throw a TimeoutException - in which case should this be in a try/finally to ensure the signal is always reset?
_asyncLocker = _asyncLock.Lock(LockTimeoutMilliseconds);
_isMainDom = true;
@@ -183,9 +181,6 @@ namespace Umbraco.Core
// which is accepted
_signal.Reset();
//WaitOneAsync (ext method) will wait for a signal without blocking the main thread, the waiting is done on a background thread
_signal.WaitOneAsync()
.ContinueWith(_ => OnSignal("signal"));
@@ -74,11 +74,6 @@ namespace Umbraco.Core.Migrations.Upgrade
throw new InvalidOperationException($"Version {currentVersion} cannot be migrated to {UmbracoVersion.SemanticVersion}."
+ $" Please upgrade first to at least {minVersion}.");
// Force versions between 7.14.*-7.15.* into into 7.14 initial state. Because there is no db-changes,
// and we don't want users to workaround my putting in version 7.14.0 them self.
if (minVersion <= currentVersion && currentVersion < new SemVersion(7, 16))
return GetInitState(minVersion);
// initial state is eg "{init-7.14.0}"
return GetInitState(currentVersion);
}
@@ -19,8 +19,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
var sqlDataTypes = Sql()
.Select<DataTypeDto>()
.From<DataTypeDto>()
.Where<DataTypeDto>(x => x.EditorAlias == Constants.PropertyEditors.Legacy.Aliases.RelatedLinks
|| x.EditorAlias == Constants.PropertyEditors.Legacy.Aliases.RelatedLinks2);
.Where<DataTypeDto>(x => x.EditorAlias == "Umbraco.RelatedLinks"
|| x.EditorAlias == "Umbraco.RelatedLinks2");
var dataTypes = Database.Fetch<DataTypeDto>(sqlDataTypes);
var dataTypeIds = dataTypes.Select(x => x.NodeId).ToList();
@@ -50,10 +50,10 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
var properties = Database.Fetch<PropertyDataDto>(sqlPropertyData);
// Create a Multi URL Picker datatype for the converted RelatedLinks data
foreach (var property in properties)
{
var value = property.Value?.ToString();
var value = property.Value.ToString();
if (string.IsNullOrWhiteSpace(value))
continue;
@@ -89,7 +89,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
Name = relatedLink.Caption,
Target = relatedLink.NewWindow ? "_blank" : null,
Udi = udi,
// Should only have a URL if it's an external link otherwise it wil be a UDI
// Should only have a URL if it's an external link otherwise it wil be a UDI
Url = relatedLink.IsInternal == false ? relatedLink.Link : null
};
@@ -103,7 +103,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
Database.Update(property);
}
}
}
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core.Composing;
@@ -19,18 +18,6 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
private readonly PropertyEditorCollection _propertyEditors;
private readonly ILogger _logger;
private static readonly ISet<string> LegacyAliases = new HashSet<string>()
{
Constants.PropertyEditors.Legacy.Aliases.Date,
Constants.PropertyEditors.Legacy.Aliases.Textbox,
Constants.PropertyEditors.Legacy.Aliases.ContentPicker2,
Constants.PropertyEditors.Legacy.Aliases.MediaPicker2,
Constants.PropertyEditors.Legacy.Aliases.MemberPicker2,
Constants.PropertyEditors.Legacy.Aliases.RelatedLinks2,
Constants.PropertyEditors.Legacy.Aliases.TextboxMultiple,
Constants.PropertyEditors.Legacy.Aliases.MultiNodeTreePicker2,
};
public DataTypeMigration(IMigrationContext context, PreValueMigratorCollection preValueMigrators, PropertyEditorCollection propertyEditors, ILogger logger)
: base(context)
{
@@ -83,23 +70,16 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
var newAlias = migrator.GetNewAlias(dataType.EditorAlias);
if (newAlias == null)
{
if (!LegacyAliases.Contains(dataType.EditorAlias))
{
_logger.Warn<DataTypeMigration>(
"Skipping validation of configuration for data type {NodeId} : {EditorAlias}."
+ " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, dataType.EditorAlias);
}
_logger.Warn<DataTypeMigration>("Skipping validation of configuration for data type {NodeId} : {EditorAlias}."
+ " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, dataType.EditorAlias);
}
else if (!_propertyEditors.TryGet(newAlias, out var propertyEditor))
{
if (!LegacyAliases.Contains(newAlias))
{
_logger.Warn<DataTypeMigration>("Skipping validation of configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})"
+ " because no property editor with that alias was found."
+ " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, newAlias, dataType.EditorAlias);
}
_logger.Warn<DataTypeMigration>("Skipping validation of configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})"
+ " because no property editor with that alias was found."
+ " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, newAlias, dataType.EditorAlias);
}
else
{
@@ -3,7 +3,7 @@
class ContentPickerPreValueMigrator : DefaultPreValueMigrator
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == Constants.PropertyEditors.Legacy.Aliases.ContentPicker2;
=> editorAlias == "Umbraco.ContentPicker2";
public override string GetNewAlias(string editorAlias)
=> null;
@@ -1,32 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
class DropDownFlexiblePreValueMigrator : IPreValueMigrator
{
public bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.DropDown.Flexible";
public virtual string GetNewAlias(string editorAlias)
=> null;
public object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues)
{
var config = new DropDownFlexibleConfiguration();
foreach (var preValue in preValues.Values)
{
if (preValue.Alias == "multiple")
{
config.Multiple = (preValue.Value == "1");
}
else
{
config.Items.Add(new ValueListConfiguration.ValueListItem { Id = preValue.Id, Value = preValue.Value });
}
}
return config;
}
}
}
@@ -6,15 +6,15 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
private readonly string[] _editors =
{
Constants.PropertyEditors.Legacy.Aliases.MediaPicker2,
Constants.PropertyEditors.Aliases.MediaPicker
"Umbraco.MediaPicker2",
"Umbraco.MediaPicker"
};
public override bool CanMigrate(string editorAlias)
=> _editors.Contains(editorAlias);
public override string GetNewAlias(string editorAlias)
=> Constants.PropertyEditors.Aliases.MediaPicker;
=> "Umbraco.MediaPicker";
// you wish - but MediaPickerConfiguration lives in Umbraco.Web
/*
@@ -19,7 +19,6 @@ public class PreValueMigratorComposer : ICoreComposer
.Append<NestedContentPreValueMigrator>()
.Append<DecimalPreValueMigrator>()
.Append<ListViewPreValueMigrator>()
.Append<DropDownFlexiblePreValueMigrator>()
.Append<ValueListPreValueMigrator>();
}
}
@@ -9,7 +9,6 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
private readonly string[] _editors =
{
"Umbraco.RadioButtonList",
"Umbraco.CheckBoxList",
"Umbraco.DropDown",
"Umbraco.DropdownlistPublishingKeys",
"Umbraco.DropDownMultiple",
@@ -16,7 +16,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
var dataTypes = GetDataTypes(Constants.PropertyEditors.Legacy.Aliases.Date);
var dataTypes = GetDataTypes("Umbraco.Date");
foreach (var dataType in dataTypes)
{
@@ -25,14 +25,6 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
config = (DateTimeConfiguration) new CustomDateTimeConfigurationEditor().FromDatabase(
dataType.Configuration);
// If the Umbraco.Date type is the default from V7 and it has never been updated, then the
// configuration is empty, and the format stuff is handled by in JS by moment.js. - We can't do that
// after the migration, so we force the format to the default from V7.
if (string.IsNullOrEmpty(dataType.Configuration))
{
config.Format = "YYYY-MM-DD";
};
}
catch (Exception ex)
{
@@ -12,12 +12,12 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.ContentPicker2, Constants.PropertyEditors.Aliases.ContentPicker);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.MediaPicker2, Constants.PropertyEditors.Aliases.MediaPicker);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.MemberPicker2, Constants.PropertyEditors.Aliases.MemberPicker);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.MultiNodeTreePicker2, Constants.PropertyEditors.Aliases.MultiNodeTreePicker);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.TextboxMultiple, Constants.PropertyEditors.Aliases.TextArea, false);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.Textbox, Constants.PropertyEditors.Aliases.TextBox, false);
RenameDataType(Constants.PropertyEditors.Aliases.ContentPicker + "2", Constants.PropertyEditors.Aliases.ContentPicker);
RenameDataType(Constants.PropertyEditors.Aliases.MediaPicker + "2", Constants.PropertyEditors.Aliases.MediaPicker);
RenameDataType(Constants.PropertyEditors.Aliases.MemberPicker + "2", Constants.PropertyEditors.Aliases.MemberPicker);
RenameDataType(Constants.PropertyEditors.Aliases.MultiNodeTreePicker + "2", Constants.PropertyEditors.Aliases.MultiNodeTreePicker);
RenameDataType("Umbraco.TextboxMultiple", Constants.PropertyEditors.Aliases.TextArea, false);
RenameDataType("Umbraco.Textbox", Constants.PropertyEditors.Aliases.TextBox, false);
}
private void RenameDataType(string fromAlias, string toAlias, bool checkCollision = true)
@@ -30,20 +30,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
.Where<DataTypeDto>(x => x.EditorAlias == toAlias));
if (oldCount > 0)
{
// If we throw it means that the upgrade will exit and cannot continue.
// This will occur if a v7 site has the old "Obsolete" property editors that are already named with the `toAlias` name.
// TODO: We should have an additional upgrade step when going from 7 -> 8 like we did with 6 -> 7 that shows a compatibility report,
// this would include this check and then we can provide users with information on what they should do (i.e. before upgrading to v8 they will
// need to migrate these old obsolete editors to non-obsolete editors)
throw new InvalidOperationException(
$"Cannot rename datatype alias \"{fromAlias}\" to \"{toAlias}\" because the target alias is already used." +
$"This is generally because when upgrading from a v7 to v8 site, the v7 site contains Data Types that reference old and already Obsolete " +
$"Property Editors. Before upgrading to v8, any Data Types using property editors that are named with the prefix '(Obsolete)' must be migrated " +
$"to the non-obsolete v7 property editors of the same type.");
}
throw new InvalidOperationException($"Cannot rename datatype alias \"{fromAlias}\" to \"{toAlias}\" because the target alias is already used.");
}
Database.Execute(Sql()
@@ -14,18 +14,11 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
//Get anything currently scheduled
var releaseSql = new Sql()
.Select("nodeId", "releaseDate")
var scheduleSql = new Sql()
.Select("nodeId", "releaseDate", "expireDate")
.From("umbracoDocument")
.Where("releaseDate IS NOT NULL");
var releases = Database.Dictionary<int, DateTime> (releaseSql);
var expireSql = new Sql()
.Select("nodeId", "expireDate")
.From("umbracoDocument")
.Where("expireDate IS NOT NULL");
var expires = Database.Dictionary<int, DateTime>(expireSql);
.Where("releaseDate IS NOT NULL OR expireDate IS NOT NULL");
var schedules = Database.Dictionary<int, (DateTime? releaseDate, DateTime? expireDate)> (scheduleSql);
//drop old cols
Delete.Column("releaseDate").FromTable("umbracoDocument").Do();
@@ -34,25 +27,20 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
Create.Table<ContentScheduleDto>(true).Do();
//migrate the schedule
foreach(var s in releases)
foreach(var s in schedules)
{
var date = s.Value;
var date = s.Value.releaseDate;
var action = ContentScheduleAction.Release.ToString();
if (!date.HasValue)
{
date = s.Value.expireDate;
action = ContentScheduleAction.Expire.ToString();
}
Insert.IntoTable(ContentScheduleDto.TableName)
.Row(new { id = Guid.NewGuid(), nodeId = s.Key, date = date, action = action })
.Row(new { nodeId = s.Key, date = date.Value, action = action })
.Do();
}
foreach (var s in expires)
{
var date = s.Value;
var action = ContentScheduleAction.Expire.ToString();
Insert.IntoTable(ContentScheduleDto.TableName)
.Row(new { id = Guid.NewGuid(), nodeId = s.Key, date = date, action = action })
.Do();
}
}
}
}
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
@@ -37,7 +36,6 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
var properties = Database.Fetch<PropertyDataDto>(sqlPropertyData);
var exceptions = new List<Exception>();
foreach (var property in properties)
{
var value = property.TextValue;
@@ -45,34 +43,19 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
if (property.PropertyTypeDto.DataTypeDto.EditorAlias == Constants.PropertyEditors.Aliases.Grid)
{
try
{
var obj = JsonConvert.DeserializeObject<JObject>(value);
var allControls = obj.SelectTokens("$.sections..rows..areas..controls");
var obj = JsonConvert.DeserializeObject<JObject>(value);
var allControls = obj.SelectTokens("$.sections..rows..areas..controls");
foreach (var control in allControls.SelectMany(c => c))
foreach (var control in allControls.SelectMany(c => c))
{
var controlValue = control["value"];
if (controlValue.Type == JTokenType.String)
{
var controlValue = control["value"];
if (controlValue.Type == JTokenType.String)
{
control["value"] = UpdateMediaUrls(mediaLinkPattern, controlValue.Value<string>());
}
control["value"] = UpdateMediaUrls(mediaLinkPattern, controlValue.Value<string>());
}
property.TextValue = JsonConvert.SerializeObject(obj);
}
catch (JsonException e)
{
exceptions.Add(new InvalidOperationException(
"Cannot deserialize the value as json. This can be because the property editor " +
"type is changed from another type into a grid. Old versions of the value in this " +
"property can have the structure from the old property editor type. This needs to be " +
"changed manually before updating the database.\n" +
$"Property info: Id = {property.Id}, LanguageId = {property.LanguageId}, VersionId = {property.VersionId}, Value = {property.Value}"
, e));
continue;
}
property.TextValue = JsonConvert.SerializeObject(obj);
}
else
{
@@ -82,12 +65,6 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
Database.Update(property);
}
if (exceptions.Any())
{
throw new AggregateException("One or more errors related to unexpected data in grid values occurred.", exceptions);
}
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
+1 -9
View File
@@ -21,7 +21,6 @@ namespace Umbraco.Core.Models
private string _alias;
private string _description;
private int _dataTypeId;
private Guid _dataTypeKey;
private Lazy<int> _propertyGroupId;
private string _propertyEditorAlias;
private ValueStorageType _valueStorageType;
@@ -114,7 +113,7 @@ namespace Umbraco.Core.Models
/// Gets of sets the alias of the property type.
/// </summary>
[DataMember]
public virtual string Alias
public string Alias
{
get => _alias;
set => SetPropertyValueAndDetectChanges(SanitizeAlias(value), ref _alias, nameof(Alias));
@@ -140,13 +139,6 @@ namespace Umbraco.Core.Models
set => SetPropertyValueAndDetectChanges(value, ref _dataTypeId, nameof(DataTypeId));
}
[DataMember]
public Guid DataTypeKey
{
get => _dataTypeKey;
set => SetPropertyValueAndDetectChanges(value, ref _dataTypeKey, nameof(DataTypeKey));
}
/// <summary>
/// Gets or sets the alias of the property editor for this property type.
/// </summary>
@@ -13,10 +13,6 @@
/// <summary>
/// Refreshes the factory.
/// </summary>
/// <remarks>
/// <para>This will typically re-compiled models/classes into a new DLL that are used to populate the cache.</para>
/// <para>This is called prior to refreshing the cache.</para>
/// </remarks>
void Refresh();
}
}
@@ -54,7 +54,6 @@ namespace Umbraco.Core.Persistence.Factories
propertyType.Alias = typeDto.Alias;
propertyType.DataTypeId = typeDto.DataTypeId;
propertyType.DataTypeKey = typeDto.DataTypeDto.NodeDto.UniqueId;
propertyType.Description = typeDto.Description;
propertyType.Id = typeDto.Id;
propertyType.Key = typeDto.UniqueId;
@@ -7,7 +7,6 @@ using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Scoping;
using static Umbraco.Core.Persistence.NPocoSqlExtensions.Statics;
namespace Umbraco.Core.Persistence.Repositories.Implement
{
@@ -189,11 +188,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var groupDtos = Database.Fetch<PropertyTypeGroupDto>(sql1);
var sql2 = Sql()
.Select<PropertyTypeDto>(r => r.Select(x => x.DataTypeDto, r1 => r1.Select(x => x.NodeDto)))
.Select<PropertyTypeDto>(r => r.Select(x => x.DataTypeDto))
.AndSelect<MemberPropertyTypeDto>()
.From<PropertyTypeDto>()
.InnerJoin<DataTypeDto>().On<PropertyTypeDto, DataTypeDto>((pt, dt) => pt.DataTypeId == dt.NodeId)
.InnerJoin<NodeDto>().On<DataTypeDto, NodeDto>((dt, n) => dt.NodeId == n.NodeId)
.InnerJoin<ContentTypeDto>().On<PropertyTypeDto, ContentTypeDto>((pt, ct) => pt.ContentTypeId == ct.NodeId)
.LeftJoin<PropertyTypeGroupDto>().On<PropertyTypeDto, PropertyTypeGroupDto>((pt, ptg) => pt.PropertyTypeGroupId == ptg.Id)
.LeftJoin<MemberPropertyTypeDto>().On<PropertyTypeDto, MemberPropertyTypeDto>((pt, mpt) => pt.Id == mpt.PropertyTypeId)
@@ -292,7 +290,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
Description = dto.Description,
DataTypeId = dto.DataTypeId,
DataTypeKey = dto.DataTypeDto.NodeDto.UniqueId,
Id = dto.Id,
Key = dto.UniqueId,
Mandatory = dto.Mandatory,
@@ -1013,9 +1013,8 @@ AND umbracoNode.id <> @id",
if (propertyType.PropertyEditorAlias.IsNullOrWhiteSpace() == false)
{
var sql = Sql()
.Select<DataTypeDto>(dt => dt.Select(x => x.NodeDto))
.SelectAll()
.From<DataTypeDto>()
.InnerJoin<NodeDto>().On<DataTypeDto, NodeDto>((dt, n) => dt.NodeId == n.NodeId)
.Where("propertyEditorAlias = @propertyEditorAlias", new { propertyEditorAlias = propertyType.PropertyEditorAlias })
.OrderBy<DataTypeDto>(typeDto => typeDto.NodeId);
var datatype = Database.FirstOrDefault<DataTypeDto>(sql);
@@ -1023,7 +1022,6 @@ AND umbracoNode.id <> @id",
if (datatype != null)
{
propertyType.DataTypeId = datatype.NodeId;
propertyType.DataTypeKey = datatype.NodeDto.UniqueId;
}
else
{
@@ -225,7 +225,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
//this reset's its current data type reference which will be re-assigned based on the property editor assigned on the next line
propertyType.DataTypeId = 0;
propertyType.DataTypeKey = default;
}
}
}
@@ -30,7 +30,7 @@ namespace Umbraco.Core.PropertyEditors
// defaults
Type = type;
Icon = Constants.Icons.PropertyEditor;
Group = Constants.PropertyEditors.Groups.Common;
Group = "common";
// assign properties based on the attribute, if it is found
Attribute = GetType().GetCustomAttribute<DataEditorAttribute>(false);
@@ -121,7 +121,7 @@ namespace Umbraco.Core.PropertyEditors
/// Gets or sets an optional group.
/// </summary>
/// <remarks>The group can be used for example to group the editors by category.</remarks>
public string Group { get; set; } = Constants.PropertyEditors.Groups.Common;
public string Group { get; set; } = "common";
/// <summary>
/// Gets or sets a value indicating whether the value editor is deprecated.
@@ -5,11 +5,7 @@ namespace Umbraco.Core.PropertyEditors
/// <summary>
/// Represents a property editor for label properties.
/// </summary>
[DataEditor(
Constants.PropertyEditors.Aliases.Label,
"Label",
"readonlyvalue",
Icon = "icon-readonly")]
[DataEditor(Constants.PropertyEditors.Aliases.Label, "Label", "readonlyvalue", Icon = "icon-readonly")]
public class LabelPropertyEditor : DataEditor
{
/// <summary>
+6 -14
View File
@@ -103,26 +103,18 @@ namespace Umbraco.Core
/// Gets the children of the content item.
/// </summary>
/// <param name="content">The content item.</param>
/// <param name="culture">
/// The specific culture to get the url children for. Default is null which will use the current culture in <see cref="VariationContext"/>
/// </param>
/// <param name="culture">The specific culture to get the url children for. If null is used the current culture is used (Default is null).</param>
/// <remarks>
/// <para>Gets children that are available for the specified culture.</para>
/// <para>Children are sorted by their sortOrder.</para>
/// <para>
/// For culture,
/// if null is used the current culture is used.
/// If an empty string is used only invariant children are returned.
/// If "*" is used all children are returned.
/// </para>
/// <para>
/// If a variant culture is specified or there is a current culture in the <see cref="VariationContext"/> then the Children returned
/// will include both the variant children matching the culture AND the invariant children because the invariant children flow with the current culture.
/// However, if an empty string is specified only invariant children are returned.
/// </para>
/// <para>The '*' culture and supported and returns everything.</para>
/// </remarks>
public static IEnumerable<IPublishedContent> Children(this IPublishedContent content, string culture = null)
{
// invariant has invariant value (whatever the requested culture)
if (!content.ContentType.VariesByCulture() && culture != "*")
culture = "";
// handle context culture for variant
if (culture == null)
culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
@@ -9,14 +9,7 @@ namespace Umbraco.Core
public static class PublishedModelFactoryExtensions
{
/// <summary>
/// Returns true if the current <see cref="IPublishedModelFactory"/> is an implementation of <see cref="ILivePublishedModelFactory"/>
/// </summary>
/// <param name="factory"></param>
/// <returns></returns>
public static bool IsLiveFactory(this IPublishedModelFactory factory) => factory is ILivePublishedModelFactory;
/// <summary>
/// Executes an action with a safe live factory
/// Executes an action with a safe live factory/
/// </summary>
/// <remarks>
/// <para>If the factory is a live factory, ensures it is refreshed and locked while executing the action.</para>
@@ -27,7 +20,6 @@ namespace Umbraco.Core
{
lock (liveFactory.SyncRoot)
{
//Call refresh on the live factory to re-compile the models
liveFactory.Refresh();
action();
}
+3 -3
View File
@@ -139,7 +139,7 @@ namespace Umbraco.Core.Runtime
// there should be none, really - this is here "just in case"
Compose(composition);
// acquire the main domain - if this fails then anything that should be registered with MainDom will not operate
// acquire the main domain
AcquireMainDom(mainDom);
// determine our runtime level
@@ -218,13 +218,13 @@ namespace Umbraco.Core.Runtime
IOHelper.SetRootDirectory(path);
}
private bool AcquireMainDom(MainDom mainDom)
private void AcquireMainDom(MainDom mainDom)
{
using (var timer = ProfilingLogger.DebugDuration<CoreRuntime>("Acquiring MainDom.", "Acquired."))
{
try
{
return mainDom.Acquire();
mainDom.Acquire();
}
catch
{
-5
View File
@@ -97,11 +97,6 @@ namespace Umbraco.Core
/// <param name="request"></param>
internal void EnsureApplicationUrl(HttpRequestBase request = null)
{
//Fixme: This causes problems with site swap on azure because azure pre-warms a site by calling into `localhost` and when it does that
// it changes the URL to `localhost:80` which actually doesn't work for pinging itself, it only works internally in Azure. The ironic part
// about this is that this is here specifically for the slot swap scenario https://issues.umbraco.org/issue/U4-10626
// see U4-10626 - in some cases we want to reset the application url
// (this is a simplified version of what was in 7.x)
// note: should this be optional? is it expensive?
@@ -6,25 +6,9 @@ namespace Umbraco.Core.Services.Changes
public enum ContentTypeChangeTypes : byte
{
None = 0,
/// <summary>
/// Item type has been created, no impact
/// </summary>
Create = 1,
/// <summary>
/// Content type changes impact only the Content type being saved
/// </summary>
RefreshMain = 2,
/// <summary>
/// Content type changes impacts the content type being saved and others used that are composed of it
/// </summary>
RefreshOther = 4, // changed, other change
/// <summary>
/// Content type was removed
/// </summary>
Remove = 8
Create = 1, // item type has been created, no impact
RefreshMain = 2, // changed, impacts content (adding property or composition does NOT)
RefreshOther = 4, // changed, other changes
Remove = 8 // item type has been removed
}
}
-1
View File
@@ -241,7 +241,6 @@
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\DefaultPreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\RenamingPreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\RichTextPreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\DropDownFlexiblePreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\MergeDateAndDateTimePropertyEditor.cs" />
<Compile Include="Models\Entities\EntityExtensions.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\PreValueMigratorBase.cs" />
-2
View File
@@ -23,8 +23,6 @@ namespace Umbraco.Core
handle,
(state, timedOut) =>
{
//TODO: We aren't checking if this is timed out
tcs.SetResult(null);
// we take a lock here to make sure the outer method has completed setting the local variable callbackHandle.
+1 -1
View File
@@ -45,7 +45,7 @@ namespace Umbraco.Examine
continue;
case string strVal:
{
if (strVal.IsNullOrWhiteSpace()) continue;
if (strVal.IsNullOrWhiteSpace()) return;
var key = $"{keyVal.Key}{cultureSuffix}";
if (values.TryGetValue(key, out var v))
values[key] = new List<object>(v) { val }.ToArray();
+1 -28
View File
@@ -48,31 +48,6 @@ namespace Umbraco.Examine
}
}
/// <summary>
/// Returns all index fields that are culture specific (suffixed) or invariant
/// </summary>
/// <param name="index"></param>
/// <param name="culture"></param>
/// <returns></returns>
public static IEnumerable<string> GetCultureAndInvariantFields(this IUmbracoIndex index, string culture)
{
var allFields = index.GetFields();
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var field in allFields)
{
var match = CultureIsoCodeFieldNameMatchExpression.Match(field);
if (match.Success && match.Groups.Count == 3 && culture.InvariantEquals(match.Groups[2].Value))
{
yield return field; //matches this culture field
}
else if (!match.Success)
{
yield return field; //matches no culture field (invariant)
}
}
}
internal static bool TryParseLuceneQuery(string query)
{
// TODO: I'd assume there would be a more strict way to parse the query but not that i can find yet, for now we'll
@@ -102,7 +77,7 @@ namespace Umbraco.Examine
/// <remarks>
/// This is not thread safe, use with care
/// </remarks>
internal static void ConfigureLuceneIndexes(this IExamineManager examineManager, ILogger logger, bool disableExamineIndexing)
internal static void UnlockLuceneIndexes(this IExamineManager examineManager, ILogger logger)
{
foreach (var luceneIndexer in examineManager.Indexes.OfType<LuceneIndex>())
{
@@ -111,8 +86,6 @@ namespace Umbraco.Examine
//that could end up halting shutdown for a very long time causing overlapping appdomains and many other problems.
luceneIndexer.WaitForIndexQueueOnShutdown = false;
if (disableExamineIndexing) continue; //exit if not enabled, we don't need to unlock them if we're not maindom
//we should check if the index is locked ... it shouldn't be! We are using simple fs lock now and we are also ensuring that
//the indexes are not operational unless MainDom is true
var dir = luceneIndexer.GetLuceneDirectory();
@@ -124,7 +124,7 @@ namespace Umbraco.Tests.PublishedContent
_source = new TestDataSource(kits);
// at last, create the complete NuCache snapshot service!
var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true };
var options = new PublishedSnapshotService.Options { IgnoreLocalDb = true };
_snapshotService = new PublishedSnapshotService(options,
null,
runtime,
@@ -151,139 +151,117 @@ namespace Umbraco.Tests.PublishedContent
Mock.Get(factory).Setup(x => x.GetInstance(typeof(IVariationContextAccessor))).Returns(_variationAccesor);
}
private IEnumerable<ContentNodeKit> GetNestedVariantKits()
{
var paths = new Dictionary<int, string> { { -1, "-1" } };
//1x variant (root)
yield return CreateVariantKit(1, -1, 1, paths);
//1x invariant under root
yield return CreateInvariantKit(4, 1, 1, paths);
//1x variant under root
yield return CreateVariantKit(7, 1, 4, paths);
//2x mixed under invariant
yield return CreateVariantKit(10, 4, 1, paths);
yield return CreateInvariantKit(11, 4, 2, paths);
//2x mixed under variant
yield return CreateVariantKit(12, 7, 1, paths);
yield return CreateInvariantKit(13, 7, 2, paths);
}
private IEnumerable<ContentNodeKit> GetInvariantKits()
{
var paths = new Dictionary<int, string> { { -1, "-1" } };
yield return CreateInvariantKit(1, -1, 1, paths);
yield return CreateInvariantKit(2, -1, 2, paths);
yield return CreateInvariantKit(3, -1, 3, paths);
yield return CreateInvariantKit(4, 1, 1, paths);
yield return CreateInvariantKit(5, 1, 2, paths);
yield return CreateInvariantKit(6, 1, 3, paths);
yield return CreateInvariantKit(7, 2, 3, paths);
yield return CreateInvariantKit(8, 2, 2, paths);
yield return CreateInvariantKit(9, 2, 1, paths);
yield return CreateInvariantKit(10, 3, 1, paths);
yield return CreateInvariantKit(11, 4, 1, paths);
yield return CreateInvariantKit(12, 4, 2, paths);
}
private ContentNodeKit CreateInvariantKit(int id, int parentId, int sortOrder, Dictionary<int, string> paths)
{
if (!paths.TryGetValue(parentId, out var parentPath))
throw new Exception("Unknown parent.");
var path = paths[id] = parentPath + "," + id;
var level = path.Count(x => x == ',');
var now = DateTime.Now;
return new ContentNodeKit
ContentNodeKit CreateKit(int id, int parentId, int sortOrder)
{
ContentTypeId = _contentTypeInvariant.Id,
Node = new ContentNode(id, Guid.NewGuid(), level, path, sortOrder, parentId, DateTime.Now, 0),
DraftData = null,
PublishedData = new ContentData
if (!paths.TryGetValue(parentId, out var parentPath))
throw new Exception("Unknown parent.");
var path = paths[id] = parentPath + "," + id;
var level = path.Count(x => x == ',');
var now = DateTime.Now;
return new ContentNodeKit
{
Name = "N" + id,
Published = true,
TemplateId = 0,
VersionId = 1,
VersionDate = now,
WriterId = 0,
Properties = new Dictionary<string, PropertyData[]>(),
CultureInfos = new Dictionary<string, CultureVariation>()
}
};
ContentTypeId = _contentTypeInvariant.Id,
Node = new ContentNode(id, Guid.NewGuid(), level, path, sortOrder, parentId, DateTime.Now, 0),
DraftData = null,
PublishedData = new ContentData
{
Name = "N" + id,
Published = true,
TemplateId = 0,
VersionId = 1,
VersionDate = now,
WriterId = 0,
Properties = new Dictionary<string, PropertyData[]>(),
CultureInfos = new Dictionary<string, CultureVariation>()
}
};
}
yield return CreateKit(1, -1, 1);
yield return CreateKit(2, -1, 2);
yield return CreateKit(3, -1, 3);
yield return CreateKit(4, 1, 1);
yield return CreateKit(5, 1, 2);
yield return CreateKit(6, 1, 3);
yield return CreateKit(7, 2, 3);
yield return CreateKit(8, 2, 2);
yield return CreateKit(9, 2, 1);
yield return CreateKit(10, 3, 1);
yield return CreateKit(11, 4, 1);
yield return CreateKit(12, 4, 2);
}
private IEnumerable<ContentNodeKit> GetVariantKits()
{
var paths = new Dictionary<int, string> { { -1, "-1" } };
yield return CreateVariantKit(1, -1, 1, paths);
yield return CreateVariantKit(2, -1, 2, paths);
yield return CreateVariantKit(3, -1, 3, paths);
yield return CreateVariantKit(4, 1, 1, paths);
yield return CreateVariantKit(5, 1, 2, paths);
yield return CreateVariantKit(6, 1, 3, paths);
yield return CreateVariantKit(7, 2, 3, paths);
yield return CreateVariantKit(8, 2, 2, paths);
yield return CreateVariantKit(9, 2, 1, paths);
yield return CreateVariantKit(10, 3, 1, paths);
yield return CreateVariantKit(11, 4, 1, paths);
yield return CreateVariantKit(12, 4, 2, paths);
}
private static Dictionary<string, CultureVariation> GetCultureInfos(int id, DateTime now)
{
var en = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
var fr = new[] { 1, 3, 4, 6, 7, 9, 10, 12 };
var infos = new Dictionary<string, CultureVariation>();
if (en.Contains(id))
infos["en-US"] = new CultureVariation { Name = "N" + id + "-" + "en-US", Date = now, IsDraft = false };
if (fr.Contains(id))
infos["fr-FR"] = new CultureVariation { Name = "N" + id + "-" + "fr-FR", Date = now, IsDraft = false };
return infos;
}
private ContentNodeKit CreateVariantKit(int id, int parentId, int sortOrder, Dictionary<int, string> paths)
{
if (!paths.TryGetValue(parentId, out var parentPath))
throw new Exception("Unknown parent.");
var path = paths[id] = parentPath + "," + id;
var level = path.Count(x => x == ',');
var now = DateTime.Now;
return new ContentNodeKit
Dictionary<string, CultureVariation> GetCultureInfos(int id, DateTime now)
{
ContentTypeId = _contentTypeVariant.Id,
Node = new ContentNode(id, Guid.NewGuid(), level, path, sortOrder, parentId, DateTime.Now, 0),
DraftData = null,
PublishedData = new ContentData
var en = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
var fr = new[] { 1, 3, 4, 6, 7, 9, 10, 12 };
var infos = new Dictionary<string, CultureVariation>();
if (en.Contains(id))
infos["en-US"] = new CultureVariation { Name = "N" + id + "-" + "en-US", Date = now, IsDraft = false };
if (fr.Contains(id))
infos["fr-FR"] = new CultureVariation { Name = "N" + id + "-" + "fr-FR", Date = now, IsDraft = false };
return infos;
}
ContentNodeKit CreateKit(int id, int parentId, int sortOrder)
{
if (!paths.TryGetValue(parentId, out var parentPath))
throw new Exception("Unknown parent.");
var path = paths[id] = parentPath + "," + id;
var level = path.Count(x => x == ',');
var now = DateTime.Now;
return new ContentNodeKit
{
Name = "N" + id,
Published = true,
TemplateId = 0,
VersionId = 1,
VersionDate = now,
WriterId = 0,
Properties = new Dictionary<string, PropertyData[]>(),
CultureInfos = GetCultureInfos(id, now)
}
};
ContentTypeId = _contentTypeVariant.Id,
Node = new ContentNode(id, Guid.NewGuid(), level, path, sortOrder, parentId, DateTime.Now, 0),
DraftData = null,
PublishedData = new ContentData
{
Name = "N" + id,
Published = true,
TemplateId = 0,
VersionId = 1,
VersionDate = now,
WriterId = 0,
Properties = new Dictionary<string, PropertyData[]>(),
CultureInfos = GetCultureInfos(id, now)
}
};
}
yield return CreateKit(1, -1, 1);
yield return CreateKit(2, -1, 2);
yield return CreateKit(3, -1, 3);
yield return CreateKit(4, 1, 1);
yield return CreateKit(5, 1, 2);
yield return CreateKit(6, 1, 3);
yield return CreateKit(7, 2, 3);
yield return CreateKit(8, 2, 2);
yield return CreateKit(9, 2, 1);
yield return CreateKit(10, 3, 1);
yield return CreateKit(11, 4, 1);
yield return CreateKit(12, 4, 2);
}
private IEnumerable<ContentNodeKit> GetVariantWithDraftKits()
@@ -682,96 +660,6 @@ namespace Umbraco.Tests.PublishedContent
Assert.AreEqual(1, snapshot.Content.GetById(7).Parent?.Id);
}
[Test]
public void NestedVariationChildrenTest()
{
var mixedKits = GetNestedVariantKits();
Init(mixedKits);
var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null);
_snapshotAccessor.PublishedSnapshot = snapshot;
//TEST with en-us variation context
_variationAccesor.VariationContext = new VariationContext("en-US");
var documents = snapshot.Content.GetAtRoot().ToArray();
AssertDocuments(documents, "N1-en-US");
documents = snapshot.Content.GetById(1).Children().ToArray();
AssertDocuments(documents, "N4", "N7-en-US");
//Get the invariant and list children, there's a variation context so it should return invariant AND en-us variants
documents = snapshot.Content.GetById(4).Children().ToArray();
AssertDocuments(documents, "N10-en-US", "N11");
//Get the variant and list children, there's a variation context so it should return invariant AND en-us variants
documents = snapshot.Content.GetById(7).Children().ToArray();
AssertDocuments(documents, "N12-en-US", "N13");
//TEST with fr-fr variation context
_variationAccesor.VariationContext = new VariationContext("fr-FR");
documents = snapshot.Content.GetAtRoot().ToArray();
AssertDocuments(documents, "N1-fr-FR");
documents = snapshot.Content.GetById(1).Children().ToArray();
AssertDocuments(documents, "N4", "N7-fr-FR");
//Get the invariant and list children, there's a variation context so it should return invariant AND en-us variants
documents = snapshot.Content.GetById(4).Children().ToArray();
AssertDocuments(documents, "N10-fr-FR", "N11");
//Get the variant and list children, there's a variation context so it should return invariant AND en-us variants
documents = snapshot.Content.GetById(7).Children().ToArray();
AssertDocuments(documents, "N12-fr-FR", "N13");
//TEST specific cultures
documents = snapshot.Content.GetAtRoot("fr-FR").ToArray();
AssertDocuments(documents, "N1-fr-FR");
documents = snapshot.Content.GetById(1).Children("fr-FR").ToArray();
AssertDocuments(documents, "N4", "N7-fr-FR"); //NOTE: Returns invariant, this is expected
documents = snapshot.Content.GetById(1).Children("").ToArray();
AssertDocuments(documents, "N4"); //Only returns invariant since that is what was requested
documents = snapshot.Content.GetById(4).Children("fr-FR").ToArray();
AssertDocuments(documents, "N10-fr-FR", "N11"); //NOTE: Returns invariant, this is expected
documents = snapshot.Content.GetById(4).Children("").ToArray();
AssertDocuments(documents, "N11"); //Only returns invariant since that is what was requested
documents = snapshot.Content.GetById(7).Children("fr-FR").ToArray();
AssertDocuments(documents, "N12-fr-FR", "N13"); //NOTE: Returns invariant, this is expected
documents = snapshot.Content.GetById(7).Children("").ToArray();
AssertDocuments(documents, "N13"); //Only returns invariant since that is what was requested
//TEST without variation context
// This will actually convert the culture to "" which will be invariant since that's all it will know how to do
// This will return a NULL name for culture specific entities because there is no variation context
_variationAccesor.VariationContext = null;
documents = snapshot.Content.GetAtRoot().ToArray();
//will return nothing because there's only variant at root
Assert.AreEqual(0, documents.Length);
//so we'll continue to getting the known variant, do not fully assert this because the Name will NULL
documents = snapshot.Content.GetAtRoot("fr-FR").ToArray();
Assert.AreEqual(1, documents.Length);
documents = snapshot.Content.GetById(1).Children().ToArray();
AssertDocuments(documents, "N4");
//Get the invariant and list children
documents = snapshot.Content.GetById(4).Children().ToArray();
AssertDocuments(documents, "N11");
//Get the variant and list children
documents = snapshot.Content.GetById(7).Children().ToArray();
AssertDocuments(documents, "N13");
}
[Test]
public void VariantChildrenTest()
{
@@ -169,7 +169,7 @@ namespace Umbraco.Tests.PublishedContent
_variationAccesor = new TestVariationContextAccessor();
// at last, create the complete NuCache snapshot service!
var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true };
var options = new PublishedSnapshotService.Options { IgnoreLocalDb = true };
_snapshotService = new PublishedSnapshotService(options,
null,
runtime,
@@ -81,19 +81,6 @@ namespace Umbraco.Tests.Routing
Assert.AreEqual(expected, resolvedUrl);
}
[Test]
public void Get_Media_Url_Returns_Absolute_Url_If_Stored_Url_Is_Absolute()
{
const string expected = "http://localhost/media/rfeiw584/test.jpg";
var umbracoContext = GetUmbracoContext("http://localhost", mediaUrlProviders: new[] { _mediaUrlProvider });
var publishedContent = CreatePublishedContent(Constants.PropertyEditors.Aliases.UploadField, expected, null);
var resolvedUrl = umbracoContext.UrlProvider.GetMediaUrl(publishedContent, UrlMode.Relative);
Assert.AreEqual(expected, resolvedUrl);
}
[Test]
public void Get_Media_Url_Returns_Empty_String_When_PropertyType_Is_Not_Supported()
{
@@ -72,7 +72,7 @@ namespace Umbraco.Tests.Scoping
protected override IPublishedSnapshotService CreatePublishedSnapshotService()
{
var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true };
var options = new PublishedSnapshotService.Options { IgnoreLocalDb = true };
var publishedSnapshotAccessor = new UmbracoContextPublishedSnapshotAccessor(Umbraco.Web.Composing.Current.UmbracoContextAccessor);
var runtimeStateMock = new Mock<IRuntimeState>();
runtimeStateMock.Setup(x => x.Level).Returns(() => RuntimeLevel.Run);
@@ -0,0 +1,157 @@
using System.Collections.Specialized;
using System.Web;
using System.Web.Helpers;
using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web.Mvc;
using Umbraco.Web.Security;
namespace Umbraco.Tests.Security
{
[TestFixture]
public class UmbracoAntiForgeryAdditionalDataProviderTests
{
[Test]
public void Test_Wrapped_Non_BeginUmbracoForm()
{
var wrapped = Mock.Of<IAntiForgeryAdditionalDataProvider>(x => x.GetAdditionalData(It.IsAny<HttpContextBase>()) == "custom");
var provider = new UmbracoAntiForgeryAdditionalDataProvider(wrapped);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var data = provider.GetAdditionalData(httpContextFactory.HttpContext);
Assert.IsTrue(data.DetectIsJson());
var json = JsonConvert.DeserializeObject<UmbracoAntiForgeryAdditionalDataProvider.AdditionalData>(data);
Assert.AreEqual(null, json.Ufprt);
Assert.IsTrue(json.Stamp != default);
Assert.AreEqual("custom", json.WrappedValue);
}
[Test]
public void Null_Wrapped_Non_BeginUmbracoForm()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var data = provider.GetAdditionalData(httpContextFactory.HttpContext);
Assert.IsTrue(data.DetectIsJson());
var json = JsonConvert.DeserializeObject<UmbracoAntiForgeryAdditionalDataProvider.AdditionalData>(data);
Assert.AreEqual(null, json.Ufprt);
Assert.IsTrue(json.Stamp != default);
Assert.AreEqual("default", json.WrappedValue);
}
[Test]
public void Validate_Non_Json()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "hello");
Assert.IsFalse(isValid);
}
[Test]
public void Validate_Invalid_Json()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '0'}");
Assert.IsFalse(isValid);
isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': ''}");
Assert.IsFalse(isValid);
isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'hello': 'world'}");
Assert.IsFalse(isValid);
}
[Test]
public void Validate_No_Request_Ufprt()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
//there is a ufprt in the additional data, but not in the request
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': 'ASBVDFDFDFDF'}");
Assert.IsFalse(isValid);
}
[Test]
public void Validate_No_AdditionalData_Ufprt()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var requestMock = Mock.Get(httpContextFactory.HttpContext.Request);
requestMock.SetupGet(x => x["ufprt"]).Returns("ABCDEFG");
//there is a ufprt in the additional data, but not in the request
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': ''}");
Assert.IsFalse(isValid);
}
[Test]
public void Validate_No_AdditionalData_Or_Request_Ufprt()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
//there is a ufprt in the additional data, but not in the request
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': ''}");
Assert.IsTrue(isValid);
}
[Test]
public void Validate_Request_And_AdditionalData_Ufprt()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var routeParams1 = $"{RenderRouteHandler.ReservedAdditionalKeys.Controller}={HttpUtility.UrlEncode("Test")}&{RenderRouteHandler.ReservedAdditionalKeys.Action}={HttpUtility.UrlEncode("Index")}&{RenderRouteHandler.ReservedAdditionalKeys.Area}=Umbraco";
var routeParams2 = $"{RenderRouteHandler.ReservedAdditionalKeys.Controller}={HttpUtility.UrlEncode("Test")}&{RenderRouteHandler.ReservedAdditionalKeys.Action}={HttpUtility.UrlEncode("Index")}&{RenderRouteHandler.ReservedAdditionalKeys.Area}=Umbraco";
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var requestMock = Mock.Get(httpContextFactory.HttpContext.Request);
requestMock.SetupGet(x => x["ufprt"]).Returns(routeParams1.EncryptWithMachineKey());
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': '" + routeParams2.EncryptWithMachineKey() + "'}");
Assert.IsTrue(isValid);
routeParams2 = $"{RenderRouteHandler.ReservedAdditionalKeys.Controller}={HttpUtility.UrlEncode("Invalid")}&{RenderRouteHandler.ReservedAdditionalKeys.Action}={HttpUtility.UrlEncode("Index")}&{RenderRouteHandler.ReservedAdditionalKeys.Area}=Umbraco";
isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': '" + routeParams2.EncryptWithMachineKey() + "'}");
Assert.IsFalse(isValid);
}
[Test]
public void Validate_Wrapped_Request_And_AdditionalData_Ufprt()
{
var wrapped = Mock.Of<IAntiForgeryAdditionalDataProvider>(x => x.ValidateAdditionalData(It.IsAny<HttpContextBase>(), "custom") == true);
var provider = new UmbracoAntiForgeryAdditionalDataProvider(wrapped);
var routeParams1 = $"{RenderRouteHandler.ReservedAdditionalKeys.Controller}={HttpUtility.UrlEncode("Test")}&{RenderRouteHandler.ReservedAdditionalKeys.Action}={HttpUtility.UrlEncode("Index")}&{RenderRouteHandler.ReservedAdditionalKeys.Area}=Umbraco";
var routeParams2 = $"{RenderRouteHandler.ReservedAdditionalKeys.Controller}={HttpUtility.UrlEncode("Test")}&{RenderRouteHandler.ReservedAdditionalKeys.Action}={HttpUtility.UrlEncode("Index")}&{RenderRouteHandler.ReservedAdditionalKeys.Area}=Umbraco";
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var requestMock = Mock.Get(httpContextFactory.HttpContext.Request);
requestMock.SetupGet(x => x["ufprt"]).Returns(routeParams1.EncryptWithMachineKey());
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': '" + routeParams2.EncryptWithMachineKey() + "'}");
Assert.IsFalse(isValid);
isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'custom', 'Ufprt': '" + routeParams2.EncryptWithMachineKey() + "'}");
Assert.IsTrue(isValid);
routeParams2 = $"{RenderRouteHandler.ReservedAdditionalKeys.Controller}={HttpUtility.UrlEncode("Invalid")}&{RenderRouteHandler.ReservedAdditionalKeys.Action}={HttpUtility.UrlEncode("Index")}&{RenderRouteHandler.ReservedAdditionalKeys.Area}=Umbraco";
isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': '" + routeParams2.EncryptWithMachineKey() + "'}");
Assert.IsFalse(isValid);
}
}
}
@@ -42,7 +42,7 @@ namespace Umbraco.Tests.Services
protected override IPublishedSnapshotService CreatePublishedSnapshotService()
{
var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true };
var options = new PublishedSnapshotService.Options { IgnoreLocalDb = true };
var publishedSnapshotAccessor = new UmbracoContextPublishedSnapshotAccessor(Umbraco.Web.Composing.Current.UmbracoContextAccessor);
var runtimeStateMock = new Mock<IRuntimeState>();
runtimeStateMock.Setup(x => x.Level).Returns(() => RuntimeLevel.Run);
@@ -25,23 +25,19 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
public async Task<Tuple<HttpResponseMessage, string>> Execute(string controllerName, string actionName, HttpMethod method,
HttpContent content = null,
MediaTypeWithQualityHeaderValue mediaTypeHeader = null,
bool assertOkResponse = true, object routeDefaults = null, string url = null)
bool assertOkResponse = true)
{
if (mediaTypeHeader == null)
{
mediaTypeHeader = new MediaTypeWithQualityHeaderValue("application/json");
}
if (routeDefaults == null)
{
routeDefaults = new { controller = controllerName, action = actionName, id = RouteParameter.Optional };
}
var startup = new TestStartup(
configuration =>
{
configuration.Routes.MapHttpRoute("Default",
routeTemplate: "{controller}/{action}/{id}",
defaults: routeDefaults);
defaults: new { controller = controllerName, action = actionName, id = RouteParameter.Optional });
},
_controllerFactory);
@@ -49,7 +45,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
{
var request = new HttpRequestMessage
{
RequestUri = new Uri("https://testserver/" + (url ?? "")),
RequestUri = new Uri("https://testserver/"),
Method = method
};
@@ -1,22 +0,0 @@
using Lucene.Net.Store;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Umbraco.Tests.TestHelpers
{
/// <summary>
/// Used for tests with Lucene so that each RAM directory is unique
/// </summary>
public class RandomIdRAMDirectory : RAMDirectory
{
private readonly string _lockId = Guid.NewGuid().ToString();
public override string GetLockId()
{
return _lockId;
}
}
}
+1 -4
View File
@@ -147,6 +147,7 @@
<Compile Include="Routing\MediaUrlProviderTests.cs" />
<Compile Include="Runtimes\StandaloneTests.cs" />
<Compile Include="Routing\GetContentUrlsTests.cs" />
<Compile Include="Security\UmbracoAntiForgeryAdditionalDataProviderTests.cs" />
<Compile Include="Services\AmbiguousEventTests.cs" />
<Compile Include="Services\ContentServiceEventTests.cs" />
<Compile Include="Services\ContentServicePublishBranchTests.cs" />
@@ -157,7 +158,6 @@
<Compile Include="Services\MemberGroupServiceTests.cs" />
<Compile Include="Services\MediaTypeServiceTests.cs" />
<Compile Include="Services\PropertyValidationServiceTests.cs" />
<Compile Include="TestHelpers\RandomIdRamDirectory.cs" />
<Compile Include="Testing\Objects\TestDataSource.cs" />
<Compile Include="Published\PublishedSnapshotTestObjects.cs" />
<Compile Include="Published\ModelTypeTests.cs" />
@@ -243,7 +243,6 @@
<Compile Include="Cache\FullDataSetCachePolicyTests.cs" />
<Compile Include="Cache\SingleItemsOnlyCachePolicyTests.cs" />
<Compile Include="Collections\DeepCloneableListTests.cs" />
<Compile Include="Web\Controllers\AuthenticationControllerTests.cs" />
<Compile Include="Web\Controllers\BackOfficeControllerUnitTests.cs" />
<Compile Include="CoreThings\DelegateExtensionsTests.cs" />
<Compile Include="Web\Controllers\ContentControllerTests.cs" />
@@ -269,8 +268,6 @@
<Compile Include="StringNewlineExtensions.cs" />
<Compile Include="Strings\StylesheetHelperTests.cs" />
<Compile Include="Strings\StringValidationTests.cs" />
<Compile Include="Web\Mvc\ValidateUmbracoFormRouteStringAttributeTests.cs" />
<Compile Include="Web\PublishedContentQueryTests.cs" />
<Compile Include="Web\UmbracoHelperTests.cs" />
<Compile Include="Membership\MembershipProviderBaseTests.cs" />
<Compile Include="Membership\UmbracoServiceMembershipProviderTests.cs" />
@@ -1,139 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Security.Cryptography;
using System.Threading;
using System.Web;
using System.Web.Hosting;
using System.Web.Http;
using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.ControllerTesting;
using Umbraco.Tests.Testing;
using Umbraco.Web;
using Umbraco.Web.Editors;
using Umbraco.Web.Features;
using Umbraco.Web.Models.ContentEditing;
using IUser = Umbraco.Core.Models.Membership.IUser;
namespace Umbraco.Tests.Web.Controllers
{
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.None)]
public class AuthenticationControllerTests : TestWithDatabaseBase
{
protected override void ComposeApplication(bool withApplication)
{
base.ComposeApplication(withApplication);
//if (!withApplication) return;
// replace the true IUserService implementation with a mock
// so that each test can configure the service to their liking
Composition.RegisterUnique(f => Mock.Of<IUserService>());
// kill the true IEntityService too
Composition.RegisterUnique(f => Mock.Of<IEntityService>());
Composition.RegisterUnique<UmbracoFeatures>();
}
[Test]
public async System.Threading.Tasks.Task GetCurrentUser_Fips()
{
ApiController CtrlFactory(HttpRequestMessage message, IUmbracoContextAccessor umbracoContextAccessor, UmbracoHelper helper)
{
//setup some mocks
var userServiceMock = Mock.Get(Current.Services.UserService);
userServiceMock.Setup(service => service.GetUserById(It.IsAny<int>()))
.Returns(() => null);
if (Thread.GetDomain().GetData(".appPath") != null)
{
HttpContext.Current = new HttpContext(new SimpleWorkerRequest("", "", new StringWriter()));
}
else
{
var baseDir = IOHelper.MapPath("", false).TrimEnd(IOHelper.DirSepChar);
HttpContext.Current = new HttpContext(new SimpleWorkerRequest("/", baseDir, "", "", new StringWriter()));
}
IOHelper.ForceNotHosted = true;
var usersController = new AuthenticationController(
Factory.GetInstance<IGlobalSettings>(),
umbracoContextAccessor,
Factory.GetInstance<ISqlContext>(),
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
Factory.GetInstance<IRuntimeState>(),
helper);
return usersController;
}
Mock.Get(Current.SqlContext)
.Setup(x => x.Query<IUser>())
.Returns(new Query<IUser>(Current.SqlContext));
var syntax = new SqlCeSyntaxProvider();
Mock.Get(Current.SqlContext)
.Setup(x => x.SqlSyntax)
.Returns(syntax);
var mappers = new MapperCollection(new[]
{
new UserMapper(new Lazy<ISqlContext>(() => Current.SqlContext), new ConcurrentDictionary<Type, ConcurrentDictionary<string, string>>())
});
Mock.Get(Current.SqlContext)
.Setup(x => x.Mappers)
.Returns(mappers);
// Testing what happens if the system were configured to only use FIPS-compliant algorithms
var typ = typeof(CryptoConfig);
var flds = typ.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
var haveFld = flds.FirstOrDefault(f => f.Name == "s_haveFipsAlgorithmPolicy");
var isFld = flds.FirstOrDefault(f => f.Name == "s_fipsAlgorithmPolicy");
var originalFipsValue = CryptoConfig.AllowOnlyFipsAlgorithms;
try
{
if (!originalFipsValue)
{
haveFld.SetValue(null, true);
isFld.SetValue(null, true);
}
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Authentication", "GetCurrentUser", HttpMethod.Get);
var obj = JsonConvert.DeserializeObject<UserDetail>(response.Item2);
Assert.AreEqual(-1, obj.UserId);
}
finally
{
if (!originalFipsValue)
{
haveFld.SetValue(null, false);
isFld.SetValue(null, false);
}
}
}
}
}
@@ -4,8 +4,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Reflection;
using System.Security.Cryptography;
using System.Web.Http;
using Moq;
using Newtonsoft.Json;
@@ -157,7 +155,7 @@ namespace Umbraco.Tests.Web.Controllers
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Users", "GetPagedUsers", HttpMethod.Get);
var obj = JsonConvert.DeserializeObject<PagedResult<UserBasic>>(response.Item2);
var obj = JsonConvert.DeserializeObject<PagedResult<UserDisplay>>(response.Item2);
Assert.AreEqual(0, obj.TotalItems);
}
@@ -192,100 +190,9 @@ namespace Umbraco.Tests.Web.Controllers
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Users", "GetPagedUsers", HttpMethod.Get);
var obj = JsonConvert.DeserializeObject<PagedResult<UserBasic>>(response.Item2);
var obj = JsonConvert.DeserializeObject<PagedResult<UserDisplay>>(response.Item2);
Assert.AreEqual(10, obj.TotalItems);
Assert.AreEqual(10, obj.Items.Count());
}
[Test]
public async System.Threading.Tasks.Task GetPagedUsers_Fips()
{
await RunFipsTest("GetPagedUsers", mock =>
{
var users = MockedUser.CreateMulipleUsers(10);
long outVal = 10;
mock.Setup(service => service.GetAll(
It.IsAny<long>(), It.IsAny<int>(), out outVal, It.IsAny<string>(), It.IsAny<Direction>(),
It.IsAny<UserState[]>(), It.IsAny<string[]>(), It.IsAny<string[]>(), It.IsAny<IQuery<IUser>>()))
.Returns(() => users);
}, response =>
{
var obj = JsonConvert.DeserializeObject<PagedResult<UserBasic>>(response.Item2);
Assert.AreEqual(10, obj.TotalItems);
Assert.AreEqual(10, obj.Items.Count());
});
}
[Test]
public async System.Threading.Tasks.Task GetById_Fips()
{
const int mockUserId = 1234;
var user = MockedUser.CreateUser();
await RunFipsTest("GetById", mock =>
{
mock.Setup(service => service.GetUserById(1234))
.Returns((int i) => i == mockUserId ? user : null);
}, response =>
{
var obj = JsonConvert.DeserializeObject<UserDisplay>(response.Item2);
Assert.AreEqual(user.Username, obj.Username);
Assert.AreEqual(user.Email, obj.Email);
}, new { controller = "Users", action = "GetById" }, $"Users/GetById/{mockUserId}");
}
private async System.Threading.Tasks.Task RunFipsTest(string action, Action<Mock<IUserService>> userServiceSetup,
Action<Tuple<HttpResponseMessage, string>> verification,
object routeDefaults = null, string url = null)
{
ApiController CtrlFactory(HttpRequestMessage message, IUmbracoContextAccessor umbracoContextAccessor, UmbracoHelper helper)
{
//setup some mocks
var userServiceMock = Mock.Get(Current.Services.UserService);
userServiceSetup(userServiceMock);
var usersController = new UsersController(
Factory.GetInstance<IGlobalSettings>(),
umbracoContextAccessor,
Factory.GetInstance<ISqlContext>(),
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
Factory.GetInstance<IRuntimeState>(),
helper);
return usersController;
}
// Testing what happens if the system were configured to only use FIPS-compliant algorithms
var typ = typeof(CryptoConfig);
var flds = typ.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
var haveFld = flds.FirstOrDefault(f => f.Name == "s_haveFipsAlgorithmPolicy");
var isFld = flds.FirstOrDefault(f => f.Name == "s_fipsAlgorithmPolicy");
var originalFipsValue = CryptoConfig.AllowOnlyFipsAlgorithms;
try
{
if (!originalFipsValue)
{
haveFld.SetValue(null, true);
isFld.SetValue(null, true);
}
MockForGetPagedUsers();
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Users", action, HttpMethod.Get, routeDefaults: routeDefaults, url: url);
verification(response);
}
finally
{
if (!originalFipsValue)
{
haveFld.SetValue(null, false);
isFld.SetValue(null, false);
}
}
}
}
}
@@ -4,7 +4,6 @@ using Umbraco.Web;
namespace Umbraco.Tests.Web.Mvc
{
[TestFixture]
public class HtmlHelperExtensionMethodsTests
{
@@ -1,37 +0,0 @@
using NUnit.Framework;
using Umbraco.Web;
using Umbraco.Web.Mvc;
namespace Umbraco.Tests.Web.Mvc
{
[TestFixture]
public class ValidateUmbracoFormRouteStringAttributeTests
{
[Test]
public void Validate_Route_String()
{
var attribute = new ValidateUmbracoFormRouteStringAttribute();
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(null, null, null, null));
const string ControllerName = "Test";
const string ControllerAction = "Index";
const string Area = "MyArea";
var validUfprt = UrlHelperRenderExtensions.CreateEncryptedRouteString(ControllerName, ControllerAction, Area);
var invalidUfprt = validUfprt + "z";
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(invalidUfprt, null, null, null));
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(validUfprt, ControllerName, ControllerAction, "doesntMatch"));
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(validUfprt, ControllerName, ControllerAction, null));
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(validUfprt, ControllerName, "doesntMatch", Area));
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(validUfprt, ControllerName, null, Area));
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(validUfprt, "doesntMatch", ControllerAction, Area));
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(validUfprt, null, ControllerAction, Area));
Assert.DoesNotThrow(() => attribute.ValidateRouteString(validUfprt, ControllerName, ControllerAction, Area));
Assert.DoesNotThrow(() => attribute.ValidateRouteString(validUfprt, ControllerName.ToLowerInvariant(), ControllerAction.ToLowerInvariant(), Area.ToLowerInvariant()));
}
}
}
@@ -1,99 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Examine;
using Examine.LuceneEngine.Providers;
using Lucene.Net.Store;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Examine;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web;
using Umbraco.Web.PublishedCache;
namespace Umbraco.Tests.Web
{
[TestFixture]
public class PublishedContentQueryTests
{
private class TestIndex : LuceneIndex, IUmbracoIndex
{
private readonly string[] _fieldNames;
public TestIndex(string name, Directory luceneDirectory, string[] fieldNames)
: base(name, luceneDirectory, null, null, null, null)
{
_fieldNames = fieldNames;
}
public bool EnableDefaultEventHandler => throw new NotImplementedException();
public bool PublishedValuesOnly => throw new NotImplementedException();
public IEnumerable<string> GetFields() => _fieldNames;
}
private TestIndex CreateTestIndex(Directory luceneDirectory, string[] fieldNames)
{
var indexer = new TestIndex("TestIndex", luceneDirectory, fieldNames);
using (indexer.ProcessNonAsync())
{
//populate with some test data
indexer.IndexItem(new ValueSet("1", "content", new Dictionary<string, object>
{
[fieldNames[0]] = "Hello world, there are products here",
[UmbracoContentIndex.VariesByCultureFieldName] = "n"
}));
indexer.IndexItem(new ValueSet("2", "content", new Dictionary<string, object>
{
[fieldNames[1]] = "Hello world, there are products here",
[UmbracoContentIndex.VariesByCultureFieldName] = "y"
}));
indexer.IndexItem(new ValueSet("3", "content", new Dictionary<string, object>
{
[fieldNames[2]] = "Hello world, there are products here",
[UmbracoContentIndex.VariesByCultureFieldName] = "y"
}));
}
return indexer;
}
private PublishedContentQuery CreatePublishedContentQuery(IIndex indexer)
{
var examineManager = new Mock<IExamineManager>();
IIndex outarg = indexer;
examineManager.Setup(x => x.TryGetIndex("TestIndex", out outarg)).Returns(true);
var contentCache = new Mock<IPublishedContentCache>();
contentCache.Setup(x => x.GetById(It.IsAny<int>())).Returns((int intId) => Mock.Of<IPublishedContent>(x => x.Id == intId));
var snapshot = Mock.Of<IPublishedSnapshot>(x => x.Content == contentCache.Object);
var variationContext = new VariationContext();
var variationContextAccessor = Mock.Of<IVariationContextAccessor>(x => x.VariationContext == variationContext);
return new PublishedContentQuery(snapshot, variationContextAccessor, examineManager.Object);
}
[TestCase("fr-fr", ExpectedResult = "1, 3", TestName = "Search Culture: fr-fr. Must return both fr-fr and invariant results")]
[TestCase("en-us", ExpectedResult = "1, 2", TestName = "Search Culture: en-us. Must return both en-us and invariant results")]
[TestCase("*", ExpectedResult = "1, 2, 3", TestName = "Search Culture: *. Must return all cultures and all invariant results")]
[TestCase(null, ExpectedResult = "1", TestName = "Search Culture: null. Must return only invariant results")]
public string Search(string culture)
{
using (var luceneDir = new RandomIdRAMDirectory())
{
var fieldNames = new[] { "title", "title_en-us", "title_fr-fr" };
using (var indexer = CreateTestIndex(luceneDir, fieldNames))
{
var pcq = CreatePublishedContentQuery(indexer);
var results = pcq.Search("Products", culture, "TestIndex");
var ids = results.Select(x => x.Content.Id).ToArray();
return string.Join(", ", ids);
}
}
}
}
}
+3 -7
View File
@@ -1,8 +1,5 @@
using System;
using System.Text;
using Examine.LuceneEngine;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
@@ -16,19 +13,18 @@ using Umbraco.Web;
namespace Umbraco.Tests.Web
{
[TestFixture]
public class UmbracoHelperTests
{
{
[TearDown]
public void TearDown()
{
Current.Reset();
}
// ------- Int32 conversion tests
[Test]
public static void Converting_Boxed_34_To_An_Int_Returns_34()
@@ -23,7 +23,7 @@ module.exports = function(files, out) {
// sort files in stream by path or any custom sort comparator
task = task.pipe(babel())
.pipe(sort())
.pipe(embedTemplates({ basePath: "./src/", minimize:{ loose: true } }))
.pipe(embedTemplates({ basePath: "./src/" }))
.pipe(concat(out))
.pipe(wrap('(function(){\n%= body %\n})();'))
.pipe(gulp.dest(config.root + config.targets.js));
@@ -94,10 +94,6 @@
content.apps[0].active = true;
$scope.appChanged(content.apps[0]);
}
// otherwise make sure the save options are up to date with the current content state
else {
createButtons($scope.content);
}
editorState.set(content);
@@ -1,7 +1,7 @@
(function () {
'use strict';
function ContentNodeInfoDirective($timeout, logResource, eventsService, userService, localizationService, dateHelper, editorService, redirectUrlsResource, overlayService, entityResource) {
function ContentNodeInfoDirective($timeout, logResource, eventsService, userService, localizationService, dateHelper, editorService, redirectUrlsResource, overlayService) {
function link(scope) {
@@ -16,12 +16,8 @@
scope.disableTemplates = Umbraco.Sys.ServerVariables.features.disabledFeatures.disableTemplates;
scope.allowChangeDocumentType = false;
scope.allowChangeTemplate = false;
scope.allTemplates = [];
function onInit() {
entityResource.getAll("Template").then(function (templates) {
scope.allTemplates = templates;
});
// set currentVariant
scope.currentVariant = _.find(scope.node.variants, (v) => v.active);
@@ -162,12 +158,8 @@
}
scope.openTemplate = function () {
var template = _.findWhere(scope.allTemplates, {alias: scope.node.template})
if (!template) {
return;
}
var templateEditor = {
id: template.id,
id: scope.node.templateId,
submit: function (model) {
editorService.close();
},
@@ -1,7 +1,7 @@
(function () {
'use strict';
function EditorContentHeader(serverValidationManager, localizationService, editorState) {
function EditorContentHeader(serverValidationManager) {
function link(scope, el, attr, ctrl) {
@@ -13,24 +13,7 @@
if (!scope.serverValidationAliasField) {
scope.serverValidationAliasField = "Alias";
}
scope.isNew = scope.content.state == "NotCreated";
localizationService.localizeMany([
scope.isNew ? "placeholders_a11yCreateItem" : "placeholders_a11yEdit",
"placeholders_a11yName"]
).then(function (data) {
scope.a11yMessage = data[0];
scope.a11yName = data[1];
if (!scope.isNew) {
scope.a11yMessage += " " + scope.content.name;
} else {
var name = editorState.current.contentTypeName;
scope.a11yMessage += " " + name;
scope.a11yName = name + " " + scope.a11yName;
}
});
scope.vm = {};
scope.vm.dropdownOpen = false;
scope.vm.currentVariant = "";
@@ -16,7 +16,9 @@
editor.moveRight = true;
editor.level = 0;
editor.styleIndex = 0;
editor.infinityMode = true;
// push the new editor to the dom
scope.editors.push(editor);
@@ -101,14 +101,14 @@ angular.module('umbraco.directives')
var eventBindings = [];
function oneTimeClick(event) {
var el = event.target.nodeName;
//ignore link and button clicks
var els = ["INPUT", "A", "BUTTON"];
if (els.indexOf(el) >= 0) { return; }
// ignore clicks on button groups toggles (i.e. the save and publish button)
var parents = $(event.target).closest("[data-element='button-group-toggle']");
if (parents.length > 0) {
return;
}
// ignore clicks on new overlay
var parents = $(event.target).parents("a,button,.umb-overlay,.umb-tour");
parents = $(event.target).parents(".umb-overlay,.umb-tour");
if (parents.length > 0) {
return;
}
@@ -131,6 +131,12 @@ angular.module('umbraco.directives')
return;
}
// ignore clicks on dialog actions
var actions = $(event.target).parents(".umb-action");
if (actions.length === 1) {
return;
}
//ignore clicks inside this element
if ($(element).has($(event.target)).length > 0) {
return;
@@ -5,7 +5,7 @@ angular.module("umbraco.directives")
uniqueId: '=',
value: '=',
configuration: "=", //this is the RTE configuration
datatypeKey: '@',
datatypeId: '@',
ignoreUserStartNodes: '@'
},
templateUrl: 'views/components/grid/grid-rte.html',
@@ -43,7 +43,7 @@ angular.module("umbraco.directives")
scope.config = {
ignoreUserStartNodes: scope.ignoreUserStartNodes === "true"
}
scope.dataTypeKey = scope.datatypeKey; //Yes - this casing is rediculous, but it's because the var starts with `data` so it can't be `data-type-id` :/
scope.dataTypeId = scope.datatypeId; //Yes - this casing is rediculous, but it's because the var starts with `data` so it can't be `data-type-id` :/
//stores a reference to the editor
var tinyMceEditor = null;
@@ -12,7 +12,7 @@ function treeSearchBox(localizationService, searchService, $q) {
searchFromName: "@",
showSearch: "@",
section: "@",
datatypeKey: "@",
datatypeId: "@",
hideSearchCallback: "=",
searchCallback: "="
},
@@ -63,8 +63,8 @@ function treeSearchBox(localizationService, searchService, $q) {
}
//append dataTypeId value if there is one
if (scope.datatypeKey) {
searchArgs["dataTypeKey"] = scope.datatypeKey;
if (scope.datatypeId) {
searchArgs["dataTypeId"] = scope.datatypeId;
}
searcher(searchArgs).then(function (data) {
@@ -4,7 +4,7 @@
@restrict A
@description
Use this directive make an element sticky and follow the page when scrolling. `umb-sticky-bar--active` class is applied when the element is stuck
Use this directive make an element sticky and follow the page when scrolling.
<h3>Markup example</h3>
<pre>
@@ -12,102 +12,140 @@ Use this directive make an element sticky and follow the page when scrolling. `u
<div
class="my-sticky-bar"
umb-sticky-bar>
umb-sticky-bar
scrollable-container=".container">
</div>
</div>
</pre>
<h3>CSS example</h3>
<pre>
.my-sticky-bar {
padding: 15px 0;
background: #000000;
position: relative;
top: 0;
}
.my-sticky-bar.-umb-sticky-bar {
top: 100px;
}
</pre>
@param {string} scrollableContainer Set the class (".element") or the id ("#element") of the scrollable container element.
**/
(function () {
'use strict';
function StickyBarDirective() {
/**
On initial load, the intersector fires if the grid editor is in the viewport
This flag is used to suppress the setClass behaviour on the initial load
**/
var initial = true;
/**
Toggle `umb-sticky-bar--active` class on the sticky-bar element
**/
function setClass(addClass, current) {
if (!initial) {
current.classList.toggle('umb-sticky-bar--active', addClass);
} else {
initial = false;
}
}
/**
Inserts two elements in the umbStickyBar parent element
These are used by the IntersectionObserve to calculate scroll position
**/
function addSentinels(current) {
['-top', '-bottom'].forEach(s => {
const sentinel = document.createElement('div');
sentinel.classList.add('umb-sticky-sentinel', s);
current.parentElement.appendChild(sentinel);
});
}
/**
Calls into setClass when the footer sentinel enters/exits the bottom of the container
Container is the parent element of the umbStickyBar element
**/
function observeFooter(current, container) {
const observer = new IntersectionObserver((records, observer) => {
let [target, rootBounds, intersected] = [records[0].boundingClientRect, records[0].rootBounds, records[0].intersectionRatio === 1];
if (target.bottom > rootBounds.top && intersected) {
setClass(true, current);
}
if (target.top < rootBounds.top && target.bottom < rootBounds.bottom) {
setClass(false, current);
}
}, {
threshold: [1],
root: container
});
observer.observe(current.parentElement.querySelector('.umb-sticky-sentinel.-bottom'));
}
/**
Calls into setClass when the header sentinel enters/exits the top of the container
Container is the parent element of the umbStickyBar element
**/
function observeHeader(current, container) {
const observer = new IntersectionObserver((records, observer) => {
let [target, rootBounds] = [records[0].boundingClientRect, records[0].rootBounds];
if (target.bottom < rootBounds.top) {
setClass(true, current);
}
if (target.bottom >= rootBounds.top && target.bottom < rootBounds.bottom) {
setClass(false, current);
}
}, {
threshold: [0],
root: container
});
observer.observe(current.parentElement.querySelector('.umb-sticky-sentinel.-top'));
}
function StickyBarDirective($rootScope) {
function link(scope, el, attr, ctrl) {
let current = el[0];
let container = current.closest('[data-element="editor-container"]');
var bar = $(el);
var scrollableContainer = null;
var clonedBar = null;
var cloneIsMade = false;
addSentinels(current);
function activate() {
if (bar.parents(".umb-property").length > 1) {
bar.addClass("nested");
return;
}
if (attr.scrollableContainer) {
scrollableContainer = bar.closest(attr.scrollableContainer);
} else {
scrollableContainer = $(window);
}
scrollableContainer.on('scroll.umbStickyBar', determineVisibility).trigger("scroll");
$(window).on('resize.umbStickyBar', determineVisibility);
scope.$on('$destroy', function () {
scrollableContainer.off('.umbStickyBar');
$(window).off('.umbStickyBar');
});
}
function determineVisibility() {
var barTop = bar[0].offsetTop;
var scrollTop = scrollableContainer.scrollTop();
if (scrollTop > barTop) {
if (!cloneIsMade) {
createClone();
clonedBar.css({
'visibility': 'visible'
});
} else {
calculateSize();
}
} else {
if (cloneIsMade) {
//remove cloned element (switched places with original on creation)
bar.remove();
bar = clonedBar;
clonedBar = null;
bar.removeClass('-umb-sticky-bar');
bar.css({
position: 'relative',
'width': 'auto',
'height': 'auto',
'z-index': 'auto',
'visibility': 'visible'
});
cloneIsMade = false;
}
}
}
function calculateSize() {
var width = bar.innerWidth();
clonedBar.css({
width: width + 10 // + 10 (5*2) because we need to add border to avoid seeing the shadow beneath. Look at the CSS.
});
}
function createClone() {
//switch place with cloned element, to keep binding intact
clonedBar = bar;
bar = clonedBar.clone();
clonedBar.after(bar);
clonedBar.addClass('-umb-sticky-bar');
clonedBar.css({
'position': 'fixed',
// if you change this z-index value, make sure the sticky editor sub headers do not
// clash with umb-dropdown (e.g. the content actions dropdown in content list view)
'z-index': 99,
'visibility': 'hidden'
});
cloneIsMade = true;
calculateSize();
}
activate();
observeHeader(current, container);
observeFooter(current, container);
}
var directive = {
@@ -133,7 +133,7 @@ function entityResource($q, $http, umbRequestHelper) {
* ##usage
* <pre>
* //get media by id
* entityResource.getById(0, "Media")
* entityResource.getEntityById(0, "Media")
* .then(function(ent) {
* var myDoc = ent;
* alert('its here!');
@@ -172,7 +172,7 @@ function entityResource($q, $http, umbRequestHelper) {
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
"GetUrlAndAnchors",
[{ id: id }])),
{ id: id })),
'Failed to retrieve url and anchors data for id ' + id);
},
@@ -204,7 +204,7 @@ function entityResource($q, $http, umbRequestHelper) {
* ##usage
* <pre>
* //Get templates for ids
* entityResource.getByIds( [1234,2526,28262], "Template")
* entityResource.getEntitiesByIds( [1234,2526,28262], "Template")
* .then(function(templateArray) {
* var myDoc = contentArray;
* alert('they are here!');
@@ -327,8 +327,8 @@ function entityResource($q, $http, umbRequestHelper) {
{ type: type },
{ culture: culture}
];
if (options && options.dataTypeKey) {
args.push({ dataTypeKey: options.dataTypeKey });
if (options && options.dataTypeId) {
args.push({ dataTypeId: options.dataTypeId });
}
return umbRequestHelper.resourcePromise(
@@ -356,8 +356,8 @@ function entityResource($q, $http, umbRequestHelper) {
getChildren: function (id, type, options) {
var args = [{ id: id }, { type: type }];
if (options && options.dataTypeKey) {
args.push({ dataTypeKey: options.dataTypeKey });
if (options && options.dataTypeId) {
args.push({ dataTypeId: options.dataTypeId });
}
return umbRequestHelper.resourcePromise(
@@ -404,8 +404,7 @@ function entityResource($q, $http, umbRequestHelper) {
pageNumber: 100,
filter: '',
orderDirection: "Ascending",
orderBy: "SortOrder",
dataTypeKey: null
orderBy: "SortOrder"
};
if (options === undefined) {
options = {};
@@ -422,7 +421,6 @@ function entityResource($q, $http, umbRequestHelper) {
options.orderDirection = "Descending";
}
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
@@ -436,7 +434,7 @@ function entityResource($q, $http, umbRequestHelper) {
orderBy: options.orderBy,
orderDirection: options.orderDirection,
filter: encodeURIComponent(options.filter),
dataTypeKey: options.dataTypeKey
dataTypeId: options.dataTypeId
}
)),
'Failed to retrieve child data for id ' + parentId);
@@ -478,7 +476,7 @@ function entityResource($q, $http, umbRequestHelper) {
filter: '',
orderDirection: "Ascending",
orderBy: "SortOrder",
dataTypeKey: null
dataTypeId: null
};
if (options === undefined) {
options = {};
@@ -508,7 +506,7 @@ function entityResource($q, $http, umbRequestHelper) {
orderBy: options.orderBy,
orderDirection: options.orderDirection,
filter: encodeURIComponent(options.filter),
dataTypeKey: options.dataTypeKey
dataTypeId: options.dataTypeId
}
)),
'Failed to retrieve child data for id ' + parentId);
@@ -537,15 +535,15 @@ function entityResource($q, $http, umbRequestHelper) {
* @returns {Promise} resourcePromise object containing the entity array.
*
*/
search: function (query, type, searchFrom, canceler, dataTypeKey) {
search: function (query, type, searchFrom, canceler, dataTypeId) {
var args = [{ query: query }, { type: type }];
if (searchFrom) {
args.push({ searchFrom: searchFrom });
}
if (dataTypeKey) {
args.push({ dataTypeKey: dataTypeKey });
if (dataTypeId) {
args.push({ dataTypeId: dataTypeId });
}
var httpConfig = {};
@@ -261,7 +261,7 @@ When building a custom infinite editor view you can use the same components as a
*/
unbindKeyboardShortcuts();
// set flag so we know when the editor is open in "infinite mode"
// set flag so we know when the editor is open in "infinie mode"
editor.infiniteMode = true;
editors.push(editor);
@@ -67,7 +67,7 @@ angular.module('umbraco.services')
throw "args.term is required";
}
return entityResource.search(args.term, "Document", args.searchFrom, args.canceler, args.dataTypeKey).then(function (data) {
return entityResource.search(args.term, "Document", args.searchFrom, args.canceler, args.dataTypeId).then(function (data) {
_.each(data, function (item) {
searchResultFormatter.configureContentResult(item);
});
@@ -92,7 +92,7 @@ angular.module('umbraco.services')
throw "args.term is required";
}
return entityResource.search(args.term, "Media", args.searchFrom, args.canceler, args.dataTypeKey).then(function (data) {
return entityResource.search(args.term, "Media", args.searchFrom, args.canceler, args.dataTypeId).then(function (data) {
_.each(data, function (item) {
searchResultFormatter.configureMediaResult(item);
});
@@ -1121,7 +1121,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
entityResource.getAnchors(args.model.value).then(function (anchorValues) {
var linkPicker = {
currentTarget: currentTarget,
dataTypeKey: args.model.dataTypeKey,
dataTypeId: args.model.dataTypeId,
ignoreUserStartNodes: args.model.config.ignoreUserStartNodes,
anchors: anchorValues,
submit: function (model) {
@@ -1159,7 +1159,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
disableFolderSelect: true,
startNodeId: startNodeId,
startNodeIsVirtual: startNodeIsVirtual,
dataTypeKey: args.model.dataTypeKey,
dataTypeId: args.model.dataTypeId,
submit: function (model) {
self.insertMediaInEditor(args.editor, model.selection[0]);
editorService.close();
@@ -32,32 +32,15 @@
border-radius: 3px;
}
[umb-sticky-bar] {
.umb-editor-sub-header.-umb-sticky-bar {
box-shadow: 0 6px 3px -3px rgba(0,0,0,.16);
transition: box-shadow 240ms;
margin-top: 0;
margin-top: 0;
margin-bottom: 0;
position:sticky;
z-index: 99;
top: calc(@appHeaderHeight + @editorHeaderHeight);
&.umb-sticky-bar--active {
box-shadow: 0 6px 3px -3px rgba(0,0,0,.16);
}
}
.umb-sticky-sentinel {
position: absolute;
left: 0;
width: 100%;
pointer-events: none;
&.-top {
top:0px;
height:1px;
}
&.-bottom {
bottom:50px;
height:10px;
.umb-editor--infinityMode & {
top: calc(@editorHeaderHeight);
}
}
@@ -17,7 +17,7 @@
z-index: @zIndexEditor;
}
.umb-editor--infiniteMode {
.umb-editor--infinityMode {
transform: none;
will-change: transform;
transition: transform 400ms ease-in-out;
@@ -65,7 +65,7 @@
width: 500px;
will-change: transform;
left: auto;
.umb-editor-container {
max-width: 500px;
}
@@ -90,3 +90,14 @@
opacity: 1;
transition: opacity 320ms 20ms, visibility 0s;
}
.umb-editor--trashed-message {
background:@errorBackground;
color:@errorText;
padding:10px;
margin-bottom:20px;
i {
margin-right:5px;
}
}
@@ -94,7 +94,6 @@
font-size: 14px;
color: @black;
margin-left: 10px;
text-align: left;
}
small {
@@ -5,7 +5,6 @@
// --------------------------------------------------
.umb-property-editor {
width: 100%;
position:relative;
}
.umb-property-editor-tiny {
@@ -166,6 +165,8 @@
.sp-replacer {
display: inline-flex;
margin-right: 18px;
border: solid 1px @gray-8;
border-radius: 3px;
}
label {
@@ -20,14 +20,14 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
$scope.model.title = value;
});
}
$scope.customTreeParams = dialogOptions.dataTypeKey ? "dataTypeKey=" + dialogOptions.dataTypeKey : "";
$scope.customTreeParams = dialogOptions.dataTypeId ? "dataTypeId=" + dialogOptions.dataTypeId : "";
$scope.dialogTreeApi = {};
$scope.model.target = {};
$scope.searchInfo = {
searchFromId: null,
searchFromName: null,
showSearch: false,
dataTypeKey: dialogOptions.dataTypeKey,
dataTypeId: dialogOptions.dataTypeId,
results: [],
selectedSearchResults: []
};
@@ -59,10 +59,10 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
if (dialogOptions.currentTarget) {
// clone the current target so we don't accidentally update the caller's model while manipulating $scope.model.target
$scope.model.target = angular.copy(dialogOptions.currentTarget);
// if we have a node ID, we fetch the current node to build the form data
//if we have a node ID, we fetch the current node to build the form data
if ($scope.model.target.id || $scope.model.target.udi) {
// will be either a udi or an int
//will be either a udi or an int
var id = $scope.model.target.udi ? $scope.model.target.udi : $scope.model.target.id;
if ($scope.model.target.udi) {
@@ -175,7 +175,7 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
var mediaPicker = {
startNodeId: startNodeId,
startNodeIsVirtual: startNodeIsVirtual,
dataTypeKey: dialogOptions.dataTypeKey,
dataTypeId: dialogOptions.dataTypeId,
submit: function (model) {
var media = model.selection[0];
@@ -25,7 +25,7 @@
ng-model="model.target.url"
ng-disabled="model.target.id || model.target.udi" />
</umb-control-group>
<umb-control-group label="@defaultdialogs_anchorLinkPicker">
<input type="text"
list="anchors"
@@ -33,13 +33,13 @@
placeholder="@placeholders_anchor"
class="umb-property-editor umb-textstring"
ng-model="model.target.anchor" />
<datalist id="anchors">
<option value="{{a}}" ng-repeat="a in anchorValues"></option>
</datalist>
</umb-control-group>
</div>
<umb-control-group label="@defaultdialogs_nodeNameLinkPicker">
<input type="text"
localize="placeholder"
@@ -47,7 +47,7 @@
class="umb-property-editor umb-textstring"
ng-model="model.target.name" />
</umb-control-group>
<umb-control-group ng-if="showTarget" label="@content_target">
<umb-checkbox
model="vm.openInNewWindow"
@@ -58,28 +58,28 @@
<div class="umb-control-group">
<h5><localize key="defaultdialogs_linkToPage">Link to page</localize></h5>
<div ng-hide="miniListView">
<umb-tree-search-box
<umb-tree-search-box
hide-search-callback="hideSearch"
search-callback="onSearchResults"
search-from-id="{{searchInfo.searchFromId}}"
search-from-name="{{searchInfo.searchFromName}}"
datatype-key="{{searchInfo.dataTypeKey}}"
datatype-id="{{searchInfo.dataTypeId}}"
show-search="{{searchInfo.showSearch}}"
section="{{section}}">
</umb-tree-search-box>
<br />
<umb-tree-search-results
<umb-tree-search-results
ng-if="searchInfo.showSearch"
results="searchInfo.results"
select-result-callback="selectResult">
</umb-tree-search-results>
<div ng-hide="searchInfo.showSearch">
<umb-tree
<umb-tree
section="content"
hideheader="true"
hideoptions="true"
@@ -92,17 +92,17 @@
</umb-tree>
</div>
</div>
<umb-mini-list-view
<umb-mini-list-view
ng-if="miniListView"
node="miniListView"
entity-type="Document"
on-select="selectListViewNode(node)"
on-close="closeMiniListView()">
</umb-mini-list-view>
</div>
<div class="umb-control-group">
<h5><localize key="defaultdialogs_linkToMedia">Link to media</localize></h5>
<a href ng-click="switchToMediaPicker()" class="btn">
@@ -51,17 +51,13 @@ angular.module("umbraco")
$scope.acceptedMediatypes = types;
});
var dataTypeKey = null;
if($scope.model && $scope.model.dataTypeKey) {
dataTypeKey = $scope.model.dataTypeKey;
}
$scope.searchOptions = {
pageNumber: 1,
pageSize: 100,
totalItems: 0,
totalPages: 0,
filter: '',
dataTypeKey: dataTypeKey
dataTypeId: $scope.model.dataTypeId
};
//preload selected item
@@ -164,7 +160,7 @@ angular.module("umbraco")
}
if (folder.id > 0) {
entityResource.getAncestors(folder.id, "media", null, { dataTypeKey: dataTypeKey })
entityResource.getAncestors(folder.id, "media", null, { dataTypeId: $scope.model.dataTypeId })
.then(function (anc) {
$scope.path = _.filter(anc,
function (f) {
@@ -268,7 +264,7 @@ angular.module("umbraco")
// also make sure the node is not trashed
if (nodePath.indexOf($scope.startNodeId.toString()) !== -1 && node.trashed === false) {
$scope.gotoFolder({ id: $scope.lastOpenedNode, name: "Media", icon: "icon-folder", path: node.path });
$scope.gotoFolder({ id: $scope.lastOpenedNode, name: "Media", icon: "icon-folder" });
return true;
} else {
$scope.gotoFolder({ id: $scope.startNodeId, name: "Media", icon: "icon-folder" });
@@ -315,7 +311,6 @@ angular.module("umbraco")
if ($scope.searchOptions.filter) {
searchMedia();
} else {
// reset pagination
$scope.searchOptions = {
pageNumber: 1,
@@ -323,7 +318,7 @@ angular.module("umbraco")
totalItems: 0,
totalPages: 0,
filter: '',
dataTypeKey: dataTypeKey
dataTypeId: $scope.model.dataTypeId
};
getChildren($scope.currentFolder.id);
}
@@ -28,12 +28,12 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController",
vm.treeAlias = $scope.model.treeAlias;
vm.multiPicker = $scope.model.multiPicker;
vm.hideHeader = (typeof $scope.model.hideHeader) === "boolean" ? $scope.model.hideHeader : true;
vm.dataTypeKey = $scope.model.dataTypeKey;
vm.dataTypeId = $scope.model.dataTypeId;
vm.searchInfo = {
searchFromId: $scope.model.startNodeId,
searchFromName: null,
showSearch: false,
dataTypeKey: vm.dataTypeKey,
dataTypeId: vm.dataTypeId,
results: [],
selectedSearchResults: []
}
@@ -192,8 +192,8 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController",
if (vm.selectedLanguage && vm.selectedLanguage.id) {
queryParams["culture"] = vm.selectedLanguage.culture;
}
if (vm.dataTypeKey) {
queryParams["dataTypeKey"] = vm.dataTypeKey;
if (vm.dataTypeId) {
queryParams["dataTypeId"] = vm.dataTypeId;
}
var queryString = $.param(queryParams); //create the query string from the params object
@@ -27,7 +27,7 @@
<a ng-click="vm.selectLanguage(language)" ng-repeat="language in vm.languages" href="">{{language.name}}</a>
</div>
</div>
<div class="umb-control-group">
<umb-tree-search-box
ng-if="vm.enableSearh"
@@ -36,22 +36,22 @@
search-from-id="{{vm.searchInfo.searchFromId}}"
search-from-name="{{vm.searchInfo.searchFromName}}"
show-search="{{vm.searchInfo.showSearch}}"
datatype-key="{{vm.searchInfo.dataTypeKey}}"
datatype-id="{{vm.searchInfo.dataTypeId}}"
section="{{vm.section}}">
</umb-tree-search-box>
</div>
<umb-tree-search-results ng-if="vm.searchInfo.showSearch"
results="vm.searchInfo.results"
select-result-callback="vm.selectResult">
</umb-tree-search-results>
<umb-empty-state ng-if="!vm.hasItems && vm.emptyStateMessage" position="center">
{{ vm.emptyStateMessage }}
</umb-empty-state>
<div ng-if="vm.treeReady" ng-hide="vm.searchInfo.showSearch" ng-animate="'tree-fade-out'">
<umb-tree
<umb-tree
section="{{vm.section}}"
treealias="{{vm.treeAlias}}"
hideheader="{{vm.hideHeader}}"
@@ -65,10 +65,10 @@
api="vm.dialogTreeApi">
</umb-tree>
</div>
</div>
<umb-mini-list-view
<umb-mini-list-view
ng-if="vm.miniListView"
node="vm.miniListView"
entity-type="{{vm.entityType}}"
@@ -93,7 +93,7 @@
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button
ng-if="vm.multiPicker"
type="button"
@@ -101,7 +101,7 @@
label-key="general_submit"
action="vm.submit(model)">
</umb-button>
</umb-editor-footer-content-right>
</umb-editor-footer>
@@ -27,6 +27,12 @@
</ng-form>
<umb-editor-container ng-if="vm.editor.content.apps.length > 0">
<!-- Deleted Context Message Bar (Displayed when viewing node in recycle bin) -->
<div ng-show="vm.content.trashed" class="umb-editor--trashed-message">
<i class="icon icon-trash"></i> <localize key="content_nodeIsInTrash">This content node is in the Recycle Bin</localize>
</div>
<div class="umb-editor-sub-views">
<div ng-repeat="app in vm.editor.content.apps track by app.alias">
<umb-editor-sub-view model="app" content="vm.content" />
@@ -1,5 +1,6 @@
<div
class="umb-editor-sub-header umb-editor-sub-header--{{appearance}}"
umb-sticky-bar
scrollable-container=".umb-editor-container"
ng-transclude>
</div>
@@ -11,30 +11,24 @@
<div class="flex items-center" style="flex: 1;">
<div id="nameField" class="umb-editor-header__name-and-description" style="flex: 1 1 auto;">
<div>
<p tabindex="0" class="sr-only">
{{a11yMessage}}
</p>
</div>
<div class="umb-editor-header__name-wrapper">
<label for="headerName" class="sr-only">{{a11yName}}</label>
<ng-form name="headerNameForm">
<input data-element="editor-name-field"
type="text"
class="umb-editor-header__name-input"
localize="placeholder"
placeholder="@placeholders_entername"
name="headerName"
id="headerName"
ng-model="name"
ng-class="{'name-is-empty': $parent.name===null || $parent.name===''}"
ng-disabled="nameDisabled"
umb-auto-focus
val-server-field="{{serverValidationNameField}}"
required
aria-required="true"
aria-invalid="{{contentForm.headerNameForm.headerName.$invalid ? true : false}}"
autocomplete="off" maxlength="255" />
<input
data-element="editor-name-field"
type="text"
class="umb-editor-header__name-input"
localize="placeholder"
placeholder="@placeholders_entername"
name="headerName"
ng-model="name"
ng-class="{'name-is-empty': $parent.name===null || $parent.name===''}"
ng-disabled="nameDisabled"
umb-auto-focus
val-server-field="{{serverValidationNameField}}"
required
aria-required="true"
aria-invalid="{{contentForm.headerNameForm.headerName.$invalid ? true : false}}"
autocomplete="off" maxlength="255" />
</ng-form>
<a ng-if="content.variants.length > 0 && hideChangeVariant !== true" class="umb-variant-switcher__toggle" href="" ng-click="vm.dropdownOpen = !vm.dropdownOpen" ng-class="{'--error': vm.errorsOnOtherVariants}">
@@ -5,7 +5,7 @@
ng-class="{'umb-editor--small': model.size === 'small',
'umb-editor--animating': model.animating,
'--notInFront': model.inFront !== true,
'umb-editor--infiniteMode': model.infiniteMode,
'umb-editor--infinityMode': model.infinityMode,
'moveRight': model.moveRight,
'umb-editor--n0': model.styleIndex === 0,
'umb-editor--n1': model.styleIndex === 1,
@@ -32,7 +32,7 @@
</div>
<div class="text-center" ng-if="(availableItems | compareArrays:selectedItems:'alias').length === 0">
<small><localize key="general_all">All</localize> {{itemLabel}}s <localize key="grid_areAdded">are added</localize></small>
<small><localize key="general_all">Akk</localize> {{itemLabel}}s <localize key="grid_areAdded">are added</localize></small>
</div>
</div>
@@ -94,11 +94,6 @@ function contentCreateController($scope,
navigationService.hideDialog(showMenu);
};
$scope.editContentType = function() {
$location.path("/settings/documenttypes/edit/" + $scope.contentTypeId).search("view", "permissions");
close();
}
$scope.createBlank = createBlank;
$scope.createOrSelectBlueprintIfAny = createOrSelectBlueprintIfAny;
$scope.createFromBlueprint = createFromBlueprint;
@@ -24,7 +24,7 @@ function ContentEditController($scope, $routeParams, contentResource) {
$scope.page = $routeParams.page;
$scope.isNew = infiniteMode ? $scope.model.create : $routeParams.create;
//load the default culture selected in the main tree if any
$scope.culture = $routeParams.cculture ? $routeParams.cculture : $routeParams.mculture;
$scope.culture = $routeParams.cculture ? $routeParams.cculture : ($routeParams.mculture === "true");
//Bind to $routeUpdate which will execute anytime a location changes but the route is not triggered.
//This is so we can listen to changes on the cculture parameter since that will not cause a route change
@@ -10,7 +10,7 @@
<p class="abstract" ng-if="!hasSettingsAccess"><localize key="create_noDocumentTypesWithNoSettingsAccess"/></p>
<div ng-if="hasSettingsAccess">
<p class="abstract"><localize key="create_noDocumentTypes" /></p>
<button class="btn umb-outline" ng-click="editContentType()">
<button class="btn umb-outline" href="#settings/documentTypes/edit/{{contentTypeId}}?view=permissions" ng-click="close()">
<localize key="create_noDocumentTypesEditPermissions"/>
</button>
</div>
@@ -11,7 +11,7 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action" ng-repeat="documentType in vm.documentTypes | orderBy:'name':false">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createBlueprint(documentType)" prevent-default>
<a href="" class="umb-action-link" ng-click="vm.createBlueprint(documentType)" prevent-default>
<i class="large icon {{documentType.icon}}"></i>
<span class="menu-label">
{{documentType.name}}
@@ -19,7 +19,7 @@
{{documentType.description}}
</small>
</span>
</button>
</a>
</li>
</ul>
@@ -6,20 +6,20 @@
<ul class="umb-actions umb-actions-child">
<li data-element="action-data-type" class="umb-action">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="createDataType()" umb-auto-focus>
<a href="" class="umb-action-link" ng-click="createDataType()" umb-auto-focus>
<i class="large icon icon-autofill"></i>
<span class="menu-label">
<localize key="create_newDataType">New data type</localize>
</span>
</button>
</a>
</li>
<li data-element="action-folder" class="umb-action">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="showCreateFolder()">
<a href="" class="umb-action-link" ng-click="showCreateFolder()">
<i class="large icon icon-folder"></i>
<span class="menu-label">
<localize key="create_newFolder">New folder</localize>...
</span>
</button>
</a>
</li>
</ul>
</div>
@@ -7,36 +7,36 @@
<ul class="umb-actions umb-actions-child">
<li data-element="action-documentType" class="umb-action" ng-hide="model.disableTemplates">
<button href="" ng-click="createDocType()" class="umb-action-link umb-outline btn-reset" umb-auto-focus>
<a href="" ng-click="createDocType()" class="umb-action-link" umb-auto-focus>
<i class="large icon icon-item-arrangement"></i>
<span class="menu-label">
<localize key="content_documentType">Document type</localize>
</span>
</button>
</a>
</li>
<li data-element="action-documentTypeWithoutTemplate" class="umb-action">
<button href="" ng-click="createComponent()" class="umb-action-link umb-outline btn-reset">
<a href="" ng-click="createComponent()" class="umb-action-link">
<i class="large icon icon-item-arrangement"></i>
<span class="menu-label">
<localize ng-if="model.disableTemplates === false" key="create_documentTypeWithoutTemplate"></localize>
<localize ng-if="model.disableTemplates === true" key="content_documentType">Document type></localize>
</span>
</button>
</a>
</li>
<li data-element="action-documentTypeCollection" class="umb-action">
<button href="" ng-click="showCreateDocTypeCollection()" class="umb-action-link umb-outline btn-reset">
<a href="" ng-click="showCreateDocTypeCollection()" class="umb-action-link">
<i class="large icon icon-thumbnail-list"></i>
<span class="menu-label">
Document Type Collection...
<!-- <localize key="content_documentType_collection">Document Type Collection</localize>-->
</span>
</button>
</a>
</li>
<li data-element="action-folder" ng-if="model.allowCreateFolder" class="umb-action">
<button href="" ng-click="showCreateFolder()" class="umb-action-link umb-outline btn-reset">
<a href="" ng-click="showCreateFolder()" class="umb-action-link">
<i class="large icon icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize>...</span>
</button>
</a>
</li>
</ul>
</div>
@@ -10,12 +10,11 @@
vm.numberOfErrors = 0;
vm.commonLogMessages = [];
vm.commonLogMessagesCount = 10;
vm.dateRangeLabel = "";
// ChartJS Options - for count/overview of log distribution
vm.logTypeLabels = ["Debug", "Info", "Warning", "Error", "Fatal"];
vm.logTypeLabels = ["Info", "Debug", "Warning", "Error", "Critical"];
vm.logTypeData = [0, 0, 0, 0, 0];
vm.logTypeColors = ['#eaddd5', '#2bc37c', '#3544b1', '#ff9412', '#d42054'];
vm.logTypeColors = [ '#dcdcdc', '#97bbcd', '#46bfbd', '#fdb45c', '#f7464a'];
vm.chartOptions = {
legend: {
display: true,
@@ -24,42 +23,35 @@
};
let querystring = $location.search();
if (querystring.startDate) {
if(querystring.startDate){
vm.startDate = querystring.startDate;
vm.dateRangeLabel = getDateRangeLabel("Selected Time Period");
} else {
}else{
vm.startDate = new Date(Date.now());
vm.startDate.setDate(vm.startDate.getDate() - 1);
vm.startDate.setDate(vm.startDate.getDate()-1);
vm.startDate = vm.startDate.toIsoDateString();
vm.dateRangeLabel = getDateRangeLabel("Today");
}
if (querystring.endDate) {
if(querystring.endDate){
vm.endDate = querystring.endDate;
if (querystring.endDate === querystring.startDate) {
vm.dateRangeLabel = getDateRangeLabel("Selected Date");
}
} else {
}else{
vm.endDate = new Date(Date.now()).toIsoDateString();
}
vm.period = [vm.startDate, vm.endDate];
//functions
vm.searchLogQuery = searchLogQuery;
vm.findMessageTemplate = findMessageTemplate;
vm.searchErrors = searchErrors;
function preFlightCheck(){
vm.loading = true;
//Do our pre-flight check (to see if we can view logs)
//IE the log file is NOT too big such as 1GB & crash the site
logViewerResource.canViewLogs(vm.startDate, vm.endDate).then(function (result) {
logViewerResource.canViewLogs(vm.startDate, vm.endDate).then(function(result){
vm.loading = false;
vm.canLoadLogs = result;
if (result) {
if(result){
//Can view logs - so initalise
init();
}
@@ -70,39 +62,39 @@
function init() {
vm.loading = true;
var savedSearches = logViewerResource.getSavedSearches().then(function (data) {
vm.searches = data;
},
// fallback to some defaults if error from API response
function () {
vm.searches = [
{
"name": "Find all logs where the Level is NOT Verbose and NOT Debug",
"query": "Not(@Level='Verbose') and Not(@Level='Debug')"
vm.searches = data;
},
// fallback to some defaults if error from API response
function () {
vm.searches = [
{
"name": "Find all logs where the Level is NOT Verbose and NOT Debug",
"query": "Not(@Level='Verbose') and Not(@Level='Debug')"
},
{
"name": "Find all logs that has an exception property (Warning, Error & Fatal with Exceptions)",
"query": "Has(@Exception)"
{
"name": "Find all logs that has an exception property (Warning, Error & Critical with Exceptions)",
"query": "Has(@Exception)"
},
{
"name": "Find all logs that have the property 'Duration'",
"query": "Has(Duration)"
{
"name": "Find all logs that have the property 'Duration'",
"query": "Has(Duration)"
},
{
"name": "Find all logs that have the property 'Duration' and the duration is greater than 1000ms",
"query": "Has(Duration) and Duration > 1000"
{
"name": "Find all logs that have the property 'Duration' and the duration is greater than 1000ms",
"query": "Has(Duration) and Duration > 1000"
},
{
"name": "Find all logs that are from the namespace 'Umbraco.Core'",
"query": "StartsWith(SourceContext, 'Umbraco.Core')"
{
"name": "Find all logs that are from the namespace 'Umbraco.Core'",
"query": "StartsWith(SourceContext, 'Umbraco.Core')"
},
{
"name": "Find all logs that use a specific log message template",
"query": "@MessageTemplate = '[Timing {TimingId}] {EndMessage} ({TimingDuration}ms)'"
{
"name": "Find all logs that use a specific log message template",
"query": "@MessageTemplate = '[Timing {TimingId}] {EndMessage} ({TimingDuration}ms)'"
}
]
});
});
var numOfErrors = logViewerResource.getNumberOfErrors(vm.startDate, vm.endDate).then(function (data) {
vm.numberOfErrors = data;
@@ -110,56 +102,41 @@
var logCounts = logViewerResource.getLogLevelCounts(vm.startDate, vm.endDate).then(function (data) {
vm.logTypeData = [];
for (let [key, value] of Object.entries(data)) {
const index = vm.logTypeLabels.findIndex(x => key.startsWith(x));
if (index > -1) {
vm.logTypeData[index] = value;
}
}
vm.logTypeData.push(data.Information);
vm.logTypeData.push(data.Debug);
vm.logTypeData.push(data.Warning);
vm.logTypeData.push(data.Error);
vm.logTypeData.push(data.Fatal);
});
var commonMsgs = logViewerResource.getMessageTemplates(vm.startDate, vm.endDate).then(function (data) {
var commonMsgs = logViewerResource.getMessageTemplates(vm.startDate, vm.endDate).then(function(data){
vm.commonLogMessages = data;
});
//Set loading indicator to false when these 3 queries complete
$q.all([savedSearches, numOfErrors, logCounts, commonMsgs]).then(function () {
//Set loading indicatior to false when these 3 queries complete
$q.all([savedSearches, numOfErrors, logCounts, commonMsgs]).then(function(data) {
vm.loading = false;
});
$timeout(function () {
navigationService.syncTree({
tree: "logViewer",
path: "-1"
});
navigationService.syncTree({ tree: "logViewer", path: "-1" });
});
}
function searchLogQuery(logQuery) {
$location.path("/settings/logViewer/search").search({
lq: logQuery,
startDate: vm.startDate,
endDate: vm.endDate
});
function searchLogQuery(logQuery){
$location.path("/settings/logViewer/search").search({lq: logQuery, startDate: vm.startDate, endDate: vm.endDate});
}
function findMessageTemplate(template) {
function findMessageTemplate(template){
var logQuery = "@MessageTemplate='" + template.MessageTemplate + "'";
searchLogQuery(logQuery);
}
function getDateRangeLabel(suffix) {
return "Log Overview for " + suffix;
}
function searchErrors(){
var logQuery = "@Level='Fatal' or @Level='Error' or Has(@Exception)";
searchLogQuery(logQuery);
}
preFlightCheck();
/////////////////////
vm.config = {
@@ -170,21 +147,20 @@
maxDate: "today",
conjunction: " to "
};
vm.dateRangeChange = function(selectedDates, dateStr, instance) {
if(selectedDates.length > 0){
vm.startDate = selectedDates[0].toIsoDateString();
vm.endDate = selectedDates[selectedDates.length-1].toIsoDateString(); // Take the last date as end
vm.dateRangeChange = function (selectedDates, dateStr, instance) {
if (selectedDates.length > 0) {
// Update view by re-requesting route with updated querystring.
// By doing this we make sure the URL matches the selected time period, aiding sharing the link.
// Also resolves a minor layout issue where the " to " conjunction between the selected dates
// is collapsed to a comma.
const startDate = selectedDates[0].toIsoDateString();
const endDate = selectedDates[selectedDates.length - 1].toIsoDateString(); // Take the last date as end
$location.path("/settings/logViewer/overview").search({
startDate: startDate,
endDate: endDate
});
if(vm.startDate === vm.endDate){
vm.period = [vm.startDate];
}else{
vm.period = [vm.startDate, vm.endDate];
}
preFlightCheck();
}
}
@@ -3,7 +3,7 @@
<umb-editor-view footer="false">
<umb-editor-header
name="vm.dateRangeLabel"
name="'Log Overview for Today'"
name-locked="true"
hide-icon="true"
hide-description="true"
@@ -74,16 +74,17 @@
<umb-box>
<umb-box-header title="Time Period"></umb-box-header>
<umb-flatpickr class="datepicker"
ng-model="vm.period"
options="vm.config"
on-close="vm.dateRangeChange(selectedDates, dateStr, instance)">
<umb-flatpickr
class="datepicker"
ng-model="vm.period"
options="vm.config"
on-close="vm.dateRangeChange(selectedDates, dateStr, instance)">
</umb-flatpickr>
</umb-box>
<div ng-show=" vm.canLoadLogs">
<!-- No of Errors -->
<umb-box ng-click="vm.searchErrors()" style="cursor:pointer;">
<umb-box ng-click="vm.searchLogQuery('Has(@Exception)')" style="cursor:pointer;">
<umb-box-header title="Number of Errors"></umb-box-header>
<umb-box-content class="block-form" style="font-size: 40px; font-weight:900; text-align:center; color:#fe6561;">
{{ vm.numberOfErrors }}
@@ -11,29 +11,27 @@
vm.showBackButton = true;
vm.page = {};
// this array is also used to map the logTypeColor param onto the log items
// in setLogTypeColors()
vm.logLevels = [
{
name: 'Verbose',
logTypeColor: ''
},
{
name: 'Debug',
logTypeColor: 'gray'
},
{
name: 'Information',
logTypeColor: 'success'
name: 'Debug',
logTypeColor: 'secondary'
},
{
name: 'Warning',
name: 'Information',
logTypeColor: 'primary'
},
{
name: 'Error',
name: 'Warning',
logTypeColor: 'warning'
},
{
name: 'Error',
logTypeColor: 'danger'
},
{
name: 'Fatal',
logTypeColor: 'danger'
@@ -120,7 +118,7 @@
"query": "Not(@Level='Verbose') and Not(@Level='Debug')"
},
{
"name": "Find all logs that has an exception property (Warning, Error & Fatal with Exceptions)",
"name": "Find all logs that has an exception property (Warning, Error & Critical with Exceptions)",
"query": "Has(@Exception)"
},
{
@@ -175,8 +173,25 @@
}
function setLogTypeColor(logItems) {
logItems.forEach(logItem =>
logItem.logTypeColor = vm.logLevels.find(x => x.name === logItem.Level).logTypeColor);
angular.forEach(logItems, function (log) {
switch (log.Level) {
case "Information":
log.logTypeColor = "primary";
break;
case "Debug":
log.logTypeColor = "secondary";
break;
case "Warning":
log.logTypeColor = "warning";
break;
case "Fatal":
case "Error":
log.logTypeColor = "danger";
break;
default:
log.logTypeColor = "gray";
}
});
}
function getFilterName(array) {
@@ -17,13 +17,13 @@
<ul class="umb-actions umb-actions-child">
<li data-element="action-{{docType.alias}}" class="umb-action" ng-repeat="docType in allowedTypes">
<button ng-click="createMediaItem(docType)" class="umb-action-link umb-outline btn-reset" prevent-default>
<a ng-href="" ng-click="createMediaItem(docType)" class="umb-action-link" prevent-default>
<i class="large icon {{docType.icon}}"></i>
<span class="menu-label">
{{docType.name}}
<small>{{docType.description}}</small>
</span>
</button>
</a>
</li>
<!--
<li class="add">
@@ -7,19 +7,19 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="createMediaType()" umb-auto-focus>
<a href="" class="umb-action-link" ng-click="createMediaType()" umb-auto-focus>
<i class="large icon icon-item-arrangement"></i>
<span class="menu-label">
<localize key="general_new">New</localize>
<localize key="content_mediatype">Media type</localize>
</span>
</button>
</a>
</li>
<li class="umb-action">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="showCreateFolder()">
<a href="" class="umb-action-link" ng-click="showCreateFolder()">
<i class="large icon icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize>...</span>
</button>
</a>
</li>
</ul>
</div>
@@ -6,13 +6,13 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action" ng-repeat="docType in allowedTypes">
<button class="umb-action-link umb-outline btn-reset" href="#member/member/edit/{{currentNode.id}}?doctype={{docType.alias}}&create=true" ng-click="hideActions()">
<a class="umb-action-link" href="#member/member/edit/{{currentNode.id}}?doctype={{docType.alias}}&create=true" ng-click="hideActions()">
<i class="large icon {{docType.icon}}"></i>
<span class="menu-label">
{{docType.name}}
<small>{{docType.description}}</small>
</span>
</button>
</a>
</li>
</ul>
@@ -139,7 +139,7 @@ function MemberEditController($scope, $routeParams, $location, appState, memberR
//anytime a user is changing a member's password without the oldPassword, we are in effect resetting it so we need to set that flag here
var passwordProp = _.find(contentEditingHelper.getAllProps($scope.content), function (e) { return e.alias === '_umb_password' });
if (passwordProp && passwordProp.value && !passwordProp.value.reset) {
if (!passwordProp.value.reset) {
//so if the admin is not explicitly resetting the password, flag it for resetting if a new password is being entered
passwordProp.value.reset = !passwordProp.value.oldPassword && passwordProp.config.allowManuallyChangingPassword;
}
@@ -5,13 +5,13 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="showCreateFolder()">
<a href="" class="umb-action-link" ng-click="showCreateFolder()">
<i class="large icon icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize></span>
</button>
</a>
</li>
<li class="umb-action">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="createMemberType()">
<a href="" class="umb-action-link" ng-click="createMemberType()">
<i class="large icon icon-item-arrangement"></i>
@@ -20,7 +20,7 @@
<localize key="content_memberType">Member type</localize>
</span>
</button>
</a>
</li>
</ul>
</div>
@@ -11,28 +11,28 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createFile()" umb-auto-focus>
<a href="" class="umb-action-link" ng-click="vm.createFile()" umb-auto-focus>
<i class="large icon-article"></i>
<span class="menu-label"><localize key="create_newPartialViewMacro">New partial view macro</localize></span>
</button>
</a>
</li>
<li class="umb-action">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createFileWithoutMacro()">
<a href="" class="umb-action-link" ng-click="vm.createFileWithoutMacro()">
<i class="large icon icon-article"></i>
<span class="menu-label"><localize key="create_newPartialViewMacroNoMacro">New partial view macro (without macro)</localize></span>
</button>
</a>
</li>
<li class="umb-action">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFromSnippet()">
<a href="" class="umb-action-link" ng-click="vm.showCreateFromSnippet()">
<i class="large icon icon-article"></i>
<span class="menu-label"><localize key="create_newPartialViewMacroFromSnippet">>New partial view macro from snippet</localize>...</span>
</button>
</a>
</li>
<li class="umb-action">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFolder()">
<a href="" class="umb-action-link" ng-click="vm.showCreateFolder()">
<i class="large icon icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize>...</span>
</button>
</a>
</li>
</ul>
</div>
@@ -44,10 +44,10 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action" ng-repeat="snippet in vm.snippets">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createFileFromSnippet(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
<a href="" class="umb-action-link" ng-click="vm.createFileFromSnippet(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
<i class="icon-article icon" style="font-size: 20px;"></i>
<span class="menu-label" style="margin-left: 0; padding-left: 5px;">{{ snippet.name }}</span>
</button>
</a>
</li>
</ul>
</div>
@@ -10,22 +10,22 @@
<div ng-if="!vm.showSnippets">
<ul class="umb-actions umb-actions-child">
<li class="umb-action">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createPartialView()" umb-auto-focus>
<a href="" class="umb-action-link" ng-click="vm.createPartialView()" umb-auto-focus>
<i class="large icon icon-article"></i>
<span class="menu-label"><localize key="create_newEmptyPartialView">New empty partial view</localize></span>
</button>
</a>
</li>
<li class="umb-action">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFromSnippet()">
<a href="" class="umb-action-link" ng-click="vm.showCreateFromSnippet()">
<i class="large icon icon-article"></i>
<span class="menu-label"><localize key="create_newPartialViewFromSnippet">New partial view from snippet</localize>...</span>
</button>
</a>
</li>
<li class="umb-action">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFolder()">
<a href="" class="umb-action-link" ng-click="vm.showCreateFolder()">
<i class="large icon icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize>...</span>
</button>
</a>
</li>
</ul>
</div>
@@ -34,10 +34,10 @@
<div ng-if="vm.showSnippets">
<ul class="umb-actions umb-actions-child">
<li class="umb-action" ng-repeat="snippet in vm.snippets">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createPartialView(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
<a href="" class="umb-action-link" ng-click="vm.createPartialView(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
<i class="icon-article icon" style="font-size: 20px;"></i>
<span class="menu-label" style="margin-left: 0; padding-left: 5px;">{{ snippet.name }}</span>
</button>
</a>
</li>
</ul>
</div>
@@ -86,7 +86,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
showOpenButton: false,
showEditButton: false,
showPathOnHover: false,
dataTypeKey: null,
dataTypeId: null,
maxNumber: 1,
minNumber: 0,
startNode: {
@@ -140,7 +140,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
entityType: entityType,
filterCssClass: "not-allowed not-published",
startNodeId: null,
dataTypeKey: $scope.model.dataTypeKey,
dataTypeId: $scope.model.dataTypeId,
currentNode: editorState ? editorState.current : null,
callback: function (data) {
if (angular.isArray(data)) {
@@ -162,7 +162,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
// pre-value config on to the dialog options
angular.extend(dialogOptions, $scope.model.config);
dialogOptions.dataTypeKey = $scope.model.dataTypeKey;
dialogOptions.dataTypeId = $scope.model.dataTypeId;
// if we can't pick more than one item, explicitly disable multiPicker in the dialog options
if ($scope.model.config.maxNumber && parseInt($scope.model.config.maxNumber) === 1) {
@@ -1,4 +1,3 @@
//TODO: What is this file? Is it used?? I don't think so
var uSkyGridConfig = [
{
@@ -30,7 +30,7 @@ angular.module("umbraco")
showDetails: true,
disableFolderSelect: true,
onlyImages: true,
dataTypeKey: $scope.model.dataTypeKey,
dataTypeId: $scope.model.dataTypeId,
submit: function(model) {
var selectedImage = model.selection[0];
@@ -4,7 +4,7 @@
configuration="model.config.rte"
value="control.value"
unique-id="control.$uniqueId"
datatype-key="{{model.dataTypeKey}}"
datatype-id="{{model.dataTypeId}}"
ignore-user-start-nodes="{{model.config.ignoreUserStartNodes}}">
</grid-rte>
@@ -187,7 +187,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
var mediaPicker = {
startNodeId: $scope.model.config.startNodeId,
startNodeIsVirtual: $scope.model.config.startNodeIsVirtual,
dataTypeKey: $scope.model.dataTypeKey,
dataTypeId: $scope.model.dataTypeId,
multiPicker: multiPicker,
onlyImages: onlyImages,
disableFolderSelect: disableFolderSelect,
@@ -229,7 +229,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
$scope.sortableOptions = {
disabled: !multiPicker,
disabled: !$scope.isMultiPicker,
items: "li:not(.add-wrapper)",
cancel: ".unsortable",
update: function (e, ui) {
@@ -77,7 +77,7 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
var linkPicker = {
currentTarget: target,
dataTypeKey: $scope.model.dataTypeKey,
dataTypeId: $scope.model.dataTypeId,
ignoreUserStartNodes : $scope.model.config.ignoreUserStartNodes,
submit: function (model) {
if (model.target.url || model.target.anchor) {

Some files were not shown because too many files have changed in this diff Show More