diff --git a/src/Umbraco.Core/Logging/Viewer/ILogViewer.cs b/src/Umbraco.Core/Logging/Viewer/ILogViewer.cs
index 4aaf6d25f2..b39a3f38df 100644
--- a/src/Umbraco.Core/Logging/Viewer/ILogViewer.cs
+++ b/src/Umbraco.Core/Logging/Viewer/ILogViewer.cs
@@ -26,26 +26,26 @@ namespace Umbraco.Core.Logging.Viewer
/// A count of number of errors
/// By counting Warnings with Exceptions, Errors & Fatal messages
///
- int GetNumberOfErrors(DateTimeOffset startDate, DateTimeOffset endDate);
+ int GetNumberOfErrors(LogTimePeriod logTimePeriod);
///
/// Returns a number of the different log level entries
///
- LogLevelCounts GetLogLevelCounts(DateTimeOffset startDate, DateTimeOffset endDate);
+ LogLevelCounts GetLogLevelCounts(LogTimePeriod logTimePeriod);
///
/// Returns a list of all unique message templates and their counts
///
- IEnumerable GetMessageTemplates(DateTimeOffset startDate, DateTimeOffset endDate);
+ IEnumerable GetMessageTemplates(LogTimePeriod logTimePeriod);
bool CanHandleLargeLogs { get; }
- bool CheckCanOpenLogs(DateTimeOffset startDate, DateTimeOffset endDate);
+ bool CheckCanOpenLogs(LogTimePeriod logTimePeriod);
///
/// Returns the collection of logs
///
- PagedResult GetLogs(DateTimeOffset startDate, DateTimeOffset endDate,
+ PagedResult GetLogs(LogTimePeriod logTimePeriod,
int pageNumber = 1,
int pageSize = 100,
Direction orderDirection = Direction.Descending,
diff --git a/src/Umbraco.Core/Logging/Viewer/JsonLogViewer.cs b/src/Umbraco.Core/Logging/Viewer/JsonLogViewer.cs
index 9e6d911489..bbe2f3704d 100644
--- a/src/Umbraco.Core/Logging/Viewer/JsonLogViewer.cs
+++ b/src/Umbraco.Core/Logging/Viewer/JsonLogViewer.cs
@@ -26,7 +26,7 @@ namespace Umbraco.Core.Logging.Viewer
public override bool CanHandleLargeLogs => false;
- public override bool CheckCanOpenLogs(DateTimeOffset startDate, DateTimeOffset endDate)
+ public override bool CheckCanOpenLogs(LogTimePeriod logTimePeriod)
{
//Log Directory
var logDirectory = _logsPath;
@@ -36,7 +36,7 @@ namespace Umbraco.Core.Logging.Viewer
//foreach full day in the range - see if we can find one or more filenames that end with
//yyyyMMdd.json - Ends with due to MachineName in filenames - could be 1 or more due to load balancing
- for (var day = startDate.Date; day.Date <= endDate.Date; day = day.AddDays(1))
+ for (var day = logTimePeriod.StartTime.Date; day.Date <= logTimePeriod.EndTime.Date; day = day.AddDays(1))
{
//Filename ending to search for (As could be multiple)
var filesToFind = GetSearchPattern(day);
@@ -57,7 +57,7 @@ namespace Umbraco.Core.Logging.Viewer
return $"*{day:yyyyMMdd}*.json";
}
- protected override IReadOnlyList GetLogs(DateTimeOffset startDate, DateTimeOffset endDate, ILogFilter filter, int skip, int take)
+ protected override IReadOnlyList GetLogs(LogTimePeriod logTimePeriod, ILogFilter filter, int skip, int take)
{
var logs = new List();
@@ -68,7 +68,7 @@ namespace Umbraco.Core.Logging.Viewer
//foreach full day in the range - see if we can find one or more filenames that end with
//yyyyMMdd.json - Ends with due to MachineName in filenames - could be 1 or more due to load balancing
- for (var day = startDate.Date; day.Date <= endDate.Date; day = day.AddDays(1))
+ for (var day = logTimePeriod.StartTime.Date; day.Date <= logTimePeriod.EndTime.Date; day = day.AddDays(1))
{
//Filename ending to search for (As could be multiple)
var filesToFind = GetSearchPattern(day);
diff --git a/src/Umbraco.Core/Logging/Viewer/LogTimePeriod.cs b/src/Umbraco.Core/Logging/Viewer/LogTimePeriod.cs
new file mode 100644
index 0000000000..0f41faef0a
--- /dev/null
+++ b/src/Umbraco.Core/Logging/Viewer/LogTimePeriod.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Umbraco.Core.Logging.Viewer
+{
+ public class LogTimePeriod
+ {
+ public LogTimePeriod(DateTime startTime, DateTime endTime)
+ {
+ StartTime = startTime;
+ EndTime = endTime;
+ }
+
+ public DateTime StartTime { get; }
+ public DateTime EndTime { get; }
+ }
+}
diff --git a/src/Umbraco.Core/Logging/Viewer/LogViewerSourceBase.cs b/src/Umbraco.Core/Logging/Viewer/LogViewerSourceBase.cs
index 3578a56e74..acb2f5dbf9 100644
--- a/src/Umbraco.Core/Logging/Viewer/LogViewerSourceBase.cs
+++ b/src/Umbraco.Core/Logging/Viewer/LogViewerSourceBase.cs
@@ -27,9 +27,9 @@ namespace Umbraco.Core.Logging.Viewer
///
/// Get all logs from your chosen data source back as Serilog LogEvents
///
- protected abstract IReadOnlyList GetLogs(DateTimeOffset startDate, DateTimeOffset endDate, ILogFilter filter, int skip, int take);
+ protected abstract IReadOnlyList GetLogs(LogTimePeriod logTimePeriod, ILogFilter filter, int skip, int take);
- public abstract bool CheckCanOpenLogs(DateTimeOffset startDate, DateTimeOffset endDate);
+ public abstract bool CheckCanOpenLogs(LogTimePeriod logTimePeriod);
public virtual IReadOnlyList GetSavedSearches()
{
@@ -82,24 +82,24 @@ namespace Umbraco.Core.Logging.Viewer
return searches;
}
- public int GetNumberOfErrors(DateTimeOffset startDate, DateTimeOffset endDate)
+ public int GetNumberOfErrors(LogTimePeriod logTimePeriod)
{
var errorCounter = new ErrorCounterFilter();
- GetLogs(startDate, endDate, errorCounter, 0, int.MaxValue);
+ GetLogs(logTimePeriod, errorCounter, 0, int.MaxValue);
return errorCounter.Count;
}
- public LogLevelCounts GetLogLevelCounts(DateTimeOffset startDate, DateTimeOffset endDate)
+ public LogLevelCounts GetLogLevelCounts(LogTimePeriod logTimePeriod)
{
var counter = new CountingFilter();
- GetLogs(startDate, endDate, counter, 0, int.MaxValue);
+ GetLogs(logTimePeriod, counter, 0, int.MaxValue);
return counter.Counts;
}
- public IEnumerable GetMessageTemplates(DateTimeOffset startDate, DateTimeOffset endDate)
+ public IEnumerable GetMessageTemplates(LogTimePeriod logTimePeriod)
{
var messageTemplates = new MessageTemplateFilter();
- GetLogs(startDate, endDate, messageTemplates, 0, int.MaxValue);
+ GetLogs(logTimePeriod, messageTemplates, 0, int.MaxValue);
var templates = messageTemplates.Counts.
Select(x => new LogTemplate { MessageTemplate = x.Key, Count = x.Value })
@@ -108,14 +108,14 @@ namespace Umbraco.Core.Logging.Viewer
return templates;
}
- public PagedResult GetLogs(DateTimeOffset startDate, DateTimeOffset endDate,
+ public PagedResult GetLogs(LogTimePeriod logTimePeriod,
int pageNumber = 1, int pageSize = 100,
Direction orderDirection = Direction.Descending,
string filterExpression = null,
string[] logLevels = null)
{
var expression = new ExpressionFilter(filterExpression);
- var filteredLogs = GetLogs(startDate, endDate, expression, 0, int.MaxValue);
+ var filteredLogs = GetLogs(logTimePeriod, expression, 0, int.MaxValue);
//This is user used the checkbox UI to toggle which log levels they wish to see
//If an empty array or null - its implied all levels to be viewed
diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs
index 2295745637..d86c682bd5 100644
--- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs
+++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs
@@ -389,7 +389,7 @@ namespace Umbraco.Core.Migrations.Install
private DatabaseSchemaResult ValidateSchema(IScope scope)
{
- if (_databaseFactory.Configured == false)
+ if (_databaseFactory.Initialized == false)
return new DatabaseSchemaResult(_databaseFactory.SqlContext.SqlSyntax);
if (_databaseSchemaValidationResult != null)
@@ -513,7 +513,7 @@ namespace Umbraco.Core.Migrations.Install
private Attempt CheckReadyForInstall()
{
- if (_databaseFactory.Configured == false)
+ if (_databaseFactory.CanConnect == false)
{
return Attempt.Fail(new Result
{
diff --git a/src/Umbraco.Core/Models/Entities/DocumentEntitySlim.cs b/src/Umbraco.Core/Models/Entities/DocumentEntitySlim.cs
index 39ece5fa10..8536b1ded3 100644
--- a/src/Umbraco.Core/Models/Entities/DocumentEntitySlim.cs
+++ b/src/Umbraco.Core/Models/Entities/DocumentEntitySlim.cs
@@ -3,6 +3,7 @@ using System.Linq;
namespace Umbraco.Core.Models.Entities
{
+
///
/// Implements .
///
diff --git a/src/Umbraco.Core/Models/Entities/EntitySlim.cs b/src/Umbraco.Core/Models/Entities/EntitySlim.cs
index 3b8f997602..b095965056 100644
--- a/src/Umbraco.Core/Models/Entities/EntitySlim.cs
+++ b/src/Umbraco.Core/Models/Entities/EntitySlim.cs
@@ -111,52 +111,6 @@ namespace Umbraco.Core.Models.Entities
public virtual bool IsContainer { get; set; }
- ///
- /// Represents a lightweight property.
- ///
- public class PropertySlim
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public PropertySlim(string editorAlias, object value)
- {
- PropertyEditorAlias = editorAlias;
- Value = value;
- }
-
- ///
- /// Gets the property editor alias.
- ///
- public string PropertyEditorAlias { get; }
-
- ///
- /// Gets the property value.
- ///
- public object Value { get; }
-
- protected bool Equals(PropertySlim other)
- {
- return PropertyEditorAlias.Equals(other.PropertyEditorAlias) && Equals(Value, other.Value);
- }
-
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- if (ReferenceEquals(this, obj)) return true;
- if (obj.GetType() != GetType()) return false;
- return Equals((PropertySlim) obj);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- return (PropertyEditorAlias.GetHashCode() * 397) ^ (Value != null ? Value.GetHashCode() : 0);
- }
- }
- }
-
#region IDeepCloneable
///
diff --git a/src/Umbraco.Core/Models/Entities/IDocumentEntitySlim.cs b/src/Umbraco.Core/Models/Entities/IDocumentEntitySlim.cs
index 38fd9a02f1..0258d49114 100644
--- a/src/Umbraco.Core/Models/Entities/IDocumentEntitySlim.cs
+++ b/src/Umbraco.Core/Models/Entities/IDocumentEntitySlim.cs
@@ -2,6 +2,7 @@
namespace Umbraco.Core.Models.Entities
{
+
///
/// Represents a lightweight document entity, managed by the entity service.
///
diff --git a/src/Umbraco.Core/Models/Entities/IMediaEntitySlim.cs b/src/Umbraco.Core/Models/Entities/IMediaEntitySlim.cs
new file mode 100644
index 0000000000..9440000146
--- /dev/null
+++ b/src/Umbraco.Core/Models/Entities/IMediaEntitySlim.cs
@@ -0,0 +1,14 @@
+namespace Umbraco.Core.Models.Entities
+{
+ ///
+ /// Represents a lightweight media entity, managed by the entity service.
+ ///
+ public interface IMediaEntitySlim : IContentEntitySlim
+ {
+
+ ///
+ /// The media file's path/url
+ ///
+ string MediaPath { get; }
+ }
+}
diff --git a/src/Umbraco.Core/Models/Entities/MediaEntitySlim.cs b/src/Umbraco.Core/Models/Entities/MediaEntitySlim.cs
new file mode 100644
index 0000000000..6292a5a35a
--- /dev/null
+++ b/src/Umbraco.Core/Models/Entities/MediaEntitySlim.cs
@@ -0,0 +1,10 @@
+namespace Umbraco.Core.Models.Entities
+{
+ ///
+ /// Implements .
+ ///
+ public class MediaEntitySlim : ContentEntitySlim, IMediaEntitySlim
+ {
+ public string MediaPath { get; set; }
+ }
+}
diff --git a/src/Umbraco.Core/Persistence/IUmbracoDatabaseFactory.cs b/src/Umbraco.Core/Persistence/IUmbracoDatabaseFactory.cs
index 0236fc4bd5..c2d65b824f 100644
--- a/src/Umbraco.Core/Persistence/IUmbracoDatabaseFactory.cs
+++ b/src/Umbraco.Core/Persistence/IUmbracoDatabaseFactory.cs
@@ -10,22 +10,35 @@ namespace Umbraco.Core.Persistence
///
/// Creates a new database.
///
- /// The new database must be disposed after being used.
+ ///
+ /// The new database must be disposed after being used.
+ /// Creating a database causes the factory to initialize if it is not already initialized.
+ ///
IUmbracoDatabase CreateDatabase();
///
- /// Gets a value indicating whether the database factory is configured.
+ /// Gets a value indicating whether the database factory is configured, i.e. whether
+ /// its connection string and provider name have been set. The factory may however not
+ /// be initialized (see ).
///
bool Configured { get; }
+ ///
+ /// Gets a value indicating whether the database factory is initialized, i.e. whether
+ /// its internal state is ready and it has been possible to connect to the database.
+ ///
+ bool Initialized { get; }
+
///
/// Gets the connection string.
///
- /// Throws if the factory is not configured.
+ /// May return null if the database factory is not configured.
string ConnectionString { get; }
///
- /// Gets a value indicating whether the database can connect.
+ /// Gets a value indicating whether the database factory is configured (see ),
+ /// and it is possible to connect to the database. The factory may however not be initialized (see
+ /// ).
///
bool CanConnect { get; }
@@ -37,6 +50,9 @@ namespace Umbraco.Core.Persistence
///
/// Gets the Sql context.
///
+ ///
+ /// Getting the Sql context causes the factory to initialize if it is not already initialized.
+ ///
ISqlContext SqlContext { get; }
///
diff --git a/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions-Bulk.cs b/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions-Bulk.cs
index c9d85feb25..0574e37c4c 100644
--- a/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions-Bulk.cs
+++ b/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions-Bulk.cs
@@ -232,6 +232,14 @@ namespace Umbraco.Core.Persistence
using (var copy = new SqlBulkCopy(tConnection, SqlBulkCopyOptions.Default, tTransaction) { BulkCopyTimeout = 10000, DestinationTableName = tableName })
using (var bulkReader = new PocoDataDataReader(records, pocoData, syntax))
{
+ //we need to add column mappings here because otherwise columns will be matched by their order and if the order of them are different in the DB compared
+ //to the order in which they are declared in the model then this will not work, so instead we will add column mappings by name so that this explicitly uses
+ //the names instead of their ordering.
+ foreach(var col in bulkReader.ColumnMappings)
+ {
+ copy.ColumnMappings.Add(col.DestinationColumn, col.DestinationColumn);
+ }
+
copy.WriteToServer(bulkReader);
return bulkReader.RecordsAffected;
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs
index 645ab9f924..ccafb9f771 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs
@@ -140,10 +140,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
while (templateDtoIx < templateDtos.Count && templateDtos[templateDtoIx].ContentTypeNodeId == contentType.Id)
{
var allowedDto = templateDtos[templateDtoIx];
+ templateDtoIx++;
if (!templates.TryGetValue(allowedDto.TemplateNodeId, out var template)) continue;
allowedTemplates.Add(template);
- templateDtoIx++;
-
+
if (allowedDto.IsDefault)
defaultTemplateId = template.Id;
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs
index b4c0e51c22..4a32e373c1 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs
@@ -75,6 +75,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
dtos = page.Items;
totalRecords = page.TotalItems;
}
+ else if (isMedia)
+ {
+ var page = Database.Page(pageIndexToFetch, pageSize, sql);
+ dtos = page.Items;
+ totalRecords = page.TotalItems;
+ }
else
{
var page = Database.Page(pageIndexToFetch, pageSize, sql);
@@ -87,10 +93,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (isContent)
BuildVariants(entities.Cast());
- // TODO: see https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
- if (isMedia)
- BuildProperties(entities, dtos.ToList());
-
return entities;
}
@@ -112,14 +114,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return cdtos.Count == 0 ? null : BuildVariants(BuildDocumentEntity(cdtos[0]));
}
- var dto = Database.FirstOrDefault(sql);
+ var dto = isMedia
+ ? Database.FirstOrDefault(sql)
+ : Database.FirstOrDefault(sql);
+
if (dto == null) return null;
var entity = BuildEntity(false, isMedia, dto);
- if (isMedia)
- BuildProperties(entity, dto);
-
return entity;
}
@@ -162,7 +164,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
: PerformGetAll(objectType);
}
- private IEnumerable GetEntities(Sql sql, bool isContent, bool isMedia, bool loadMediaProperties)
+ private IEnumerable GetEntities(Sql sql, bool isContent, bool isMedia)
{
//isContent is going to return a 1:M result now with the variants so we need to do different things
if (isContent)
@@ -174,15 +176,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
: BuildVariants(cdtos.Select(BuildDocumentEntity)).ToList();
}
- var dtos = Database.Fetch(sql);
- if (dtos.Count == 0) return Enumerable.Empty();
+ var dtos = isMedia
+ ? (IEnumerable)Database.Fetch(sql)
+ : Database.Fetch(sql);
var entities = dtos.Select(x => BuildEntity(false, isMedia, x)).ToArray();
- // TODO: See https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
- if (isMedia && loadMediaProperties)
- BuildProperties(entities, dtos);
-
return entities;
}
@@ -192,7 +191,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var isMedia = objectType == Constants.ObjectTypes.Media;
var sql = GetFullSqlForEntityType(isContent, isMedia, objectType, filter);
- return GetEntities(sql, isContent, isMedia, true);
+ return GetEntities(sql, isContent, isMedia);
}
public IEnumerable GetAllPaths(Guid objectType, params int[] ids)
@@ -238,22 +237,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
sql = translator.Translate();
sql = AddGroupBy(isContent, isMedia, sql, true);
- return GetEntities(sql, isContent, isMedia, true);
- }
-
- // TODO: See https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
- internal IEnumerable GetMediaByQueryWithoutPropertyData(IQuery query)
- {
- var isContent = false;
- var isMedia = true;
-
- var sql = GetBaseWhere(isContent, isMedia, false, null, Constants.ObjectTypes.Media);
-
- var translator = new SqlTranslator(sql, query);
- sql = translator.Translate();
- sql = AddGroupBy(isContent, isMedia, sql, true);
-
- return GetEntities(sql, isContent, isMedia, false);
+ return GetEntities(sql, isContent, isMedia);
}
public UmbracoObjectTypes GetObjectType(int id)
@@ -280,41 +264,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return Database.ExecuteScalar(sql) > 0;
}
- // TODO: see https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
- private void BuildProperties(EntitySlim entity, BaseDto dto)
- {
- var pdtos = Database.Fetch(GetPropertyData(dto.VersionId));
- foreach (var pdto in pdtos)
- BuildProperty(entity, pdto);
- }
-
- // TODO: see https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
- private void BuildProperties(EntitySlim[] entities, List dtos)
- {
- var versionIds = dtos.Select(x => x.VersionId).Distinct().ToList();
- var pdtos = Database.FetchByGroups(versionIds, 2000, GetPropertyData);
-
- var xentity = entities.ToDictionary(x => x.Id, x => x); // nodeId -> entity
- var xdto = dtos.ToDictionary(x => x.VersionId, x => x.NodeId); // versionId -> nodeId
- foreach (var pdto in pdtos)
- {
- var nodeId = xdto[pdto.VersionId];
- var entity = xentity[nodeId];
- BuildProperty(entity, pdto);
- }
- }
-
- // TODO: see https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
- private void BuildProperty(EntitySlim entity, PropertyDataDto pdto)
- {
- // explain ?!
- var value = string.IsNullOrWhiteSpace(pdto.TextValue)
- ? pdto.VarcharValue
- : pdto.TextValue.ConvertToJsonIfPossible();
-
- entity.AdditionalData[pdto.PropertyTypeDto.Alias] = new EntitySlim.PropertySlim(pdto.PropertyTypeDto.DataTypeDto.EditorAlias, value);
- }
-
private DocumentEntitySlim BuildVariants(DocumentEntitySlim entity)
=> BuildVariants(new[] { entity }).First();
@@ -400,31 +349,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return AddGroupBy(isContent, isMedia, sql, true);
}
- private Sql GetPropertyData(int versionId)
- {
- return Sql()
- .Select(r => r.Select(x => x.PropertyTypeDto, r1 => r1.Select(x => x.DataTypeDto)))
- .From()
- .InnerJoin().On((left, right) => left.PropertyTypeId == right.Id)
- .InnerJoin().On((left, right) => left.DataTypeId == right.NodeId)
- .Where(x => x.VersionId == versionId);
- }
-
- private Sql GetPropertyData(IEnumerable versionIds)
- {
- return Sql()
- .Select(r => r.Select(x => x.PropertyTypeDto, r1 => r1.Select(x => x.DataTypeDto)))
- .From()
- .InnerJoin().On((left, right) => left.PropertyTypeId == right.Id)
- .InnerJoin().On((left, right) => left.DataTypeId == right.NodeId)
- .WhereIn(x => x.VersionId, versionIds)
- .OrderBy(x => x.VersionId);
- }
-
// gets the base SELECT + FROM [+ filter] sql
// always from the 'current' content version
protected Sql GetBase(bool isContent, bool isMedia, Action> filter, bool isCount = false)
- {
+ {
var sql = Sql();
if (isCount)
@@ -448,6 +376,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
sql
.AndSelect(x => x.Published, x => x.Edited);
}
+
+ if (isMedia)
+ {
+ sql
+ .AndSelect(x => Alias(x.Path, "MediaPath"));
+ }
}
sql
@@ -467,6 +401,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
.InnerJoin().On((left, right) => left.NodeId == right.NodeId);
}
+ if (isMedia)
+ {
+ sql
+ .InnerJoin().On((left, right) => left.Id == right.Id);
+ }
+
//Any LeftJoin statements need to come last
if (isCount == false)
{
@@ -536,6 +476,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
.AndBy(x => x.Published, x => x.Edited);
}
+ if (isMedia)
+ {
+ sql
+ .AndBy(x => Alias(x.Path, "MediaPath"));
+ }
+
if (isContent || isMedia)
sql
@@ -566,23 +512,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
#region Classes
- [ExplicitColumns]
- internal class UmbracoPropertyDto
- {
- [Column("propertyEditorAlias")]
- public string PropertyEditorAlias { get; set; }
-
- [Column("propertyTypeAlias")]
- public string PropertyAlias { get; set; }
-
- [Column("varcharValue")]
- public string VarcharValue { get; set; }
-
- [Column("textValue")]
- public string TextValue { get; set; }
- }
-
-
///
/// The DTO used to fetch results for a content item with its variation info
///
@@ -594,6 +523,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
public bool Edited { get; set; }
}
+ private class MediaEntityDto : BaseDto
+ {
+ public string MediaPath { get; set; }
+ }
+
public class VariantInfoDto
{
public int NodeId { get; set; }
@@ -645,7 +579,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (isContent)
return BuildDocumentEntity(dto);
if (isMedia)
- return BuildContentEntity(dto);
+ return BuildMediaEntity(dto);
// EntitySlim does not track changes
var entity = new EntitySlim();
@@ -678,11 +612,18 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
entity.ContentTypeThumbnail = dto.Thumbnail;
}
- private static EntitySlim BuildContentEntity(BaseDto dto)
+ private MediaEntitySlim BuildMediaEntity(BaseDto dto)
{
// EntitySlim does not track changes
- var entity = new ContentEntitySlim();
+ var entity = new MediaEntitySlim();
BuildContentEntity(entity, dto);
+
+ if (dto is MediaEntityDto contentDto)
+ {
+ // fill in the media info
+ entity.MediaPath = contentDto.MediaPath;
+ }
+
return entity;
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/SimilarNodeName.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/SimilarNodeName.cs
index 9f27b6b9e3..99e824757d 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/SimilarNodeName.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/SimilarNodeName.cs
@@ -99,7 +99,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (uniqueing)
{
- if (name.NumPos > 0 && name.Name.StartsWith(nodeName) && name.NumVal == uniqueNumber)
+ if (name.NumPos > 0 && name.Name.InvariantStartsWith(nodeName) && name.NumVal == uniqueNumber)
uniqueNumber++;
else
break;
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/UserGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/UserGroupRepository.cs
index 3935027ada..3b247950e4 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/UserGroupRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/UserGroupRepository.cs
@@ -411,8 +411,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return;
//now the user association
- RemoveAllUsersFromGroup(entity.UserGroup.Id);
- AddUsersToGroup(entity.UserGroup.Id, entity.UserIds);
+ RefreshUsersInGroup(entity.UserGroup.Id, entity.UserIds);
}
protected override void PersistUpdatedItem(UserGroupWithUsers entity)
@@ -424,8 +423,18 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return;
//now the user association
- RemoveAllUsersFromGroup(entity.UserGroup.Id);
- AddUsersToGroup(entity.UserGroup.Id, entity.UserIds);
+ RefreshUsersInGroup(entity.UserGroup.Id, entity.UserIds);
+ }
+
+ ///
+ /// Adds a set of users to a group, first removing any that exist
+ ///
+ /// Id of group
+ /// Ids of users
+ private void RefreshUsersInGroup(int groupId, int[] userIds)
+ {
+ RemoveAllUsersFromGroup(groupId);
+ AddUsersToGroup(groupId, userIds);
}
///
@@ -444,7 +453,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// Ids of users
private void AddUsersToGroup(int groupId, int[] userIds)
{
- // TODO: Check if the user exists?
foreach (var userId in userIds)
{
var dto = new User2UserGroupDto
diff --git a/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs
index dc86ff060c..13422f43b1 100644
--- a/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs
+++ b/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs
@@ -28,7 +28,8 @@ namespace Umbraco.Core.Persistence
{
private readonly Lazy _mappers;
private readonly ILogger _logger;
- private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
+
+ private object _lock = new object();
private DatabaseFactory _npocoDatabaseFactory;
private IPocoDataFactory _pocoDataFactory;
@@ -36,12 +37,13 @@ namespace Umbraco.Core.Persistence
private string _providerName;
private DbProviderFactory _dbProviderFactory;
private DatabaseType _databaseType;
- private bool _serverVersionDetected;
private ISqlSyntaxProvider _sqlSyntax;
private RetryPolicy _connectionRetryPolicy;
private RetryPolicy _commandRetryPolicy;
private NPoco.MapperCollection _pocoMappers;
+ private SqlContext _sqlContext;
private bool _upgrading;
+ private bool _initialized;
#region Constructors
@@ -106,36 +108,30 @@ namespace Umbraco.Core.Persistence
#endregion
///
- public bool Configured { get; private set; }
-
- ///
- public string ConnectionString
+ public bool Configured
{
get
{
- EnsureConfigured();
- return _connectionString;
+ lock (_lock)
+ {
+ return !_connectionString.IsNullOrWhiteSpace() && !_providerName.IsNullOrWhiteSpace();
+ }
}
}
///
- public bool CanConnect
- {
- get
- {
- if (!Configured || !DbConnectionExtensions.IsConnectionAvailable(_connectionString, _providerName)) return false;
+ public bool Initialized => Volatile.Read(ref _initialized);
- if (_serverVersionDetected) return true;
+ ///
+ public string ConnectionString => _connectionString;
- if (_databaseType.IsSqlServer())
- DetectSqlServerVersion();
- _serverVersionDetected = true;
+ ///
+ public bool CanConnect =>
+ // actually tries to connect to the database (regardless of configured/initialized)
+ !_connectionString.IsNullOrWhiteSpace() && !_providerName.IsNullOrWhiteSpace() &&
+ DbConnectionExtensions.IsConnectionAvailable(_connectionString, _providerName);
- return true;
- }
- }
-
- private void DetectSqlServerVersion()
+ private void UpdateSqlServerDatabaseType()
{
// replace NPoco database type by a more efficient one
@@ -171,7 +167,15 @@ namespace Umbraco.Core.Persistence
}
///
- public ISqlContext SqlContext { get; private set; }
+ public ISqlContext SqlContext
+ {
+ get
+ {
+ // must be initialized to have a context
+ EnsureInitialized();
+ return _sqlContext;
+ }
+ }
///
public void ConfigureForUpgrade()
@@ -182,63 +186,79 @@ namespace Umbraco.Core.Persistence
///
public void Configure(string connectionString, string providerName)
{
- try
+ if (connectionString.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(connectionString));
+ if (providerName.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(providerName));
+
+ lock (_lock)
{
- _lock.EnterWriteLock();
-
- _logger.Debug("Configuring.");
-
- if (Configured) throw new InvalidOperationException("Already configured.");
-
- if (connectionString.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(connectionString));
- if (providerName.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(providerName));
+ if (Volatile.Read(ref _initialized))
+ throw new InvalidOperationException("Already initialized.");
_connectionString = connectionString;
_providerName = providerName;
-
- _connectionRetryPolicy = RetryPolicyFactory.GetDefaultSqlConnectionRetryPolicyByConnectionString(_connectionString);
- _commandRetryPolicy = RetryPolicyFactory.GetDefaultSqlCommandRetryPolicyByConnectionString(_connectionString);
-
- _dbProviderFactory = DbProviderFactories.GetFactory(_providerName);
- if (_dbProviderFactory == null)
- throw new Exception($"Can't find a provider factory for provider name \"{_providerName}\".");
- _databaseType = DatabaseType.Resolve(_dbProviderFactory.GetType().Name, _providerName);
- if (_databaseType == null)
- throw new Exception($"Can't find an NPoco database type for provider name \"{_providerName}\".");
-
- _sqlSyntax = GetSqlSyntaxProvider(_providerName);
- if (_sqlSyntax == null)
- throw new Exception($"Can't find a sql syntax provider for provider name \"{_providerName}\".");
-
- // ensure we have only 1 set of mappers, and 1 PocoDataFactory, for all database
- // so that everything NPoco is properly cached for the lifetime of the application
- _pocoMappers = new NPoco.MapperCollection { new PocoMapper() };
- var factory = new FluentPocoDataFactory(GetPocoDataFactoryResolver);
- _pocoDataFactory = factory;
- var config = new FluentConfig(xmappers => factory);
-
- // create the database factory
- _npocoDatabaseFactory = DatabaseFactory.Config(x => x
- .UsingDatabase(CreateDatabaseInstance) // creating UmbracoDatabase instances
- .WithFluentConfig(config)); // with proper configuration
-
- if (_npocoDatabaseFactory == null) throw new NullReferenceException("The call to UmbracoDatabaseFactory.Config yielded a null UmbracoDatabaseFactory instance.");
-
- SqlContext = new SqlContext(_sqlSyntax, _databaseType, _pocoDataFactory, _mappers);
-
- _logger.Debug("Configured.");
- Configured = true;
- }
- finally
- {
- if (_lock.IsWriteLockHeld)
- _lock.ExitWriteLock();
}
+
+ // rest to be lazy-initialized
+ }
+
+ private void EnsureInitialized()
+ {
+ LazyInitializer.EnsureInitialized(ref _sqlContext, ref _initialized, ref _lock, Initialize);
+ }
+
+ private SqlContext Initialize()
+ {
+ _logger.Debug("Initializing.");
+
+ if (_connectionString.IsNullOrWhiteSpace()) throw new InvalidOperationException("The factory has not been configured with a proper connection string.");
+ if (_providerName.IsNullOrWhiteSpace()) throw new InvalidOperationException("The factory has not been configured with a proper provider name.");
+
+ // cannot initialize without being able to talk to the database
+ if (!DbConnectionExtensions.IsConnectionAvailable(_connectionString, _providerName))
+ throw new Exception("Cannot connect to the database.");
+
+ _connectionRetryPolicy = RetryPolicyFactory.GetDefaultSqlConnectionRetryPolicyByConnectionString(_connectionString);
+ _commandRetryPolicy = RetryPolicyFactory.GetDefaultSqlCommandRetryPolicyByConnectionString(_connectionString);
+
+ _dbProviderFactory = DbProviderFactories.GetFactory(_providerName);
+ if (_dbProviderFactory == null)
+ throw new Exception($"Can't find a provider factory for provider name \"{_providerName}\".");
+ _databaseType = DatabaseType.Resolve(_dbProviderFactory.GetType().Name, _providerName);
+ if (_databaseType == null)
+ throw new Exception($"Can't find an NPoco database type for provider name \"{_providerName}\".");
+
+ _sqlSyntax = GetSqlSyntaxProvider(_providerName);
+ if (_sqlSyntax == null)
+ throw new Exception($"Can't find a sql syntax provider for provider name \"{_providerName}\".");
+
+ if (_databaseType.IsSqlServer())
+ UpdateSqlServerDatabaseType();
+
+ // ensure we have only 1 set of mappers, and 1 PocoDataFactory, for all database
+ // so that everything NPoco is properly cached for the lifetime of the application
+ _pocoMappers = new NPoco.MapperCollection { new PocoMapper() };
+ var factory = new FluentPocoDataFactory(GetPocoDataFactoryResolver);
+ _pocoDataFactory = factory;
+ var config = new FluentConfig(xmappers => factory);
+
+ // create the database factory
+ _npocoDatabaseFactory = DatabaseFactory.Config(x => x
+ .UsingDatabase(CreateDatabaseInstance) // creating UmbracoDatabase instances
+ .WithFluentConfig(config)); // with proper configuration
+
+ if (_npocoDatabaseFactory == null)
+ throw new NullReferenceException("The call to UmbracoDatabaseFactory.Config yielded a null UmbracoDatabaseFactory instance.");
+
+ _logger.Debug("Initialized.");
+
+ return new SqlContext(_sqlSyntax, _databaseType, _pocoDataFactory, _mappers);
}
///
public IUmbracoDatabase CreateDatabase()
{
+ // must be initialized to create a database
+ EnsureInitialized();
return (IUmbracoDatabase) _npocoDatabaseFactory.GetDatabase();
}
@@ -260,22 +280,6 @@ namespace Umbraco.Core.Persistence
}
}
- // ensures that the database is configured, else throws
- private void EnsureConfigured()
- {
- _lock.EnterReadLock();
- try
- {
- if (Configured == false)
- throw new InvalidOperationException("Not configured.");
- }
- finally
- {
- if (_lock.IsReadLockHeld)
- _lock.ExitReadLock();
- }
- }
-
// method used by NPoco's UmbracoDatabaseFactory to actually create the database instance
private UmbracoDatabase CreateDatabaseInstance()
{
@@ -292,7 +296,7 @@ namespace Umbraco.Core.Persistence
//var db = _umbracoDatabaseAccessor.UmbracoDatabase;
//_umbracoDatabaseAccessor.UmbracoDatabase = null;
//db?.Dispose();
- Configured = false;
+ Volatile.Write(ref _initialized, false);
}
// during tests, the thread static var can leak between tests
diff --git a/src/Umbraco.Core/Services/IEntityService.cs b/src/Umbraco.Core/Services/IEntityService.cs
index 9d0399f324..f03bc640ec 100644
--- a/src/Umbraco.Core/Services/IEntityService.cs
+++ b/src/Umbraco.Core/Services/IEntityService.cs
@@ -15,92 +15,40 @@ namespace Umbraco.Core.Services
/// The identifier of the entity.
IEntitySlim Get(int id);
- ///
- /// Gets an entity.
- ///
- /// The identifier of the entity.
- /// A value indicating whether to load a light entity, or the full entity.
- /// Returns either a , or an actual entity, depending on .
- IUmbracoEntity Get(int id, bool full);
-
///
/// Gets an entity.
///
/// The unique key of the entity.
IEntitySlim Get(Guid key);
- ///
- /// Gets an entity.
- ///
- /// The unique key of the entity.
- /// A value indicating whether to load a light entity, or the full entity.
- /// Returns either a , or an actual entity, depending on .
- IUmbracoEntity Get(Guid key, bool full);
-
///
/// Gets an entity.
///
/// The identifier of the entity.
/// The object type of the entity.
IEntitySlim Get(int id, UmbracoObjectTypes objectType);
-
- ///
- /// Gets an entity.
- ///
- /// The identifier of the entity.
- /// The object type of the entity.
- /// A value indicating whether to load a light entity, or the full entity.
- /// Returns either a , or an actual entity, depending on .
- IUmbracoEntity Get(int id, UmbracoObjectTypes objectType, bool full);
-
+
///
/// Gets an entity.
///
/// The unique key of the entity.
/// The object type of the entity.
IEntitySlim Get(Guid key, UmbracoObjectTypes objectType);
-
- ///
- /// Gets an entity.
- ///
- /// The unique key of the entity.
- /// The object type of the entity.
- /// A value indicating whether to load a light entity, or the full entity.
- /// Returns either a , or an actual entity, depending on .
- IUmbracoEntity Get(Guid key, UmbracoObjectTypes objectType, bool full);
-
+
///
/// Gets an entity.
///
/// The type used to determine the object type of the entity.
/// The identifier of the entity.
IEntitySlim Get(int id) where T : IUmbracoEntity;
-
- ///
- /// Gets an entity.
- ///
- /// The type used to determine the object type of the entity.
- /// The identifier of the entity.
- /// A value indicating whether to load a light entity, or the full entity.
- /// Returns either a , or an actual entity, depending on .
- IUmbracoEntity Get(int id, bool full) where T : IUmbracoEntity;
-
+
///
/// Gets an entity.
///
/// The type used to determine the object type of the entity.
/// The unique key of the entity.
IEntitySlim Get(Guid key) where T : IUmbracoEntity;
-
- ///
- /// Gets an entity.
- ///
- /// The type used to determine the object type of the entity.
- /// The unique key of the entity.
- /// A value indicating whether to load a light entity, or the full entity.
- /// Returns either a , or an actual entity, depending on .
- IUmbracoEntity Get(Guid key, bool full) where T : IUmbracoEntity;
-
+
///
/// Determines whether an entity exists.
///
diff --git a/src/Umbraco.Core/Services/IRelationService.cs b/src/Umbraco.Core/Services/IRelationService.cs
index e2733a311d..ef22632d6e 100644
--- a/src/Umbraco.Core/Services/IRelationService.cs
+++ b/src/Umbraco.Core/Services/IRelationService.cs
@@ -142,52 +142,43 @@ namespace Umbraco.Core.Services
/// Gets the Child object from a Relation as an
///
/// Relation to retrieve child object from
- /// Optional bool to load the complete object graph when set to False
/// An
- IUmbracoEntity GetChildEntityFromRelation(IRelation relation, bool loadBaseType = false);
+ IUmbracoEntity GetChildEntityFromRelation(IRelation relation);
///
/// Gets the Parent object from a Relation as an
///
/// Relation to retrieve parent object from
- /// Optional bool to load the complete object graph when set to False
/// An
- IUmbracoEntity GetParentEntityFromRelation(IRelation relation, bool loadBaseType = false);
+ IUmbracoEntity GetParentEntityFromRelation(IRelation relation);
///
/// Gets the Parent and Child objects from a Relation as a "/> with .
///
/// Relation to retrieve parent and child object from
- /// Optional bool to load the complete object graph when set to False
/// Returns a Tuple with Parent (item1) and Child (item2)
- Tuple GetEntitiesFromRelation(IRelation relation, bool loadBaseType = false);
+ Tuple GetEntitiesFromRelation(IRelation relation);
///
/// Gets the Child objects from a list of Relations as a list of objects.
///
/// List of relations to retrieve child objects from
- /// Optional bool to load the complete object graph when set to False
/// An enumerable list of
- IEnumerable GetChildEntitiesFromRelations(IEnumerable relations, bool loadBaseType = false);
+ IEnumerable GetChildEntitiesFromRelations(IEnumerable relations);
///
/// Gets the Parent objects from a list of Relations as a list of objects.
///
/// List of relations to retrieve parent objects from
- /// Optional bool to load the complete object graph when set to False
/// An enumerable list of
- IEnumerable GetParentEntitiesFromRelations(IEnumerable relations,
- bool loadBaseType = false);
+ IEnumerable GetParentEntitiesFromRelations(IEnumerable relations);
///
/// Gets the Parent and Child objects from a list of Relations as a list of objects.
///
/// List of relations to retrieve parent and child objects from
- /// Optional bool to load the complete object graph when set to False
/// An enumerable list of with
- IEnumerable> GetEntitiesFromRelations(
- IEnumerable relations,
- bool loadBaseType = false);
+ IEnumerable> GetEntitiesFromRelations(IEnumerable relations);
///
/// Relates two objects by their entity Ids.
diff --git a/src/Umbraco.Core/Services/Implement/EntityService.cs b/src/Umbraco.Core/Services/Implement/EntityService.cs
index 00edde48f3..04e2624592 100644
--- a/src/Umbraco.Core/Services/Implement/EntityService.cs
+++ b/src/Umbraco.Core/Services/Implement/EntityService.cs
@@ -7,11 +7,9 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence;
-using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
-using Umbraco.Core.Persistence.Repositories.Implement;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.Services.Implement
@@ -19,30 +17,25 @@ namespace Umbraco.Core.Services.Implement
public class EntityService : ScopeRepositoryService, IEntityService
{
private readonly IEntityRepository _entityRepository;
- private readonly Dictionary GetById, Func GetByKey)> _objectTypes;
+ private readonly Dictionary _objectTypes;
private IQuery _queryRootEntity;
private readonly IdkMap _idkMap;
- public EntityService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory,
- IContentService contentService, IContentTypeService contentTypeService,
- IMediaService mediaService, IMediaTypeService mediaTypeService,
- IDataTypeService dataTypeService,
- IMemberService memberService, IMemberTypeService memberTypeService, IdkMap idkMap,
- IEntityRepository entityRepository)
+ public EntityService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IdkMap idkMap, IEntityRepository entityRepository)
: base(provider, logger, eventMessagesFactory)
{
_idkMap = idkMap;
_entityRepository = entityRepository;
- _objectTypes = new Dictionary, Func)>
+ _objectTypes = new Dictionary
{
- { typeof (IDataType).FullName, (UmbracoObjectTypes.DataType, dataTypeService.GetDataType, dataTypeService.GetDataType) },
- { typeof (IContent).FullName, (UmbracoObjectTypes.Document, contentService.GetById, contentService.GetById) },
- { typeof (IContentType).FullName, (UmbracoObjectTypes.DocumentType, contentTypeService.Get, contentTypeService.Get) },
- { typeof (IMedia).FullName, (UmbracoObjectTypes.Media, mediaService.GetById, mediaService.GetById) },
- { typeof (IMediaType).FullName, (UmbracoObjectTypes.MediaType, mediaTypeService.Get, mediaTypeService.Get) },
- { typeof (IMember).FullName, (UmbracoObjectTypes.Member, memberService.GetById, memberService.GetByKey) },
- { typeof (IMemberType).FullName, (UmbracoObjectTypes.MemberType, memberTypeService.Get, memberTypeService.Get) },
+ { typeof (IDataType).FullName, UmbracoObjectTypes.DataType },
+ { typeof (IContent).FullName, UmbracoObjectTypes.Document },
+ { typeof (IContentType).FullName, UmbracoObjectTypes.DocumentType },
+ { typeof (IMedia).FullName, UmbracoObjectTypes.Media },
+ { typeof (IMediaType).FullName, UmbracoObjectTypes.MediaType },
+ { typeof (IMember).FullName, UmbracoObjectTypes.Member },
+ { typeof (IMemberType).FullName, UmbracoObjectTypes.MemberType },
};
}
@@ -54,162 +47,68 @@ namespace Umbraco.Core.Services.Implement
#endregion
- // gets the getters, throws if not supported
- private (UmbracoObjectTypes ObjectType, Func GetById, Func GetByKey) GetGetters(Type type)
+ // gets the object type, throws if not supported
+ private UmbracoObjectTypes GetObjectType(Type type)
{
- if (type?.FullName == null || !_objectTypes.TryGetValue(type.FullName, out var getters))
+ if (type?.FullName == null || !_objectTypes.TryGetValue(type.FullName, out var objType))
throw new NotSupportedException($"Type \"{type?.FullName ?? ""}\" is not supported here.");
- return getters;
+ return objType;
}
///
public IEntitySlim Get(int id)
{
- return (IEntitySlim) Get(id, false);
- }
-
- ///
- public IUmbracoEntity Get(int id, bool full)
- {
- if (!full)
+ using (ScopeProvider.CreateScope(autoComplete: true))
{
- // get the light entity
- using (ScopeProvider.CreateScope(autoComplete: true))
- {
- return _entityRepository.Get(id);
- }
+ return _entityRepository.Get(id);
}
-
- // get the full entity
- var objectType = GetObjectType(id);
- var entityType = objectType.GetClrType();
- var getters = GetGetters(entityType);
- return getters.GetById(id);
}
///
public IEntitySlim Get(Guid key)
{
- return (IEntitySlim) Get(key, false);
- }
-
- ///
- public IUmbracoEntity Get(Guid key, bool full)
- {
- if (!full)
+ using (ScopeProvider.CreateScope(autoComplete: true))
{
- // get the light entity
- using (ScopeProvider.CreateScope(autoComplete: true))
- {
- return _entityRepository.Get(key);
- }
+ return _entityRepository.Get(key);
}
-
- // get the full entity
- var objectType = GetObjectType(key);
- var entityType = objectType.GetClrType();
- var getters = GetGetters(entityType);
- return getters.GetByKey(key);
}
///
public virtual IEntitySlim Get(int id, UmbracoObjectTypes objectType)
{
- return (IEntitySlim) Get(id, objectType, false);
- }
-
- ///
- public virtual IUmbracoEntity Get(int id, UmbracoObjectTypes objectType, bool full)
- {
- if (!full)
+ using (ScopeProvider.CreateScope(autoComplete: true))
{
- // get the light entity
- using (ScopeProvider.CreateScope(autoComplete: true))
- {
- return _entityRepository.Get(id, objectType.GetGuid());
- }
+ return _entityRepository.Get(id, objectType.GetGuid());
}
-
- // get the full entity
- var entityType = objectType.GetClrType();
- var getters = GetGetters(entityType);
- return getters.GetById(id);
}
///
public IEntitySlim Get(Guid key, UmbracoObjectTypes objectType)
{
- return (IEntitySlim) Get(key, objectType, false);
- }
-
- ///
- public IUmbracoEntity Get(Guid key, UmbracoObjectTypes objectType, bool full)
- {
- if (!full)
+ using (ScopeProvider.CreateScope(autoComplete: true))
{
- // get the light entity
- using (ScopeProvider.CreateScope(autoComplete: true))
- {
- return _entityRepository.Get(key, objectType.GetGuid());
- }
+ return _entityRepository.Get(key, objectType.GetGuid());
}
-
- // get the full entity
- var entityType = objectType.GetClrType();
- var getters = GetGetters(entityType);
- return getters.GetByKey(key);
}
///
public virtual IEntitySlim Get(int id)
where T : IUmbracoEntity
{
- return (IEntitySlim) Get(id, false);
- }
-
- ///
- public virtual IUmbracoEntity Get(int id, bool full)
- where T : IUmbracoEntity
- {
- if (!full)
+ using (ScopeProvider.CreateScope(autoComplete: true))
{
- // get the light entity
- using (ScopeProvider.CreateScope(autoComplete: true))
- {
- return _entityRepository.Get(id);
- }
+ return _entityRepository.Get(id);
}
-
- // get the full entity
- var entityType = typeof (T);
- var getters = GetGetters(entityType);
- return getters.GetById(id);
}
///
public virtual IEntitySlim Get(Guid key)
where T : IUmbracoEntity
{
- return (IEntitySlim) Get(key, false);
- }
-
- ///
- public IUmbracoEntity Get(Guid key, bool full)
- where T : IUmbracoEntity
- {
- if (!full)
+ using (ScopeProvider.CreateScope(autoComplete: true))
{
- // get the light entity
- using (ScopeProvider.CreateScope(autoComplete: true))
- {
- return _entityRepository.Get(key);
- }
+ return _entityRepository.Get(key);
}
-
- // get the full entity
- var entityType = typeof (T);
- var getters = GetGetters(entityType);
- return getters.GetByKey(key);
}
///
@@ -240,8 +139,7 @@ namespace Umbraco.Core.Services.Implement
where T : IUmbracoEntity
{
var entityType = typeof (T);
- var getters = GetGetters(entityType);
- var objectType = getters.ObjectType;
+ var objectType = GetObjectType(entityType);
var objectTypeId = objectType.GetGuid();
using (ScopeProvider.CreateScope(autoComplete: true))
@@ -261,7 +159,7 @@ namespace Umbraco.Core.Services.Implement
if (entityType == null)
throw new NotSupportedException($"Type \"{objectType}\" is not supported here.");
- GetGetters(entityType);
+ GetObjectType(entityType);
using (ScopeProvider.CreateScope(autoComplete: true))
{
@@ -277,7 +175,7 @@ namespace Umbraco.Core.Services.Implement
public virtual IEnumerable GetAll(Guid objectType, params int[] ids)
{
var entityType = ObjectTypes.GetClrType(objectType);
- GetGetters(entityType);
+ GetObjectType(entityType);
using (ScopeProvider.CreateScope(autoComplete: true))
{
@@ -290,8 +188,7 @@ namespace Umbraco.Core.Services.Implement
where T : IUmbracoEntity
{
var entityType = typeof (T);
- var getters = GetGetters(entityType);
- var objectType = getters.ObjectType;
+ var objectType = GetObjectType(entityType);
var objectTypeId = objectType.GetGuid();
using (ScopeProvider.CreateScope(autoComplete: true))
@@ -304,7 +201,7 @@ namespace Umbraco.Core.Services.Implement
public IEnumerable GetAll(UmbracoObjectTypes objectType, Guid[] keys)
{
var entityType = objectType.GetClrType();
- GetGetters(entityType);
+ GetObjectType(entityType);
using (ScopeProvider.CreateScope(autoComplete: true))
{
@@ -316,7 +213,7 @@ namespace Umbraco.Core.Services.Implement
public virtual IEnumerable GetAll(Guid objectType, params Guid[] keys)
{
var entityType = ObjectTypes.GetClrType(objectType);
- GetGetters(entityType);
+ GetObjectType(entityType);
using (ScopeProvider.CreateScope(autoComplete: true))
{
@@ -377,22 +274,6 @@ namespace Umbraco.Core.Services.Implement
}
}
- ///
- /// Gets a collection of children by the parent's Id and UmbracoObjectType without adding property data
- ///
- /// Id of the parent to retrieve children for
- /// An enumerable list of objects
- internal IEnumerable GetMediaChildrenWithoutPropertyData(int parentId)
- {
- using (ScopeProvider.CreateScope(autoComplete: true))
- {
- var query = Query().Where(x => x.ParentId == parentId);
-
- // TODO: see https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
- return ((EntityRepository)_entityRepository).GetMediaByQueryWithoutPropertyData(query);
- }
- }
-
///
public virtual IEnumerable GetDescendants(int id)
{
@@ -578,7 +459,7 @@ namespace Umbraco.Core.Services.Implement
public virtual IEnumerable GetAllPaths(UmbracoObjectTypes objectType, params int[] ids)
{
var entityType = objectType.GetClrType();
- GetGetters(entityType);
+ GetObjectType(entityType);
using (ScopeProvider.CreateScope(autoComplete: true))
{
@@ -590,7 +471,7 @@ namespace Umbraco.Core.Services.Implement
public virtual IEnumerable GetAllPaths(UmbracoObjectTypes objectType, params Guid[] keys)
{
var entityType = objectType.GetClrType();
- GetGetters(entityType);
+ GetObjectType(entityType);
using (ScopeProvider.CreateScope(autoComplete: true))
{
diff --git a/src/Umbraco.Core/Services/Implement/RelationService.cs b/src/Umbraco.Core/Services/Implement/RelationService.cs
index a316d04f8e..405c3a2800 100644
--- a/src/Umbraco.Core/Services/Implement/RelationService.cs
+++ b/src/Umbraco.Core/Services/Implement/RelationService.cs
@@ -285,39 +285,36 @@ namespace Umbraco.Core.Services.Implement
/// Gets the Child object from a Relation as an
///
/// Relation to retrieve child object from
- /// Optional bool to load the complete object graph when set to False
/// An
- public IUmbracoEntity GetChildEntityFromRelation(IRelation relation, bool loadBaseType = false)
+ public IUmbracoEntity GetChildEntityFromRelation(IRelation relation)
{
var objectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
- return _entityService.Get(relation.ChildId, objectType, loadBaseType);
+ return _entityService.Get(relation.ChildId, objectType);
}
///
/// Gets the Parent object from a Relation as an
///
/// Relation to retrieve parent object from
- /// Optional bool to load the complete object graph when set to False
/// An
- public IUmbracoEntity GetParentEntityFromRelation(IRelation relation, bool loadBaseType = false)
+ public IUmbracoEntity GetParentEntityFromRelation(IRelation relation)
{
var objectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ParentObjectType);
- return _entityService.Get(relation.ParentId, objectType, loadBaseType);
+ return _entityService.Get(relation.ParentId, objectType);
}
///
/// Gets the Parent and Child objects from a Relation as a "/> with .
///
/// Relation to retrieve parent and child object from
- /// Optional bool to load the complete object graph when set to False
/// Returns a Tuple with Parent (item1) and Child (item2)
- public Tuple GetEntitiesFromRelation(IRelation relation, bool loadBaseType = false)
+ public Tuple GetEntitiesFromRelation(IRelation relation)
{
var childObjectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
var parentObjectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ParentObjectType);
- var child = _entityService.Get(relation.ChildId, childObjectType, loadBaseType);
- var parent = _entityService.Get(relation.ParentId, parentObjectType, loadBaseType);
+ var child = _entityService.Get(relation.ChildId, childObjectType);
+ var parent = _entityService.Get(relation.ParentId, parentObjectType);
return new Tuple(parent, child);
}
@@ -326,14 +323,13 @@ namespace Umbraco.Core.Services.Implement
/// Gets the Child objects from a list of Relations as a list of objects.
///
/// List of relations to retrieve child objects from
- /// Optional bool to load the complete object graph when set to False
/// An enumerable list of
- public IEnumerable GetChildEntitiesFromRelations(IEnumerable relations, bool loadBaseType = false)
+ public IEnumerable GetChildEntitiesFromRelations(IEnumerable relations)
{
foreach (var relation in relations)
{
var objectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
- yield return _entityService.Get(relation.ChildId, objectType, loadBaseType);
+ yield return _entityService.Get(relation.ChildId, objectType);
}
}
@@ -341,14 +337,13 @@ namespace Umbraco.Core.Services.Implement
/// Gets the Parent objects from a list of Relations as a list of objects.
///
/// List of relations to retrieve parent objects from
- /// Optional bool to load the complete object graph when set to False
/// An enumerable list of
- public IEnumerable GetParentEntitiesFromRelations(IEnumerable relations, bool loadBaseType = false)
+ public IEnumerable GetParentEntitiesFromRelations(IEnumerable relations)
{
foreach (var relation in relations)
{
var objectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ParentObjectType);
- yield return _entityService.Get(relation.ParentId, objectType, loadBaseType);
+ yield return _entityService.Get(relation.ParentId, objectType);
}
}
@@ -356,17 +351,16 @@ namespace Umbraco.Core.Services.Implement
/// Gets the Parent and Child objects from a list of Relations as a list of objects.
///
/// List of relations to retrieve parent and child objects from
- /// Optional bool to load the complete object graph when set to False
/// An enumerable list of with
- public IEnumerable> GetEntitiesFromRelations(IEnumerable relations, bool loadBaseType = false)
+ public IEnumerable> GetEntitiesFromRelations(IEnumerable relations)
{
foreach (var relation in relations)
{
var childObjectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
var parentObjectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ParentObjectType);
- var child = _entityService.Get(relation.ChildId, childObjectType, loadBaseType);
- var parent = _entityService.Get(relation.ParentId, parentObjectType, loadBaseType);
+ var child = _entityService.Get(relation.ChildId, childObjectType);
+ var parent = _entityService.Get(relation.ParentId, parentObjectType);
yield return new Tuple(parent, child);
}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 8a6acc107e..7c0e41348b 100755
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -218,6 +218,7 @@
+
@@ -249,6 +250,8 @@
+
+
diff --git a/src/Umbraco.Tests/Logging/LogviewerTests.cs b/src/Umbraco.Tests/Logging/LogviewerTests.cs
index 35981f5368..ed9deec177 100644
--- a/src/Umbraco.Tests/Logging/LogviewerTests.cs
+++ b/src/Umbraco.Tests/Logging/LogviewerTests.cs
@@ -23,9 +23,10 @@ namespace Umbraco.Tests.Logging
private string _newSearchfilePath;
private string _newSearchfileDirPath;
- private DateTimeOffset _startDate = new DateTime(year: 2018, month: 11, day: 12, hour:0, minute:0, second:0);
- private DateTimeOffset _endDate = new DateTime(year: 2018, month: 11, day: 13, hour: 0, minute: 0, second: 0);
-
+ private LogTimePeriod _logTimePeriod = new LogTimePeriod(
+ new DateTime(year: 2018, month: 11, day: 12, hour:0, minute:0, second:0),
+ new DateTime(year: 2018, month: 11, day: 13, hour: 0, minute: 0, second: 0)
+ );
[OneTimeSetUp]
public void Setup()
{
@@ -67,7 +68,7 @@ namespace Umbraco.Tests.Logging
[Test]
public void Logs_Contain_Correct_Error_Count()
{
- var numberOfErrors = _logViewer.GetNumberOfErrors(startDate: _startDate, endDate: _endDate);
+ var numberOfErrors = _logViewer.GetNumberOfErrors(_logTimePeriod);
//Our dummy log should contain 2 errors
Assert.AreEqual(2, numberOfErrors);
@@ -76,8 +77,8 @@ namespace Umbraco.Tests.Logging
[Test]
public void Logs_Contain_Correct_Log_Level_Counts()
{
- var logCounts = _logViewer.GetLogLevelCounts(startDate: _startDate, endDate: _endDate);
-
+ var logCounts = _logViewer.GetLogLevelCounts(_logTimePeriod);
+
Assert.AreEqual(1954, logCounts.Debug);
Assert.AreEqual(2, logCounts.Error);
Assert.AreEqual(0, logCounts.Fatal);
@@ -88,7 +89,7 @@ namespace Umbraco.Tests.Logging
[Test]
public void Logs_Contains_Correct_Message_Templates()
{
- var templates = _logViewer.GetMessageTemplates(startDate: _startDate, endDate: _endDate);
+ var templates = _logViewer.GetMessageTemplates(_logTimePeriod);
//Count no of templates
Assert.AreEqual(43, templates.Count());
@@ -112,7 +113,7 @@ namespace Umbraco.Tests.Logging
{
//We are just testing a return value (as we know the example file is less than 200MB)
//But this test method does not test/check that
- var canOpenLogs = _logViewer.CheckCanOpenLogs(startDate: _startDate, endDate: _endDate);
+ var canOpenLogs = _logViewer.CheckCanOpenLogs(_logTimePeriod);
Assert.IsTrue(canOpenLogs);
}
@@ -120,7 +121,7 @@ namespace Umbraco.Tests.Logging
public void Logs_Can_Be_Queried()
{
//Should get me the most 100 recent log entries & using default overloads for remaining params
- var allLogs = _logViewer.GetLogs(startDate: _startDate, endDate: _endDate, pageNumber: 1);
+ var allLogs = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1);
//Check we get 100 results back for a page & total items all good :)
Assert.AreEqual(100, allLogs.Items.Count());
@@ -138,7 +139,7 @@ namespace Umbraco.Tests.Logging
//Check we call method again with a smaller set of results & in ascending
- var smallQuery = _logViewer.GetLogs(startDate: _startDate, endDate: _endDate, pageNumber: 1, pageSize: 10, orderDirection: Direction.Ascending);
+ var smallQuery = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, pageSize: 10, orderDirection: Direction.Ascending);
Assert.AreEqual(10, smallQuery.Items.Count());
Assert.AreEqual(241, smallQuery.TotalPages);
@@ -152,17 +153,17 @@ namespace Umbraco.Tests.Logging
//Check invalid log levels
//Rather than expect 0 items - get all items back & ignore the invalid levels
string[] invalidLogLevels = { "Invalid", "NotALevel" };
- var queryWithInvalidLevels = _logViewer.GetLogs(startDate: _startDate, endDate: _endDate, pageNumber: 1, logLevels: invalidLogLevels);
+ var queryWithInvalidLevels = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, logLevels: invalidLogLevels);
Assert.AreEqual(2410, queryWithInvalidLevels.TotalItems);
//Check we can call method with an array of logLevel (error & warning)
string [] logLevels = { "Warning", "Error" };
- var queryWithLevels = _logViewer.GetLogs(startDate: _startDate, endDate: _endDate, pageNumber: 1, logLevels: logLevels);
+ var queryWithLevels = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, logLevels: logLevels);
Assert.AreEqual(9, queryWithLevels.TotalItems);
-
+
//Query @Level='Warning' BUT we pass in array of LogLevels for Debug & Info (Expect to get 0 results)
string[] logLevelMismatch = { "Debug", "Information" };
- var filterLevelQuery = _logViewer.GetLogs(startDate: _startDate, endDate: _endDate, pageNumber: 1, filterExpression: "@Level='Warning'", logLevels: logLevelMismatch); ;
+ var filterLevelQuery = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, filterExpression: "@Level='Warning'", logLevels: logLevelMismatch); ;
Assert.AreEqual(0, filterLevelQuery.TotalItems);
}
@@ -177,10 +178,10 @@ namespace Umbraco.Tests.Logging
[Test]
public void Logs_Can_Query_With_Expressions(string queryToVerify, int expectedCount)
{
- var testQuery = _logViewer.GetLogs(startDate: _startDate, endDate: _endDate, pageNumber: 1, filterExpression: queryToVerify);
+ var testQuery = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, filterExpression: queryToVerify);
Assert.AreEqual(expectedCount, testQuery.TotalItems);
}
-
+
[Test]
public void Log_Search_Can_Persist()
{
diff --git a/src/Umbraco.Tests/Models/LightEntityTest.cs b/src/Umbraco.Tests/Models/LightEntityTest.cs
index f1752a7681..41ce830cff 100644
--- a/src/Umbraco.Tests/Models/LightEntityTest.cs
+++ b/src/Umbraco.Tests/Models/LightEntityTest.cs
@@ -37,9 +37,7 @@ namespace Umbraco.Tests.Models
};
item.AdditionalData.Add("test1", 3);
item.AdditionalData.Add("test2", "valuie");
- item.AdditionalData.Add("test3", new EntitySlim.PropertySlim("TestPropertyEditor", "test"));
- item.AdditionalData.Add("test4", new EntitySlim.PropertySlim("TestPropertyEditor2", "test2"));
-
+
var result = ss.ToStream(item);
var json = result.ResultStream.ToJsonString();
Debug.Print(json); // FIXME: compare with v7
diff --git a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs
index c276dc35ca..fb451b1d5c 100644
--- a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs
+++ b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs
@@ -43,16 +43,6 @@ namespace Umbraco.Tests.Persistence
_databaseFactory = null;
}
- [Test]
- public void GetDatabaseType()
- {
- using (var database = _databaseFactory.CreateDatabase())
- {
- var databaseType = database.DatabaseType;
- Assert.AreEqual(DatabaseType.SQLCe, databaseType);
- }
- }
-
[Test]
public void CreateDatabase() // FIXME: move to DatabaseBuilderTest!
{
@@ -79,6 +69,13 @@ namespace Umbraco.Tests.Persistence
// re-create the database factory and database context with proper connection string
_databaseFactory = new UmbracoDatabaseFactory(connString, Constants.DbProviderNames.SqlCe, _logger, new Lazy(() => Mock.Of()));
+ // test get database type (requires an actual database)
+ using (var database = _databaseFactory.CreateDatabase())
+ {
+ var databaseType = database.DatabaseType;
+ Assert.AreEqual(DatabaseType.SQLCe, databaseType);
+ }
+
// create application context
//var appCtx = new ApplicationContext(
// _databaseFactory,
diff --git a/src/Umbraco.Tests/Persistence/Repositories/SimilarNodeNameTests.cs b/src/Umbraco.Tests/Persistence/Repositories/SimilarNodeNameTests.cs
index 3c23223c9f..582e5a4815 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/SimilarNodeNameTests.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/SimilarNodeNameTests.cs
@@ -36,6 +36,8 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.IsTrue(result > 0, "Expected >0 but was " + result);
}
+
+
[Test]
public void OrderByTest()
{
@@ -75,6 +77,7 @@ namespace Umbraco.Tests.Persistence.Repositories
[TestCase(0, "Alpha", "Alpha (3)")]
[TestCase(0, "Kilo (1)", "Kilo (1) (1)")] // though... we might consider "Kilo (2)"
[TestCase(6, "Kilo (1)", "Kilo (1)")] // because of the id
+ [TestCase(0, "alpha", "alpha (3)")]
[TestCase(0, "", " (1)")]
[TestCase(0, null, " (1)")]
public void Test(int nodeId, string nodeName, string expected)
@@ -95,5 +98,22 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.AreEqual(expected, SimilarNodeName.GetUniqueName(names, nodeId, nodeName));
}
+
+ [Test]
+ [Explicit("This test fails! We need to fix up the logic")]
+ public void TestMany()
+ {
+ var names = new[]
+ {
+ new SimilarNodeName { Id = 1, Name = "Alpha (2)" },
+ new SimilarNodeName { Id = 2, Name = "Test" },
+ new SimilarNodeName { Id = 3, Name = "Test (1)" },
+ new SimilarNodeName { Id = 4, Name = "Test (2)" },
+ new SimilarNodeName { Id = 22, Name = "Test (1) (1)" },
+ };
+
+ //fixme - this will yield "Test (2)" which is already in use
+ Assert.AreEqual("Test (3)", SimilarNodeName.GetUniqueName(names, 0, "Test"));
+ }
}
}
diff --git a/src/Umbraco.Tests/Services/EntityServiceTests.cs b/src/Umbraco.Tests/Services/EntityServiceTests.cs
index 2425f8b74a..0598b8cea2 100644
--- a/src/Umbraco.Tests/Services/EntityServiceTests.cs
+++ b/src/Umbraco.Tests/Services/EntityServiceTests.cs
@@ -675,15 +675,10 @@ namespace Umbraco.Tests.Services
foreach (var entity in entities)
{
- Console.WriteLine();
- foreach (var data in entity.AdditionalData)
- {
- Console.WriteLine($"{entity.Id} {data.Key} {data.Value} {(data.Value is EntitySlim.PropertySlim p ? p.PropertyEditorAlias : "")}");
- }
+ Assert.IsTrue(entity.GetType().Implements());
+ Console.WriteLine(((IMediaEntitySlim)entity).MediaPath);
+ Assert.IsNotEmpty(((IMediaEntitySlim)entity).MediaPath);
}
-
- Assert.That(entities.Any(x =>
- x.AdditionalData.Any(y => y.Value is EntitySlim.PropertySlim && ((EntitySlim.PropertySlim)y.Value).PropertyEditorAlias == Constants.PropertyEditors.Aliases.UploadField)), Is.True);
}
[Test]
diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs
index 110accdecf..31d11952ef 100644
--- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs
+++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs
@@ -164,11 +164,7 @@ namespace Umbraco.Tests.TestHelpers
var fileService = GetLazyService(factory, c => new FileService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c)));
var memberTypeService = GetLazyService(factory, c => new MemberTypeService(scopeProvider, logger, eventMessagesFactory, memberService.Value, GetRepo(c), GetRepo(c), GetRepo(c)));
- var entityService = GetLazyService(factory, c => new EntityService(
- scopeProvider, logger, eventMessagesFactory,
- contentService.Value, contentTypeService.Value, mediaService.Value, mediaTypeService.Value, dataTypeService.Value, memberService.Value, memberTypeService.Value,
- idkMap,
- GetRepo(c)));
+ var entityService = GetLazyService(factory, c => new EntityService(scopeProvider, logger, eventMessagesFactory, idkMap, GetRepo(c)));
var macroService = GetLazyService(factory, c => new MacroService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c)));
var packagingService = GetLazyService(factory, c =>
diff --git a/src/Umbraco.Web.UI.Client/gulp/config.js b/src/Umbraco.Web.UI.Client/gulp/config.js
index c27a2c5f53..4dae0dac08 100755
--- a/src/Umbraco.Web.UI.Client/gulp/config.js
+++ b/src/Umbraco.Web.UI.Client/gulp/config.js
@@ -41,12 +41,12 @@ module.exports = {
assets: "./src/assets/**"
}
},
- root: "../Umbraco.Web.UI/Umbraco/",
+ root: "../Umbraco.Web.UI/",
targets: {
- js: "js/",
- lib: "lib/",
- views: "views/",
- css: "assets/css/",
- assets: "assets/"
+ js: "Umbraco/js/",
+ lib: "Umbraco/lib/",
+ views: "Umbraco/views/",
+ css: "Umbraco/assets/css/",
+ assets: "Umbraco/assets/"
}
};
diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json
index c1c85a9688..90fb2437de 100644
--- a/src/Umbraco.Web.UI.Client/package-lock.json
+++ b/src/Umbraco.Web.UI.Client/package-lock.json
@@ -955,7 +955,7 @@
},
"ansi-escapes": {
"version": "3.1.0",
- "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
"integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==",
"dev": true
},
@@ -1104,6 +1104,7 @@
"resolved": "https://registry.npmjs.org/archive-type/-/archive-type-3.2.0.tgz",
"integrity": "sha1-nNnABpV+vpX62tW9YJiUKoE3N/Y=",
"dev": true,
+ "optional": true,
"requires": {
"file-type": "^3.1.0"
},
@@ -1112,7 +1113,8 @@
"version": "3.9.0",
"resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=",
- "dev": true
+ "dev": true,
+ "optional": true
}
}
},
@@ -1176,7 +1178,7 @@
"array-slice": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
- "integrity": "sha1-42jqFfibxwaff/uJrsOmx9SsItQ=",
+ "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==",
"dev": true
},
"array-sort": {
@@ -1538,6 +1540,7 @@
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
"dev": true,
+ "optional": true,
"requires": {
"readable-stream": "^2.3.5",
"safe-buffer": "^5.1.1"
@@ -1547,13 +1550,15 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"readable-stream": {
"version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -1566,9 +1571,10 @@
},
"string_decoder": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -1740,7 +1746,7 @@
"buffer-alloc": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
- "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
+ "integrity": "sha1-iQ3ZDZI6hz4I4Q5f1RpX5bfM4Ow=",
"dev": true,
"requires": {
"buffer-alloc-unsafe": "^1.1.0",
@@ -1750,14 +1756,15 @@
"buffer-alloc-unsafe": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
- "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
+ "integrity": "sha1-vX3CauKXLQ7aJTvgYdupkjScGfA=",
"dev": true
},
"buffer-crc32": {
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"buffer-fill": {
"version": "1.0.0",
@@ -1776,6 +1783,7 @@
"resolved": "https://registry.npmjs.org/buffer-to-vinyl/-/buffer-to-vinyl-1.1.0.tgz",
"integrity": "sha1-APFfruOreh3aLN5tkSG//dB7ImI=",
"dev": true,
+ "optional": true,
"requires": {
"file-type": "^3.1.0",
"readable-stream": "^2.0.2",
@@ -1787,19 +1795,22 @@
"version": "3.9.0",
"resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -1815,6 +1826,7 @@
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -1823,13 +1835,15 @@
"version": "2.0.3",
"resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
"integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"vinyl": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz",
"integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=",
"dev": true,
+ "optional": true,
"requires": {
"clone": "^1.0.0",
"clone-stats": "^0.0.1",
@@ -1950,7 +1964,8 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz",
"integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"caseless": {
"version": "0.12.0",
@@ -1963,6 +1978,7 @@
"resolved": "https://registry.npmjs.org/caw/-/caw-1.2.0.tgz",
"integrity": "sha1-/7Im/n78VHKI3GLuPpcHPCEtEDQ=",
"dev": true,
+ "optional": true,
"requires": {
"get-proxy": "^1.0.1",
"is-obj": "^1.0.0",
@@ -1974,7 +1990,8 @@
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz",
"integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=",
- "dev": true
+ "dev": true,
+ "optional": true
}
}
},
@@ -2249,7 +2266,8 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/co/-/co-3.1.0.tgz",
"integrity": "sha1-TqVOpaCJOBUxheFSEMaNkJK8G3g=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"coa": {
"version": "2.0.1",
@@ -2373,6 +2391,7 @@
"resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
"dev": true,
+ "optional": true,
"requires": {
"graceful-readlink": ">= 1.0.0"
}
@@ -2436,7 +2455,7 @@
},
"string_decoder": {
"version": "1.1.1",
- "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
@@ -2559,7 +2578,7 @@
"core-js": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
- "integrity": "sha1-+XJgj/DOrWi4QaFqky0LGDeRgU4=",
+ "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==",
"dev": true
},
"core-util-is": {
@@ -2585,6 +2604,7 @@
"resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz",
"integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=",
"dev": true,
+ "optional": true,
"requires": {
"capture-stack-trace": "^1.0.0"
}
@@ -2839,6 +2859,7 @@
"resolved": "https://registry.npmjs.org/decompress/-/decompress-3.0.0.tgz",
"integrity": "sha1-rx3VDQbjv8QyRh033hGzjA2ZG+0=",
"dev": true,
+ "optional": true,
"requires": {
"buffer-to-vinyl": "^1.0.0",
"concat-stream": "^1.4.6",
@@ -2856,6 +2877,7 @@
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
"integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
"dev": true,
+ "optional": true,
"requires": {
"arr-flatten": "^1.0.1"
}
@@ -2864,13 +2886,15 @@
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
"integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"braces": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
"integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
"dev": true,
+ "optional": true,
"requires": {
"expand-range": "^1.8.1",
"preserve": "^0.2.0",
@@ -2882,6 +2906,7 @@
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
"integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
"dev": true,
+ "optional": true,
"requires": {
"is-posix-bracket": "^0.1.0"
}
@@ -2891,6 +2916,7 @@
"resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
"integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
"dev": true,
+ "optional": true,
"requires": {
"is-extglob": "^1.0.0"
}
@@ -2900,6 +2926,7 @@
"resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
"integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
"dev": true,
+ "optional": true,
"requires": {
"inflight": "^1.0.4",
"inherits": "2",
@@ -2913,6 +2940,7 @@
"resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz",
"integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=",
"dev": true,
+ "optional": true,
"requires": {
"extend": "^3.0.0",
"glob": "^5.0.3",
@@ -2928,13 +2956,15 @@
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"readable-stream": {
"version": "1.0.34",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
@@ -2946,13 +2976,15 @@
"version": "0.10.31",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"through2": {
"version": "0.6.5",
"resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
"integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
"dev": true,
+ "optional": true,
"requires": {
"readable-stream": ">=1.0.33-1 <1.1.0-0",
"xtend": ">=4.0.0 <4.1.0-0"
@@ -2964,19 +2996,22 @@
"version": "4.1.15",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
"integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-extglob": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-glob": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
"dev": true,
+ "optional": true,
"requires": {
"is-extglob": "^1.0.0"
}
@@ -2985,13 +3020,15 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"dev": true,
+ "optional": true,
"requires": {
"is-buffer": "^1.1.5"
}
@@ -3001,6 +3038,7 @@
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
"integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
"dev": true,
+ "optional": true,
"requires": {
"arr-diff": "^2.0.0",
"array-unique": "^0.2.1",
@@ -3021,13 +3059,15 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"ordered-read-streams": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz",
"integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=",
"dev": true,
+ "optional": true,
"requires": {
"is-stream": "^1.0.1",
"readable-stream": "^2.0.1"
@@ -3038,6 +3078,7 @@
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -3053,6 +3094,7 @@
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -3062,6 +3104,7 @@
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
"dev": true,
+ "optional": true,
"requires": {
"is-utf8": "^0.2.0"
}
@@ -3071,6 +3114,7 @@
"resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz",
"integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=",
"dev": true,
+ "optional": true,
"requires": {
"first-chunk-stream": "^1.0.0",
"strip-bom": "^2.0.0"
@@ -3081,6 +3125,7 @@
"resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
"integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==",
"dev": true,
+ "optional": true,
"requires": {
"json-stable-stringify-without-jsonify": "^1.0.1",
"through2-filter": "^3.0.0"
@@ -3091,6 +3136,7 @@
"resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz",
"integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==",
"dev": true,
+ "optional": true,
"requires": {
"through2": "~2.0.0",
"xtend": "~4.0.0"
@@ -3103,6 +3149,7 @@
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz",
"integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=",
"dev": true,
+ "optional": true,
"requires": {
"clone": "^1.0.0",
"clone-stats": "^0.0.1",
@@ -3114,6 +3161,7 @@
"resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz",
"integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=",
"dev": true,
+ "optional": true,
"requires": {
"duplexify": "^3.2.0",
"glob-stream": "^5.3.2",
@@ -3141,6 +3189,7 @@
"resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-3.1.0.tgz",
"integrity": "sha1-IXx4n5uURQ76rcXF5TeXj8MzxGY=",
"dev": true,
+ "optional": true,
"requires": {
"is-tar": "^1.0.0",
"object-assign": "^2.0.0",
@@ -3154,19 +3203,22 @@
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
"integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
"integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"readable-stream": {
"version": "1.0.34",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
@@ -3179,6 +3231,7 @@
"resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
"integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
"dev": true,
+ "optional": true,
"requires": {
"readable-stream": ">=1.0.33-1 <1.1.0-0",
"xtend": ">=4.0.0 <4.1.0-0"
@@ -3189,6 +3242,7 @@
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
"integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=",
"dev": true,
+ "optional": true,
"requires": {
"clone": "^0.2.0",
"clone-stats": "^0.0.1"
@@ -3201,6 +3255,7 @@
"resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-3.1.0.tgz",
"integrity": "sha1-iyOTVoE1X58YnYclag+L3ZbZZm0=",
"dev": true,
+ "optional": true,
"requires": {
"is-bzip2": "^1.0.0",
"object-assign": "^2.0.0",
@@ -3215,19 +3270,22 @@
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
"integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
"integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"readable-stream": {
"version": "1.0.34",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
@@ -3240,6 +3298,7 @@
"resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
"integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
"dev": true,
+ "optional": true,
"requires": {
"readable-stream": ">=1.0.33-1 <1.1.0-0",
"xtend": ">=4.0.0 <4.1.0-0"
@@ -3250,6 +3309,7 @@
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
"integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=",
"dev": true,
+ "optional": true,
"requires": {
"clone": "^0.2.0",
"clone-stats": "^0.0.1"
@@ -3262,6 +3322,7 @@
"resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-3.1.0.tgz",
"integrity": "sha1-ssE9+YFmJomRtxXWRH9kLpaW9aA=",
"dev": true,
+ "optional": true,
"requires": {
"is-gzip": "^1.0.0",
"object-assign": "^2.0.0",
@@ -3275,19 +3336,22 @@
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
"integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
"integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"readable-stream": {
"version": "1.0.34",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
@@ -3300,6 +3364,7 @@
"resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
"integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
"dev": true,
+ "optional": true,
"requires": {
"readable-stream": ">=1.0.33-1 <1.1.0-0",
"xtend": ">=4.0.0 <4.1.0-0"
@@ -3310,6 +3375,7 @@
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
"integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=",
"dev": true,
+ "optional": true,
"requires": {
"clone": "^0.2.0",
"clone-stats": "^0.0.1"
@@ -3322,6 +3388,7 @@
"resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-3.4.0.tgz",
"integrity": "sha1-YUdbQVIGa74/7hL51inRX+ZHjus=",
"dev": true,
+ "optional": true,
"requires": {
"is-zip": "^1.0.0",
"read-all-stream": "^3.0.0",
@@ -3337,6 +3404,7 @@
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz",
"integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=",
"dev": true,
+ "optional": true,
"requires": {
"clone": "^1.0.0",
"clone-stats": "^0.0.1",
@@ -3349,7 +3417,8 @@
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"deep-is": {
"version": "0.1.3",
@@ -3493,7 +3562,7 @@
"doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
"requires": {
"esutils": "^2.0.2"
@@ -3568,6 +3637,7 @@
"resolved": "https://registry.npmjs.org/download/-/download-4.4.3.tgz",
"integrity": "sha1-qlX9rTktldS2jowr4D4MKqIbqaw=",
"dev": true,
+ "optional": true,
"requires": {
"caw": "^1.0.1",
"concat-stream": "^1.4.7",
@@ -3591,6 +3661,7 @@
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
"integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
"dev": true,
+ "optional": true,
"requires": {
"arr-flatten": "^1.0.1"
}
@@ -3599,13 +3670,15 @@
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
"integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"braces": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
"integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
"dev": true,
+ "optional": true,
"requires": {
"expand-range": "^1.8.1",
"preserve": "^0.2.0",
@@ -3617,6 +3690,7 @@
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
"integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
"dev": true,
+ "optional": true,
"requires": {
"is-posix-bracket": "^0.1.0"
}
@@ -3626,6 +3700,7 @@
"resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
"integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
"dev": true,
+ "optional": true,
"requires": {
"is-extglob": "^1.0.0"
}
@@ -3635,6 +3710,7 @@
"resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
"integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
"dev": true,
+ "optional": true,
"requires": {
"inflight": "^1.0.4",
"inherits": "2",
@@ -3648,6 +3724,7 @@
"resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz",
"integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=",
"dev": true,
+ "optional": true,
"requires": {
"extend": "^3.0.0",
"glob": "^5.0.3",
@@ -3663,13 +3740,15 @@
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"readable-stream": {
"version": "1.0.34",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
@@ -3681,13 +3760,15 @@
"version": "0.10.31",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"through2": {
"version": "0.6.5",
"resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
"integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
"dev": true,
+ "optional": true,
"requires": {
"readable-stream": ">=1.0.33-1 <1.1.0-0",
"xtend": ">=4.0.0 <4.1.0-0"
@@ -3699,19 +3780,22 @@
"version": "4.1.15",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
"integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-extglob": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-glob": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
"dev": true,
+ "optional": true,
"requires": {
"is-extglob": "^1.0.0"
}
@@ -3720,13 +3804,15 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"dev": true,
+ "optional": true,
"requires": {
"is-buffer": "^1.1.5"
}
@@ -3736,6 +3822,7 @@
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
"integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
"dev": true,
+ "optional": true,
"requires": {
"arr-diff": "^2.0.0",
"array-unique": "^0.2.1",
@@ -3756,13 +3843,15 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"ordered-read-streams": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz",
"integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=",
"dev": true,
+ "optional": true,
"requires": {
"is-stream": "^1.0.1",
"readable-stream": "^2.0.1"
@@ -3773,6 +3862,7 @@
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -3788,6 +3878,7 @@
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -3797,6 +3888,7 @@
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
"dev": true,
+ "optional": true,
"requires": {
"is-utf8": "^0.2.0"
}
@@ -3806,6 +3898,7 @@
"resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz",
"integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=",
"dev": true,
+ "optional": true,
"requires": {
"first-chunk-stream": "^1.0.0",
"strip-bom": "^2.0.0"
@@ -3816,6 +3909,7 @@
"resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
"integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==",
"dev": true,
+ "optional": true,
"requires": {
"json-stable-stringify-without-jsonify": "^1.0.1",
"through2-filter": "^3.0.0"
@@ -3826,6 +3920,7 @@
"resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz",
"integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==",
"dev": true,
+ "optional": true,
"requires": {
"through2": "~2.0.0",
"xtend": "~4.0.0"
@@ -3838,6 +3933,7 @@
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz",
"integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=",
"dev": true,
+ "optional": true,
"requires": {
"clone": "^1.0.0",
"clone-stats": "^0.0.1",
@@ -3849,6 +3945,7 @@
"resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz",
"integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=",
"dev": true,
+ "optional": true,
"requires": {
"duplexify": "^3.2.0",
"glob-stream": "^5.3.2",
@@ -3891,6 +3988,7 @@
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz",
"integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==",
"dev": true,
+ "optional": true,
"requires": {
"end-of-stream": "^1.0.0",
"inherits": "^2.0.1",
@@ -3903,6 +4001,7 @@
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
"dev": true,
+ "optional": true,
"requires": {
"once": "^1.4.0"
}
@@ -3911,13 +4010,15 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
@@ -3927,6 +4028,7 @@
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -3942,6 +4044,7 @@
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -3953,6 +4056,7 @@
"resolved": "https://registry.npmjs.org/each-async/-/each-async-1.1.1.tgz",
"integrity": "sha1-3uUim98KtrogEqOV4bhpq/iBNHM=",
"dev": true,
+ "optional": true,
"requires": {
"onetime": "^1.0.0",
"set-immediate-shim": "^1.0.0"
@@ -3962,7 +4066,8 @@
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
"integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
- "dev": true
+ "dev": true,
+ "optional": true
}
}
},
@@ -4061,7 +4166,7 @@
},
"engine.io-client": {
"version": "3.2.1",
- "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
+ "resolved": "http://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
"integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==",
"dev": true,
"requires": {
@@ -4263,7 +4368,7 @@
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"optional": true
}
@@ -4358,7 +4463,7 @@
"eslint-scope": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz",
- "integrity": "sha1-UL8wcekzi83EMzF5Sgy1M/ATYXI=",
+ "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==",
"dev": true,
"requires": {
"esrecurse": "^4.1.0",
@@ -4368,13 +4473,13 @@
"eslint-utils": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz",
- "integrity": "sha1-moUbqJ7nxGA0b5fPiTnHKYgn5RI=",
+ "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==",
"dev": true
},
"eslint-visitor-keys": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
- "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=",
+ "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==",
"dev": true
},
"espree": {
@@ -4397,7 +4502,7 @@
"esquery": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
- "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=",
+ "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
"dev": true,
"requires": {
"estraverse": "^4.0.0"
@@ -4406,7 +4511,7 @@
"esrecurse": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
- "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=",
+ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
"dev": true,
"requires": {
"estraverse": "^4.1.0"
@@ -4482,7 +4587,7 @@
"exec-buffer": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/exec-buffer/-/exec-buffer-3.2.0.tgz",
- "integrity": "sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA==",
+ "integrity": "sha1-sWhtvZBMfPmC5lLB9aebHlVzCCs=",
"dev": true,
"optional": true,
"requires": {
@@ -4691,7 +4796,7 @@
"fill-range": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
- "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
+ "integrity": "sha1-6x53OrsFbc2N8r/favWbizqTZWU=",
"dev": true,
"requires": {
"is-number": "^2.1.0",
@@ -4945,6 +5050,7 @@
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
"integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
"dev": true,
+ "optional": true,
"requires": {
"pend": "~1.2.0"
}
@@ -4992,13 +5098,15 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz",
"integrity": "sha1-5hz4BfDeHJhFZ9A4bcXfUO5a9+Q=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"filenamify": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/filenamify/-/filenamify-1.2.1.tgz",
"integrity": "sha1-qfL/0RxQO+0wABUCknI3jx8TZaU=",
"dev": true,
+ "optional": true,
"requires": {
"filename-reserved-regex": "^1.0.0",
"strip-outer": "^1.0.0",
@@ -5244,8 +5352,9 @@
"fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
- "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
- "dev": true
+ "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=",
+ "dev": true,
+ "optional": true
},
"fs-extra": {
"version": "1.0.0",
@@ -5869,6 +5978,7 @@
"resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-1.1.0.tgz",
"integrity": "sha1-iUhUSRvFkbDxR9euVw9cZ4tyVus=",
"dev": true,
+ "optional": true,
"requires": {
"rc": "^1.1.2"
}
@@ -6030,7 +6140,7 @@
"global-modules": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
- "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=",
+ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
"dev": true,
"requires": {
"global-prefix": "^1.0.1",
@@ -6175,6 +6285,7 @@
"resolved": "http://registry.npmjs.org/got/-/got-5.7.1.tgz",
"integrity": "sha1-X4FjWmHkplifGAVp6k44FoClHzU=",
"dev": true,
+ "optional": true,
"requires": {
"create-error-class": "^3.0.1",
"duplexer2": "^0.1.4",
@@ -6198,6 +6309,7 @@
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
"integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
"dev": true,
+ "optional": true,
"requires": {
"readable-stream": "^2.0.2"
}
@@ -6206,19 +6318,22 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"parse-json": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
"integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
"dev": true,
+ "optional": true,
"requires": {
"error-ex": "^1.2.0"
}
@@ -6228,6 +6343,7 @@
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -6243,6 +6359,7 @@
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -6262,7 +6379,8 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"growly": {
"version": "1.3.0",
@@ -6579,6 +6697,7 @@
"resolved": "https://registry.npmjs.org/gulp-decompress/-/gulp-decompress-1.2.0.tgz",
"integrity": "sha1-jutlpeAV+O2FMsr+KEVJYGJvDcc=",
"dev": true,
+ "optional": true,
"requires": {
"archive-type": "^3.0.0",
"decompress": "^3.0.0",
@@ -6590,13 +6709,15 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -6612,6 +6733,7 @@
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -6621,7 +6743,7 @@
"gulp-eslint": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-5.0.0.tgz",
- "integrity": "sha1-KiaECV93Syz3kxAmIHjFbMehK1I=",
+ "integrity": "sha512-9GUqCqh85C7rP9120cpxXuZz2ayq3BZc85pCTuPJS03VQYxne0aWPIXWx6LSvsGPa3uRqtSO537vaugOh+5cXg==",
"dev": true,
"requires": {
"eslint": "^5.0.1",
@@ -7229,6 +7351,7 @@
"resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz",
"integrity": "sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=",
"dev": true,
+ "optional": true,
"requires": {
"convert-source-map": "^1.1.1",
"graceful-fs": "^4.1.2",
@@ -7241,13 +7364,15 @@
"version": "4.1.15",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
"integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"strip-bom": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
"dev": true,
+ "optional": true,
"requires": {
"is-utf8": "^0.2.0"
}
@@ -7257,6 +7382,7 @@
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz",
"integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=",
"dev": true,
+ "optional": true,
"requires": {
"clone": "^1.0.0",
"clone-stats": "^0.0.1",
@@ -8072,7 +8198,7 @@
"is-absolute": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
- "integrity": "sha1-OV4a6EsR8mrReV5zwXN45IowFXY=",
+ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
"dev": true,
"requires": {
"is-relative": "^1.0.0",
@@ -8139,7 +8265,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-bzip2/-/is-bzip2-1.0.0.tgz",
"integrity": "sha1-XuWOqlounIDiFAe+3yOuWsCRs/w=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-callable": {
"version": "1.1.4",
@@ -8274,7 +8401,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz",
"integrity": "sha1-bKiwe5nHeZgCWQDlVc7Y7YCHmoM=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-jpg": {
"version": "1.0.1",
@@ -8287,7 +8415,8 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.1.1.tgz",
"integrity": "sha1-fUxXKDd+84bD4ZSpkRv1fG3DNec=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-number": {
"version": "3.0.0",
@@ -8353,7 +8482,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
"integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-regex": {
"version": "1.0.4",
@@ -8367,7 +8497,7 @@
"is-relative": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
- "integrity": "sha1-obtpNc6MXboei5dUubLcwCDiJg0=",
+ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
"dev": true,
"requires": {
"is-unc-path": "^1.0.0"
@@ -8376,14 +8506,15 @@
"is-resolvable": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
- "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=",
+ "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
"dev": true
},
"is-retry-allowed": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz",
"integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-stream": {
"version": "1.1.0",
@@ -8413,7 +8544,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-tar/-/is-tar-1.0.0.tgz",
"integrity": "sha1-L2suF5LB9bs2UZrKqdZcDSb+hT0=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-typedarray": {
"version": "1.0.0",
@@ -8424,7 +8556,7 @@
"is-unc-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
- "integrity": "sha1-1zHoiY7QkKEsNSrS6u1Qla0yLJ0=",
+ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
"dev": true,
"requires": {
"unc-path-regex": "^0.1.2"
@@ -8434,7 +8566,8 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
"integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-utf8": {
"version": "0.2.1",
@@ -8446,7 +8579,8 @@
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-0.3.0.tgz",
"integrity": "sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-windows": {
"version": "1.0.2",
@@ -8464,7 +8598,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-zip/-/is-zip-1.0.0.tgz",
"integrity": "sha1-R7Co/004p2QxzP2ZqOFaTIa6IyU=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"isarray": {
"version": "0.0.1",
@@ -8581,7 +8716,7 @@
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
"json-stable-stringify-without-jsonify": {
@@ -8804,6 +8939,7 @@
"resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
"integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
"dev": true,
+ "optional": true,
"requires": {
"readable-stream": "^2.0.5"
},
@@ -8812,13 +8948,15 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -8834,6 +8972,7 @@
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -9139,7 +9278,8 @@
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"lodash.isobject": {
"version": "2.4.1",
@@ -9335,8 +9475,9 @@
"lowercase-keys": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
- "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
- "dev": true
+ "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=",
+ "dev": true,
+ "optional": true
},
"lpad-align": {
"version": "1.1.2",
@@ -9369,7 +9510,7 @@
"make-dir": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
- "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+ "integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=",
"dev": true,
"requires": {
"pify": "^3.0.0"
@@ -9386,7 +9527,7 @@
"make-iterator": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
- "integrity": "sha1-KbM/MSqo9UfEpeSQ9Wr87JkTOtY=",
+ "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
"dev": true,
"requires": {
"kind-of": "^6.0.2"
@@ -9583,7 +9724,7 @@
"mimic-fn": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
- "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=",
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
"dev": true
},
"minimatch": {
@@ -9772,7 +9913,8 @@
"version": "1.0.0",
"resolved": "http://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz",
"integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"node.extend": {
"version": "1.1.8",
@@ -12735,7 +12877,7 @@
"dependencies": {
"minimist": {
"version": "0.0.10",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
+ "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
"dev": true
},
@@ -12822,7 +12964,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"p-pipe": {
"version": "1.2.0",
@@ -13126,7 +13269,7 @@
"pluralize": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
- "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=",
+ "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
"dev": true
},
"posix-character-classes": {
@@ -13533,7 +13676,8 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"preserve": {
"version": "0.2.0",
@@ -13665,6 +13809,7 @@
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"dev": true,
+ "optional": true,
"requires": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
@@ -13677,6 +13822,7 @@
"resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz",
"integrity": "sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=",
"dev": true,
+ "optional": true,
"requires": {
"pinkie-promise": "^2.0.0",
"readable-stream": "^2.0.0"
@@ -13686,13 +13832,15 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -13708,6 +13856,7 @@
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -13812,7 +13961,7 @@
},
"string_decoder": {
"version": "1.1.1",
- "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
@@ -14310,7 +14459,7 @@
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
"sax": {
@@ -14324,6 +14473,7 @@
"resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz",
"integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=",
"dev": true,
+ "optional": true,
"requires": {
"commander": "~2.8.1"
}
@@ -14469,7 +14619,8 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
"integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"set-value": {
"version": "2.0.0",
@@ -14497,7 +14648,7 @@
"setprototypeof": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
- "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=",
+ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
"dev": true
},
"shebang-command": {
@@ -14775,7 +14926,7 @@
},
"socket.io-parser": {
"version": "3.2.0",
- "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
+ "resolved": "http://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
"integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==",
"dev": true,
"requires": {
@@ -14920,7 +15071,7 @@
},
"chalk": {
"version": "1.1.3",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"optional": true,
@@ -14974,7 +15125,8 @@
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.2.tgz",
"integrity": "sha1-5sgLYjEj19gM8TLOU480YokHJQI=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"static-extend": {
"version": "0.1.2",
@@ -15018,6 +15170,7 @@
"resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz",
"integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=",
"dev": true,
+ "optional": true,
"requires": {
"duplexer2": "~0.1.0",
"readable-stream": "^2.0.2"
@@ -15028,6 +15181,7 @@
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
"integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
"dev": true,
+ "optional": true,
"requires": {
"readable-stream": "^2.0.2"
}
@@ -15036,13 +15190,15 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -15058,6 +15214,7 @@
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -15067,19 +15224,20 @@
"stream-consume": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz",
- "integrity": "sha1-0721mMK9CugrjKx6xQsRB6eZbEg=",
+ "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==",
"dev": true
},
"stream-shift": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
"integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"streamroller": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz",
- "integrity": "sha1-odG3z4PTmvsNYwSaWsv5NJO99ks=",
+ "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==",
"dev": true,
"requires": {
"date-format": "^1.2.0",
@@ -15106,7 +15264,7 @@
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -15121,7 +15279,7 @@
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
"safe-buffer": "~5.1.0"
@@ -15138,7 +15296,7 @@
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"dev": true,
"requires": {
"is-fullwidth-code-point": "^2.0.0",
@@ -15252,6 +15410,7 @@
"resolved": "http://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
"integrity": "sha1-lgu9EoeETzl1pFWKoQOoJV4kVqA=",
"dev": true,
+ "optional": true,
"requires": {
"chalk": "^1.0.0",
"get-stdin": "^4.0.1",
@@ -15265,13 +15424,15 @@
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"chalk": {
"version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
+ "optional": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
@@ -15285,6 +15446,7 @@
"resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
"integrity": "sha1-hHSREZ/MtftDYhfMc39/qtUPYD8=",
"dev": true,
+ "optional": true,
"requires": {
"is-relative": "^0.1.0"
}
@@ -15293,13 +15455,15 @@
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz",
"integrity": "sha1-kF/uiuhvRbPsYUvDwVyGnfCHboI=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
+ "dev": true,
+ "optional": true
}
}
},
@@ -15328,8 +15492,9 @@
"strip-outer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
- "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
+ "integrity": "sha1-sv0qv2YEudHmATBXGV34Nrip1jE=",
"dev": true,
+ "optional": true,
"requires": {
"escape-string-regexp": "^1.0.2"
}
@@ -15363,6 +15528,7 @@
"resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz",
"integrity": "sha1-HGYfZnBX9jvLeHWqFDi8FiUlFW4=",
"dev": true,
+ "optional": true,
"requires": {
"chalk": "^1.0.0"
},
@@ -15371,13 +15537,15 @@
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"chalk": {
"version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
+ "optional": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
@@ -15390,7 +15558,8 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
+ "dev": true,
+ "optional": true
}
}
},
@@ -15452,6 +15621,7 @@
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
"integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
"dev": true,
+ "optional": true,
"requires": {
"bl": "^1.0.0",
"buffer-alloc": "^1.2.0",
@@ -15467,6 +15637,7 @@
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
"integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=",
"dev": true,
+ "optional": true,
"requires": {
"once": "^1.4.0"
}
@@ -15475,22 +15646,25 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
},
"readable-stream": {
"version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -15506,6 +15680,7 @@
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -15610,6 +15785,7 @@
"resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz",
"integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=",
"dev": true,
+ "optional": true,
"requires": {
"through2": "~2.0.0",
"xtend": "~4.0.0"
@@ -15634,7 +15810,8 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/timed-out/-/timed-out-3.1.3.tgz",
"integrity": "sha1-lYYL/MXHbCd/j4Mm/Q9bLiDrohc=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"timers-ext": {
"version": "0.1.7",
@@ -15696,7 +15873,7 @@
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
- "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"dev": true,
"requires": {
"os-tmpdir": "~1.0.2"
@@ -15707,6 +15884,7 @@
"resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz",
"integrity": "sha1-HN+kcqnvUMI57maZm2YsoOs5k38=",
"dev": true,
+ "optional": true,
"requires": {
"extend-shallow": "^2.0.1"
},
@@ -15716,6 +15894,7 @@
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
+ "optional": true,
"requires": {
"is-extendable": "^0.1.0"
}
@@ -15731,8 +15910,9 @@
"to-buffer": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
- "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==",
- "dev": true
+ "integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=",
+ "dev": true,
+ "optional": true
},
"to-fast-properties": {
"version": "2.0.0",
@@ -15811,6 +15991,7 @@
"resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
"integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
"dev": true,
+ "optional": true,
"requires": {
"escape-string-regexp": "^1.0.2"
}
@@ -16059,18 +16240,19 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz",
"integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"upath": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz",
- "integrity": "sha1-NSVll+RqWB20eT0M5H+prr/J+r0=",
+ "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==",
"dev": true
},
"uri-js": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
- "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=",
+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
"dev": true,
"requires": {
"punycode": "^2.1.0"
@@ -16087,6 +16269,7 @@
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz",
"integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=",
"dev": true,
+ "optional": true,
"requires": {
"prepend-http": "^1.0.1"
}
@@ -16172,7 +16355,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz",
"integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"validate-npm-package-license": {
"version": "3.0.4",
@@ -16217,6 +16401,7 @@
"resolved": "https://registry.npmjs.org/vinyl-assign/-/vinyl-assign-1.2.1.tgz",
"integrity": "sha1-TRmIkbVRWRHXcajNnFSApGoHSkU=",
"dev": true,
+ "optional": true,
"requires": {
"object-assign": "^4.0.1",
"readable-stream": "^2.0.0"
@@ -16226,19 +16411,22 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
+ "optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -16254,6 +16442,7 @@
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -16393,6 +16582,7 @@
"resolved": "https://registry.npmjs.org/ware/-/ware-1.3.0.tgz",
"integrity": "sha1-0bFPOdLiy0q4xAmPdW/ksWTkc9Q=",
"dev": true,
+ "optional": true,
"requires": {
"wrap-fn": "^0.1.0"
}
@@ -16483,6 +16673,7 @@
"resolved": "https://registry.npmjs.org/wrap-fn/-/wrap-fn-0.1.5.tgz",
"integrity": "sha1-8htuQQFv9KfjFyDbxjoJAWvfmEU=",
"dev": true,
+ "optional": true,
"requires": {
"co": "3.1.0"
}
@@ -16586,6 +16777,7 @@
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
"integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
"dev": true,
+ "optional": true,
"requires": {
"buffer-crc32": "~0.2.3",
"fd-slicer": "~1.1.0"
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js
index 3a874f83c6..a548820138 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js
@@ -8,6 +8,7 @@
var evts = [];
var infiniteMode = $scope.infiniteModel && $scope.infiniteModel.infiniteMode;
+ var watchingCulture = false;
//setup scope vars
$scope.defaultButton = null;
@@ -26,26 +27,58 @@
$scope.allowOpen = true;
$scope.app = null;
+ //initializes any watches
+ function startWatches(content) {
+
+ //watch for changes to isNew & the content.id, set the page.isNew accordingly and load the breadcrumb if we can
+ $scope.$watchGroup(['isNew', 'content.id'], function (newVal, oldVal) {
+
+ var contentId = newVal[1];
+ $scope.page.isNew = Object.toBoolean(newVal[0]);
+
+ //We fetch all ancestors of the node to generate the footer breadcrumb navigation
+ if (!$scope.page.isNew && contentId && content.parentId && content.parentId !== -1) {
+ loadBreadcrumb();
+ if (!watchingCulture) {
+ $scope.$watch('culture',
+ function (value, oldValue) {
+ if (value !== oldValue) {
+ loadBreadcrumb();
+ }
+ });
+ }
+ }
+ });
+
+ }
+
+ //this initializes the editor with the data which will be called more than once if the data is re-loaded
function init() {
-
+
var content = $scope.content;
-
+
+ if (content.id && content.isChildOfListView && content.trashed === false) {
+ $scope.page.listViewPath = ($routeParams.page) ?
+ "/content/content/edit/" + content.parentId + "?page=" + $routeParams.page :
+ "/content/content/edit/" + content.parentId;
+ }
+
// we need to check wether an app is present in the current data, if not we will present the default app.
var isAppPresent = false;
-
+
// on first init, we dont have any apps. but if we are re-initializing, we do, but ...
if ($scope.app) {
-
+
// lets check if it still exists as part of our apps array. (if not we have made a change to our docType, even just a re-save of the docType it will turn into new Apps.)
- _.forEach(content.apps, function(app) {
+ _.forEach(content.apps, function (app) {
if (app === $scope.app) {
isAppPresent = true;
}
});
-
+
// if we did reload our DocType, but still have the same app we will try to find it by the alias.
if (isAppPresent === false) {
- _.forEach(content.apps, function(app) {
+ _.forEach(content.apps, function (app) {
if (app.alias === $scope.app.alias) {
isAppPresent = true;
app.active = true;
@@ -53,7 +86,7 @@
}
});
}
-
+
}
// if we still dont have a app, lets show the first one:
@@ -61,21 +94,8 @@
content.apps[0].active = true;
$scope.appChanged(content.apps[0]);
}
-
- editorState.set(content);
- //We fetch all ancestors of the node to generate the footer breadcrumb navigation
- if (!$scope.page.isNew) {
- if (content.parentId && content.parentId !== -1) {
- loadBreadcrumb();
- $scope.$watch('culture',
- function (value, oldValue) {
- if (value !== oldValue) {
- loadBreadcrumb();
- }
- });
- }
- }
+ editorState.set(content);
bindEvents();
@@ -118,10 +138,10 @@
function isContentCultureVariant() {
return $scope.content.variants.length > 1;
}
-
+
function reload() {
$scope.page.loading = true;
- loadContent().then(function() {
+ loadContent().then(function () {
$scope.page.loading = false;
});
}
@@ -134,7 +154,7 @@
evts.push(eventsService.on("editors.documentType.saved", function (name, args) {
// if this content item uses the updated doc type we need to reload the content item
- if(args && args.documentType && $scope.content.documentType.id === args.documentType.id) {
+ if (args && args.documentType && $scope.content.documentType.id === args.documentType.id) {
reload();
}
}));
@@ -152,12 +172,6 @@
$scope.content = data;
- if (data.isChildOfListView && data.trashed === false) {
- $scope.page.listViewPath = ($routeParams.page) ?
- "/content/content/edit/" + data.parentId + "?page=" + $routeParams.page :
- "/content/content/edit/" + data.parentId;
- }
-
init();
syncTreeNode($scope.content, $scope.content.path, true);
@@ -219,7 +233,7 @@
$scope.page.showPreviewButton = true;
}
-
+
/** Syncs the content item to it's tree node - this occurs on first load and after saving */
function syncTreeNode(content, path, initialLoad) {
@@ -228,9 +242,13 @@
}
if (!$scope.content.isChildOfListView) {
- navigationService.syncTree({ tree: $scope.treeAlias, path: path.split(","), forceReload: initialLoad !== true }).then(function (syncArgs) {
- $scope.page.menu.currentNode = syncArgs.node;
- });
+ navigationService.syncTree({ tree: $scope.treeAlias, path: path.split(","), forceReload: initialLoad !== true })
+ .then(function (syncArgs) {
+ $scope.page.menu.currentNode = syncArgs.node;
+ }, function () {
+ //handle the rejection
+ console.log("A problem occurred syncing the tree! A path is probably incorrect.")
+ });
}
else if (initialLoad === true) {
@@ -328,7 +346,7 @@
$scope.contentForm.$dirty = false;
for (var i = 0; i < $scope.content.variants.length; i++) {
- if($scope.content.variants[i].isDirty){
+ if ($scope.content.variants[i].isDirty) {
$scope.contentForm.$dirty = true;
return;
}
@@ -337,7 +355,7 @@
// This is a helper method to reduce the amount of code repitition for actions: Save, Publish, SendToPublish
function performSave(args) {
-
+
//Used to check validility of nested form - coming from Content Apps mostly
//Set them all to be invalid
var fieldsToRollback = checkValidility();
@@ -348,7 +366,8 @@
scope: $scope,
content: $scope.content,
action: args.action,
- showNotifications: args.showNotifications
+ showNotifications: args.showNotifications,
+ softRedirect: true
}).then(function (data) {
//success
init();
@@ -364,11 +383,6 @@
function (err) {
syncTreeNode($scope.content, $scope.content.path);
- //error
- if (err) {
- editorState.set($scope.content);
- }
-
resetNestedFieldValiation(fieldsToRollback);
return $q.reject(err);
@@ -421,9 +435,9 @@
//need to show a notification else it's not clear there was an error.
localizationService.localizeMany([
- "speechBubbles_validationFailedHeader",
- "speechBubbles_validationFailedMessage"
- ]
+ "speechBubbles_validationFailedHeader",
+ "speechBubbles_validationFailedMessage"
+ ]
).then(function (data) {
notificationsService.error(data[0], data[1]);
});
@@ -440,6 +454,7 @@
$scope.content = data;
init();
+ startWatches($scope.content);
resetLastListPageNumber($scope.content);
@@ -454,13 +469,14 @@
$scope.page.loading = true;
loadContent().then(function () {
+ startWatches($scope.content);
$scope.page.loading = false;
});
}
$scope.unpublish = function () {
clearNotifications($scope.content);
- if (formHelper.submitForm({ scope: $scope, action: "unpublish", skipValidation: true })) {
+ if (formHelper.submitForm({ scope: $scope, action: "unpublish", skipValidation: true })) {
var dialog = {
parentScope: $scope,
view: "views/content/overlays/unpublish.html",
@@ -494,6 +510,7 @@
overlayService.close();
}
};
+
overlayService.open(dialog);
}
};
@@ -510,7 +527,7 @@
variants: $scope.content.variants, //set a model property for the dialog
skipFormValidation: true, //when submitting the overlay form, skip any client side validation
submitButtonLabelKey: "buttons_saveToPublish",
- submit: function(model) {
+ submit: function (model) {
model.submitButtonState = "busy";
clearNotifications($scope.content);
//we need to return this promise so that the dialog can handle the result and wire up the validation response
@@ -518,14 +535,14 @@
saveMethod: contentResource.sendToPublish,
action: "sendToPublish",
showNotifications: false
- }).then(function(data) {
- //show all notifications manually here since we disabled showing them automatically in the save method
- formHelper.showNotifications(data);
- clearNotifications($scope.content);
- overlayService.close();
- return $q.when(data);
- },
- function(err) {
+ }).then(function (data) {
+ //show all notifications manually here since we disabled showing them automatically in the save method
+ formHelper.showNotifications(data);
+ clearNotifications($scope.content);
+ overlayService.close();
+ return $q.when(data);
+ },
+ function (err) {
clearDirtyState($scope.content.variants);
model.submitButtonState = "error";
//re-map the dialog model since we've re-bound the properties
@@ -534,7 +551,7 @@
return $q.when(err);
});
},
- close: function() {
+ close: function () {
overlayService.close();
}
};
@@ -563,14 +580,13 @@
if (isContentCultureVariant()) {
//before we launch the dialog we want to execute all client side validations first
if (formHelper.submitForm({ scope: $scope, action: "publish" })) {
-
var dialog = {
parentScope: $scope,
view: "views/content/overlays/publish.html",
variants: $scope.content.variants, //set a model property for the dialog
skipFormValidation: true, //when submitting the overlay form, skip any client side validation
submitButtonLabelKey: "buttons_saveAndPublish",
- submit: function(model) {
+ submit: function (model) {
model.submitButtonState = "busy";
clearNotifications($scope.content);
//we need to return this promise so that the dialog can handle the result and wire up the validation response
@@ -578,14 +594,14 @@
saveMethod: contentResource.publish,
action: "publish",
showNotifications: false
- }).then(function(data) {
- //show all notifications manually here since we disabled showing them automatically in the save method
- formHelper.showNotifications(data);
- clearNotifications($scope.content);
- overlayService.close();
- return $q.when(data);
- },
- function(err) {
+ }).then(function (data) {
+ //show all notifications manually here since we disabled showing them automatically in the save method
+ formHelper.showNotifications(data);
+ clearNotifications($scope.content);
+ overlayService.close();
+ return $q.when(data);
+ },
+ function (err) {
clearDirtyState($scope.content.variants);
model.submitButtonState = "error";
//re-map the dialog model since we've re-bound the properties
@@ -594,11 +610,10 @@
return $q.when(err);
});
},
- close: function() {
+ close: function () {
overlayService.close();
}
};
-
overlayService.open(dialog);
}
else {
@@ -617,7 +632,7 @@
$scope.page.buttonGroupState = "success";
}, function () {
$scope.page.buttonGroupState = "error";
- });;
+ });
}
};
@@ -634,7 +649,7 @@
variants: $scope.content.variants, //set a model property for the dialog
skipFormValidation: true, //when submitting the overlay form, skip any client side validation
submitButtonLabelKey: "buttons_save",
- submit: function(model) {
+ submit: function (model) {
model.submitButtonState = "busy";
clearNotifications($scope.content);
//we need to return this promise so that the dialog can handle the result and wire up the validation response
@@ -642,14 +657,14 @@
saveMethod: $scope.saveMethod(),
action: "save",
showNotifications: false
- }).then(function(data) {
- //show all notifications manually here since we disabled showing them automatically in the save method
- formHelper.showNotifications(data);
- clearNotifications($scope.content);
- overlayService.close();
- return $q.when(data);
- },
- function(err) {
+ }).then(function (data) {
+ //show all notifications manually here since we disabled showing them automatically in the save method
+ formHelper.showNotifications(data);
+ clearNotifications($scope.content);
+ overlayService.close();
+ return $q.when(data);
+ },
+ function (err) {
clearDirtyState($scope.content.variants);
model.submitButtonState = "error";
//re-map the dialog model since we've re-bound the properties
@@ -658,7 +673,7 @@
return $q.when(err);
});
},
- close: function(oldModel) {
+ close: function (oldModel) {
overlayService.close();
}
};
@@ -685,7 +700,7 @@
};
- $scope.schedule = function() {
+ $scope.schedule = function () {
clearNotifications($scope.content);
//before we launch the dialog we want to execute all client side validations first
if (formHelper.submitForm({ scope: $scope, action: "schedule" })) {
@@ -755,7 +770,7 @@
}
};
- $scope.publishDescendants = function() {
+ $scope.publishDescendants = function () {
clearNotifications($scope.content);
//before we launch the dialog we want to execute all client side validations first
if (formHelper.submitForm({ scope: $scope, action: "publishDescendants" })) {
@@ -883,13 +898,13 @@
* @param {any} app
*/
$scope.appChanged = function (app) {
-
+
$scope.app = app;
-
+
$scope.$broadcast("editors.apps.appChanged", { app: app });
-
+
createButtons($scope.content);
-
+
};
/**
@@ -907,11 +922,11 @@
$scope.infiniteModel.close($scope.infiniteModel);
}
};
-
+
/**
* Call back when user click the back-icon
*/
- $scope.onBack = function() {
+ $scope.onBack = function () {
if ($scope.infiniteModel && $scope.infiniteModel.close) {
$scope.infiniteModel.close($scope.infiniteModel);
} else {
@@ -927,9 +942,7 @@
}
//since we are not notifying and clearing server validation messages when they are received due to how the variant
//switching works, we need to ensure they are cleared when this editor is destroyed
- if (!$scope.page.isNew) {
- serverValidationManager.clear();
- }
+ serverValidationManager.clear();
});
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js
index e58ff14e21..e2f5f71781 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js
@@ -328,6 +328,8 @@
isInfoTab = true;
loadAuditTrail();
loadRedirectUrls();
+ setNodePublishStatus();
+ formatDatesToLocal();
} else {
isInfoTab = false;
}
@@ -344,6 +346,7 @@
loadAuditTrail(true);
loadRedirectUrls();
setNodePublishStatus();
+ formatDatesToLocal();
}
updateCurrentUrls();
});
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorcontentheader.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorcontentheader.directive.js
index 4999f7007a..75fa0469bb 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorcontentheader.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorcontentheader.directive.js
@@ -1,10 +1,12 @@
(function () {
'use strict';
- function EditorContentHeader() {
+ function EditorContentHeader(serverValidationManager) {
function link(scope, el, attr, ctrl) {
-
+
+ var unsubscribe = [];
+
if (!scope.serverValidationNameField) {
scope.serverValidationNameField = "Name";
}
@@ -15,9 +17,44 @@
scope.vm = {};
scope.vm.dropdownOpen = false;
scope.vm.currentVariant = "";
-
+ scope.vm.variantsWithError = [];
+ scope.vm.defaultVariant = null;
+
+ scope.vm.errorsOnOtherVariants = false;// indicating wether to show that other variants, than the current, have errors.
+
+ function checkErrorsOnOtherVariants() {
+ var check = false;
+ angular.forEach(scope.content.variants, function (variant) {
+ if (scope.openVariants.indexOf(variant.language.culture) === -1 && scope.variantHasError(variant.language.culture)) {
+ check = true;
+ }
+ });
+ scope.vm.errorsOnOtherVariants = check;
+ }
+
+ function onCultureValidation(valid, errors, allErrors, culture) {
+ var index = scope.vm.variantsWithError.indexOf(culture);
+ if(valid === true) {
+ if (index !== -1) {
+ scope.vm.variantsWithError.splice(index, 1);
+ }
+ } else {
+ if (index === -1) {
+ scope.vm.variantsWithError.push(culture);
+ }
+ }
+ checkErrorsOnOtherVariants();
+ }
+
function onInit() {
+ // find default.
+ angular.forEach(scope.content.variants, function (variant) {
+ if (variant.language.isDefault) {
+ scope.vm.defaultVariant = variant;
+ }
+ });
+
setCurrentVariant();
angular.forEach(scope.content.apps, (app) => {
@@ -26,12 +63,22 @@
}
});
+
+ angular.forEach(scope.content.variants, function (variant) {
+ unsubscribe.push(serverValidationManager.subscribe(null, variant.language.culture, null, onCultureValidation));
+ });
+
+ unsubscribe.push(serverValidationManager.subscribe(null, null, null, onCultureValidation));
+
+
+
}
function setCurrentVariant() {
angular.forEach(scope.content.variants, function (variant) {
if (variant.active) {
scope.vm.currentVariant = variant;
+ checkErrorsOnOtherVariants();
}
});
}
@@ -80,9 +127,24 @@
* @param {any} culture
*/
scope.variantIsOpen = function(culture) {
- if(scope.openVariants.indexOf(culture) !== -1) {
+ return (scope.openVariants.indexOf(culture) !== -1);
+ }
+
+ /**
+ * Check whether a variant has a error, used to display errors in variant switcher.
+ * @param {any} culture
+ */
+ scope.variantHasError = function(culture) {
+ // if we are looking for the default language we also want to check for invariant.
+ if (culture === scope.vm.defaultVariant.language.culture) {
+ if(scope.vm.variantsWithError.indexOf("invariant") !== -1) {
+ return true;
+ }
+ }
+ if(scope.vm.variantsWithError.indexOf(culture) !== -1) {
return true;
}
+ return false;
}
onInit();
@@ -103,6 +165,12 @@
}
});
}
+
+ scope.$on('$destroy', function () {
+ for (var u in unsubscribe) {
+ unsubscribe[u]();
+ }
+ });
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js
index eb5fd055eb..3541a1cf68 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js
@@ -3,107 +3,113 @@
**/
angular.module('umbraco.directives')
-.directive('onDragEnter', function () {
- return {
- link: function (scope, elm, attrs) {
- var f = function () {
- scope.$apply(attrs.onDragEnter);
- };
- elm.on("dragenter", f);
- scope.$on("$destroy", function(){ elm.off("dragenter", f);} );
- }
- };
-})
-
-.directive('onDragLeave', function () {
- return function (scope, elm, attrs) {
- var f = function (event) {
- var rect = this.getBoundingClientRect();
- var getXY = function getCursorPosition(event) {
- var x, y;
-
- if (typeof event.clientX === 'undefined') {
- // try touch screen
- x = event.pageX + document.documentElement.scrollLeft;
- y = event.pageY + document.documentElement.scrollTop;
- } else {
- x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
- y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
- }
-
- return { x: x, y : y };
- };
-
- var e = getXY(event.originalEvent);
-
- // Check the mouseEvent coordinates are outside of the rectangle
- if (e.x > rect.left + rect.width - 1 || e.x < rect.left || e.y > rect.top + rect.height - 1 || e.y < rect.top) {
- scope.$apply(attrs.onDragLeave);
+ .directive('onDragEnter', function () {
+ return {
+ link: function (scope, elm, attrs) {
+ var f = function () {
+ scope.$apply(attrs.onDragEnter);
+ };
+ elm.on("dragenter", f);
+ scope.$on("$destroy", function () { elm.off("dragenter", f); });
}
};
+ })
- elm.on("dragleave", f);
- scope.$on("$destroy", function(){ elm.off("dragleave", f);} );
- };
-})
+ .directive('onDragLeave', function () {
+ return function (scope, elm, attrs) {
+ var f = function (event) {
+ var rect = this.getBoundingClientRect();
+ var getXY = function getCursorPosition(event) {
+ var x, y;
-.directive('onDragOver', function () {
- return {
- link: function (scope, elm, attrs) {
- var f = function () {
- scope.$apply(attrs.onDragOver);
+ if (typeof event.clientX === 'undefined') {
+ // try touch screen
+ x = event.pageX + document.documentElement.scrollLeft;
+ y = event.pageY + document.documentElement.scrollTop;
+ } else {
+ x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
+ y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
+ }
+
+ return { x: x, y: y };
+ };
+
+ var e = getXY(event.originalEvent);
+
+ // Check the mouseEvent coordinates are outside of the rectangle
+ if (e.x > rect.left + rect.width - 1 || e.x < rect.left || e.y > rect.top + rect.height - 1 || e.y < rect.top) {
+ scope.$apply(attrs.onDragLeave);
+ }
};
- elm.on("dragover", f);
- scope.$on("$destroy", function(){ elm.off("dragover", f);} );
- }
- };
-})
-.directive('onDragStart', function () {
- return {
- link: function (scope, elm, attrs) {
- var f = function () {
- scope.$apply(attrs.onDragStart);
- };
- elm.on("dragstart", f);
- scope.$on("$destroy", function(){ elm.off("dragstart", f);} );
- }
- };
-})
+ elm.on("dragleave", f);
+ scope.$on("$destroy", function () { elm.off("dragleave", f); });
+ };
+ })
-.directive('onDragEnd', function () {
- return {
- link: function (scope, elm, attrs) {
- var f = function () {
- scope.$apply(attrs.onDragEnd);
- };
- elm.on("dragend", f);
- scope.$on("$destroy", function(){ elm.off("dragend", f);} );
- }
- };
-})
+ .directive('onDragOver', function () {
+ return {
+ link: function (scope, elm, attrs) {
+ var f = function () {
+ scope.$apply(attrs.onDragOver);
+ };
+ elm.on("dragover", f);
+ scope.$on("$destroy", function () { elm.off("dragover", f); });
+ }
+ };
+ })
-.directive('onDrop', function () {
- return {
- link: function (scope, elm, attrs) {
- var f = function () {
- scope.$apply(attrs.onDrop);
- };
- elm.on("drop", f);
- scope.$on("$destroy", function(){ elm.off("drop", f);} );
- }
- };
-})
+ .directive('onDragStart', function () {
+ return {
+ link: function (scope, elm, attrs) {
+ var f = function () {
+ scope.$apply(attrs.onDragStart);
+ };
+ elm.on("dragstart", f);
+ scope.$on("$destroy", function () { elm.off("dragstart", f); });
+ }
+ };
+ })
-.directive('onOutsideClick', function ($timeout, angularHelper) {
- return function (scope, element, attrs) {
+ .directive('onDragEnd', function () {
+ return {
+ link: function (scope, elm, attrs) {
+ var f = function () {
+ scope.$apply(attrs.onDragEnd);
+ };
+ elm.on("dragend", f);
+ scope.$on("$destroy", function () { elm.off("dragend", f); });
+ }
+ };
+ })
- var eventBindings = [];
+ .directive('onDrop', function () {
+ return {
+ link: function (scope, elm, attrs) {
+ var f = function () {
+ scope.$apply(attrs.onDrop);
+ };
+ elm.on("drop", f);
+ scope.$on("$destroy", function () { elm.off("drop", f); });
+ }
+ };
+ })
+
+ .directive('onOutsideClick', function ($timeout, angularHelper) {
+ return function (scope, element, attrs) {
+
+ 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; }
- function oneTimeClick(event) {
// ignore clicks on new overlay
- var parents = $(event.target).parents(".umb-overlay,.umb-tour");
- if(parents.length > 0){
+ var parents = $(event.target).parents("a,button,.umb-overlay,.umb-tour");
+ if (parents.length > 0) {
return;
}
@@ -126,70 +132,70 @@ angular.module('umbraco.directives')
}
//ignore clicks inside this element
- if( $(element).has( $(event.target) ).length > 0 ){
+ if ($(element).has($(event.target)).length > 0) {
return;
}
- scope.$apply(attrs.onOutsideClick);
- }
-
-
- $timeout(function(){
-
- if ("bindClickOn" in attrs) {
-
- eventBindings.push(scope.$watch(function() {
- return attrs.bindClickOn;
- }, function(newValue) {
- if (newValue === "true") {
- $(document).on("click", oneTimeClick);
- } else {
- $(document).off("click", oneTimeClick);
- }
- }));
-
- } else {
- $(document).on("click", oneTimeClick);
+ angularHelper.safeApply(scope, attrs.onOutsideClick);
}
- scope.$on("$destroy", function() {
- $(document).off("click", oneTimeClick);
- // unbind watchers
- for (var e in eventBindings) {
- eventBindings[e]();
+ $timeout(function () {
+
+ if ("bindClickOn" in attrs) {
+
+ eventBindings.push(scope.$watch(function () {
+ return attrs.bindClickOn;
+ }, function (newValue) {
+ if (newValue === "true") {
+ $(document).on("click", oneTimeClick);
+ } else {
+ $(document).off("click", oneTimeClick);
+ }
+ }));
+
+ } else {
+ $(document).on("click", oneTimeClick);
}
+ scope.$on("$destroy", function () {
+ $(document).off("click", oneTimeClick);
+
+ // unbind watchers
+ for (var e in eventBindings) {
+ eventBindings[e]();
+ }
+
+ });
+ }); // Temp removal of 1 sec timeout to prevent bug where overlay does not open. We need to find a better solution.
+
+ };
+ })
+
+ .directive('onRightClick', function ($parse) {
+
+ document.oncontextmenu = function (e) {
+ if (e.target.hasAttribute('on-right-click')) {
+ e.preventDefault();
+ e.stopPropagation();
+ return false;
+ }
+ };
+
+ return function (scope, el, attrs) {
+ el.on('contextmenu', function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ var fn = $parse(attrs.onRightClick);
+ scope.$apply(function () {
+ fn(scope, { $event: e });
+ });
+ return false;
});
- }); // Temp removal of 1 sec timeout to prevent bug where overlay does not open. We need to find a better solution.
+ };
+ })
- };
-})
-
-.directive('onRightClick',function($parse){
-
- document.oncontextmenu = function (e) {
- if(e.target.hasAttribute('on-right-click')) {
- e.preventDefault();
- e.stopPropagation();
- return false;
- }
- };
-
- return function(scope,el,attrs){
- el.on('contextmenu',function(e){
- e.preventDefault();
- e.stopPropagation();
- var fn = $parse(attrs.onRightClick);
- scope.$apply(function () {
- fn(scope, { $event: e });
- });
- return false;
- });
- };
-})
-
-.directive('onDelayedMouseleave', function ($timeout, $parse) {
+ .directive('onDelayedMouseleave', function ($timeout, $parse) {
return {
restrict: 'A',
@@ -198,20 +204,20 @@ angular.module('umbraco.directives')
var active = false;
var fn = $parse(attrs.onDelayedMouseleave);
- var leave_f = function(event) {
- var callback = function() {
- fn(scope, {$event:event});
+ var leave_f = function (event) {
+ var callback = function () {
+ fn(scope, { $event: event });
};
active = false;
- $timeout(function(){
- if(active === false){
+ $timeout(function () {
+ if (active === false) {
scope.$apply(callback);
}
}, 650);
};
- var enter_f = function(event, args){
+ var enter_f = function (event, args) {
active = true;
};
@@ -220,7 +226,7 @@ angular.module('umbraco.directives')
element.on("mouseenter", enter_f);
//unsub events
- scope.$on("$destroy", function(){
+ scope.$on("$destroy", function () {
element.off("mouseleave", leave_f);
element.off("mouseenter", enter_f);
});
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreesearchbox.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreesearchbox.directive.js
index b81e62a66b..4ba4cf96bb 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreesearchbox.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreesearchbox.directive.js
@@ -12,7 +12,6 @@ function treeSearchBox(localizationService, searchService, $q) {
searchFromName: "@",
showSearch: "@",
section: "@",
- ignoreUserStartNodes: "@",
hideSearchCallback: "=",
searchCallback: "="
},
@@ -35,7 +34,6 @@ function treeSearchBox(localizationService, searchService, $q) {
scope.showSearch = "false";
}
-
//used to cancel any request in progress if another one needs to take it's place
var canceler = null;
@@ -62,11 +60,6 @@ function treeSearchBox(localizationService, searchService, $q) {
searchArgs["searchFrom"] = scope.searchFromId;
}
- //append ignoreUserStartNodes value if there is one
- if (scope.ignoreUserStartNodes) {
- searchArgs["ignoreUserStartNodes"] = scope.ignoreUserStartNodes;
- }
-
searcher(searchArgs).then(function (data) {
scope.searchCallback(data);
//set back to null so it can be re-created
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js
index bbbdd392b2..396699866c 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js
@@ -505,6 +505,7 @@
property.showOnMemberProfile = propertyModel.showOnMemberProfile;
property.memberCanEdit = propertyModel.memberCanEdit;
property.isSensitiveValue = propertyModel.isSensitiveValue;
+ property.allowCultureVariant = propertyModel.allowCultureVariant;
// update existing data types
if(model.updateSameDataTypes) {
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbpagination.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbpagination.directive.js
index 4c1a8747d1..ea57a3fad6 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbpagination.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbpagination.directive.js
@@ -96,13 +96,13 @@ Use this directive to generate a pagination.
scope.pageNumber = parseInt(scope.pageNumber);
}
- scope.pagination = [];
+ let tempPagination = [];
var i = 0;
if (scope.totalPages <= 10) {
for (i = 0; i < scope.totalPages; i++) {
- scope.pagination.push({
+ tempPagination.push({
val: (i + 1),
isActive: scope.pageNumber === (i + 1)
});
@@ -119,7 +119,7 @@ Use this directive to generate a pagination.
start = Math.min(maxIndex, start);
for (i = start; i < (10 + start) ; i++) {
- scope.pagination.push({
+ tempPagination.push({
val: (i + 1),
isActive: scope.pageNumber === (i + 1)
});
@@ -129,7 +129,7 @@ Use this directive to generate a pagination.
if (start > 0) {
localizationService.localize("general_first").then(function(value){
var firstLabel = value;
- scope.pagination.unshift({ name: firstLabel, val: 1, isActive: false }, {val: "...",isActive: false});
+ tempPagination.unshift({ name: firstLabel, val: 1, isActive: false }, {val: "...",isActive: false});
});
}
@@ -137,9 +137,11 @@ Use this directive to generate a pagination.
if (start < maxIndex) {
localizationService.localize("general_last").then(function(value){
var lastLabel = value;
- scope.pagination.push({ val: "...", isActive: false }, { name: lastLabel, val: scope.totalPages, isActive: false });
+ tempPagination.push({ val: "...", isActive: false }, { name: lastLabel, val: scope.totalPages, isActive: false });
});
}
+
+ scope.pagination = tempPagination;
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js
index 61f7f039d9..39d903d85e 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js
@@ -12,27 +12,50 @@
function valPropertyMsg(serverValidationManager) {
return {
- require: ['^^form', '^^valFormManager', '^^umbProperty'],
+ require: ['^^form', '^^valFormManager', '^^umbProperty', '?^^umbVariantContent'],
replace: true,
restrict: "E",
template: "
{{errorMsg}}
",
scope: {},
link: function (scope, element, attrs, ctrl) {
+
+ var unsubscribe = [];
+ var watcher = null;
+ var hasError = false;
+ //create properties on our custom scope so we can use it in our template
+ scope.errorMsg = "";
+
+
//the property form controller api
var formCtrl = ctrl[0];
//the valFormManager controller api
var valFormManager = ctrl[1];
//the property controller api
var umbPropCtrl = ctrl[2];
+ //the variants controller api
+ var umbVariantCtrl = ctrl[3];
- scope.currentProperty = umbPropCtrl.property;
+ var currentProperty = umbPropCtrl.property;
+ scope.currentProperty = currentProperty;
+ var currentCulture = currentProperty.culture;
- //if the property is invariant (no culture), then we will explicitly set it to the string 'invariant'
- //since this matches the value that the server will return for an invariant property.
- var currentCulture = scope.currentProperty.culture || "invariant";
+ if (umbVariantCtrl) {
+ //if we are inside of an umbVariantContent directive
- var watcher = null;
+ var currentVariant = umbVariantCtrl.editor.content;
+
+ // Lets check if we have variants and we are on the default language then ...
+ if (umbVariantCtrl.content.variants.length > 1 && !currentVariant.language.isDefault && !currentCulture && !currentProperty.unlockInvariantValue) {
+ //This property is locked cause its a invariant property shown on a non-default language.
+ //Therefor do not validate this field.
+ return;
+ }
+ }
+
+ // if we have reached this part, and there is no culture, then lets fallback to invariant. To get the validation feedback for invariant language.
+ currentCulture = currentCulture || "invariant";
+
// Gets the error message to display
function getErrorMsg() {
@@ -138,13 +161,6 @@ function valPropertyMsg(serverValidationManager) {
}
- var hasError = false;
-
- //create properties on our custom scope so we can use it in our template
- scope.errorMsg = "";
-
- var unsubscribe = [];
-
//listen for form validation changes.
//The alternative is to add a watch to formCtrl.$invalid but that would lead to many more watches then
// subscribing to this single watch.
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valserver.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valserver.directive.js
index eb522fe783..a0cc7e3033 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valserver.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valserver.directive.js
@@ -7,7 +7,7 @@
**/
function valServer(serverValidationManager) {
return {
- require: ['ngModel', '?^^umbProperty'],
+ require: ['ngModel', '?^^umbProperty', '?^^umbVariantContent'],
restrict: "A",
scope: {},
link: function (scope, element, attr, ctrls) {
@@ -18,9 +18,29 @@ function valServer(serverValidationManager) {
//we cannot proceed, this validator will be disabled
return;
}
+
+ // optional reference to the varaint-content-controller, needed to avoid validation when the field is invariant on non-default languages.
+ var umbVariantCtrl = ctrls.length > 2 ? ctrls[2] : null;
var currentProperty = umbPropCtrl.property;
var currentCulture = currentProperty.culture;
+
+ if (umbVariantCtrl) {
+ //if we are inside of an umbVariantContent directive
+
+ var currentVariant = umbVariantCtrl.editor.content;
+
+ // Lets check if we have variants and we are on the default language then ...
+ if (umbVariantCtrl.content.variants.length > 1 && !currentVariant.language.isDefault && !currentCulture && !currentProperty.unlockInvariantValue) {
+ //This property is locked cause its a invariant property shown on a non-default language.
+ //Therefor do not validate this field.
+ return;
+ }
+ }
+
+ // if we have reached this part, and there is no culture, then lets fallback to invariant. To get the validation feedback for invariant language.
+ currentCulture = currentCulture || "invariant";
+
var watcher = null;
var unsubscribe = [];
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
index d571de0e2d..b807a4dc31 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
@@ -365,28 +365,17 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
*
*
* @param {Int} id id of content item to return
- * @param {Bool} options.ignoreUserStartNodes set to true to allow a user to choose nodes that they normally don't have access to
+ * @param {Int} culture optional culture to retrieve the item in
* @returns {Promise} resourcePromise object containing the content item.
*
*/
- getById: function (id, options) {
- var defaults = {
- ignoreUserStartNodes: false
- };
- if (options === undefined) {
- options = {};
- }
- //overwrite the defaults if there are any specified
- angular.extend(defaults, options);
- //now copy back to the options we will use
- options = defaults;
-
+ getById: function (id) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetById",
- [{ id: id }, { ignoreUserStartNodes: options.ignoreUserStartNodes }])),
+ { id: id })),
'Failed to retrieve data for content id ' + id)
.then(function (result) {
return $q.when(umbDataFormatter.formatContentGetData(result));
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
index d5145727ac..753d180880 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
@@ -284,31 +284,15 @@ function entityResource($q, $http, umbRequestHelper) {
* @returns {Promise} resourcePromise object containing the entity.
*
*/
- getAncestors: function (id, type, culture, options) {
- var defaults = {
- ignoreUserStartNodes: false
- };
- if (options === undefined) {
- options = {};
- }
- //overwrite the defaults if there are any specified
- angular.extend(defaults, options);
- //now copy back to the options we will use
- options = defaults;
+ getAncestors: function (id, type, culture) {
if (culture === undefined) culture = "";
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
"GetAncestors",
- [
- { id: id },
- { type: type },
- { culture: culture },
- { ignoreUserStartNodes: options.ignoreUserStartNodes }
- ])),
-
- 'Failed to retrieve ancestor data for id ' + id);
+ [{ id: id }, { type: type }, { culture: culture }])),
+ 'Failed to retrieve ancestor data for id ' + id);
},
/**
@@ -440,8 +424,7 @@ function entityResource($q, $http, umbRequestHelper) {
pageNumber: 1,
filter: '',
orderDirection: "Ascending",
- orderBy: "SortOrder",
- ignoreUserStartNodes: false
+ orderBy: "SortOrder"
};
if (options === undefined) {
options = {};
@@ -470,8 +453,7 @@ function entityResource($q, $http, umbRequestHelper) {
pageSize: options.pageSize,
orderBy: options.orderBy,
orderDirection: options.orderDirection,
- filter: encodeURIComponent(options.filter),
- ignoreUserStartNodes: options.ignoreUserStartNodes
+ filter: encodeURIComponent(options.filter)
}
)),
'Failed to retrieve child data for id ' + parentId);
@@ -499,19 +481,12 @@ function entityResource($q, $http, umbRequestHelper) {
* @returns {Promise} resourcePromise object containing the entity array.
*
*/
- search: function (query, type, options, canceler) {
+ search: function (query, type, searchFrom, canceler) {
var args = [{ query: query }, { type: type }];
-
- if(options !== undefined) {
- if (options.searchFrom) {
- args.push({ searchFrom: options.searchFrom });
- }
- if (options.ignoreUserStartNodes) {
- args.push({ ignoreUserStartNodes: options.ignoreUserStartNodes });
- }
+ if (searchFrom) {
+ args.push({ searchFrom: searchFrom });
}
-
var httpConfig = {};
if (canceler) {
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/logviewer.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/logviewer.resource.js
index 75c23e7adf..b52021ed38 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/logviewer.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/logviewer.resource.js
@@ -1,39 +1,39 @@
/**
- * @ngdoc service
- * @name umbraco.resources.logViewerResource
- * @description Retrives Umbraco log items (by default from JSON files on disk)
- *
- *
- **/
- function logViewerResource($q, $http, umbRequestHelper) {
+ * @ngdoc service
+ * @name umbraco.resources.logViewerResource
+ * @description Retrives Umbraco log items (by default from JSON files on disk)
+ *
+ *
+ **/
+function logViewerResource($q, $http, umbRequestHelper) {
//the factory object returned
return {
- getNumberOfErrors: function () {
+ getNumberOfErrors: function (startDate, endDate) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"logViewerApiBaseUrl",
- "GetNumberOfErrors")),
+ "GetNumberOfErrors")+ '?startDate='+startDate+ '&endDate='+ endDate ),
'Failed to retrieve number of errors in logs');
},
- getLogLevelCounts: function () {
+ getLogLevelCounts: function (startDate, endDate) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"logViewerApiBaseUrl",
- "GetLogLevelCounts")),
+ "GetLogLevelCounts")+ '?startDate='+startDate+ '&endDate='+ endDate ),
'Failed to retrieve log level counts');
},
- getMessageTemplates: function () {
+ getMessageTemplates: function (startDate, endDate) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"logViewerApiBaseUrl",
- "GetMessageTemplates")),
+ "GetMessageTemplates")+ '?startDate='+startDate+ '&endDate='+ endDate ),
'Failed to retrieve log templates');
},
@@ -93,12 +93,12 @@
'Failed to retrieve common log messages');
},
- canViewLogs: function () {
+ canViewLogs: function (startDate, endDate) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"logViewerApiBaseUrl",
- "GetCanViewLogs")),
+ "GetCanViewLogs") + '?startDate='+startDate+ '&endDate='+ endDate ),
'Failed to retrieve state if logs can be viewed');
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
index 462184c9f2..1d6d5171a1 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
@@ -329,8 +329,7 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
filter: '',
orderDirection: "Ascending",
orderBy: "SortOrder",
- orderBySystemField: true,
- ignoreUserStartNodes: false
+ orderBySystemField: true
};
if (options === undefined) {
options = {};
@@ -368,7 +367,6 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
"GetChildren",
[
{ id: parentId },
- { ignoreUserStartNodes: options.ignoreUserStartNodes },
{ pageNumber: options.pageNumber },
{ pageSize: options.pageSize },
{ orderBy: options.orderBy },
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js
index 1b2be5f635..732f682082 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js
@@ -5,7 +5,7 @@
* @description A helper service for most editors, some methods are specific to content/media/member model types but most are used by
* all editors to share logic and reduce the amount of replicated code among editors.
**/
-function contentEditingHelper(fileManager, $q, $location, $routeParams, notificationsService, navigationService, localizationService, serverValidationManager, formHelper) {
+function contentEditingHelper(fileManager, $q, $location, $routeParams, editorState, notificationsService, navigationService, localizationService, serverValidationManager, formHelper) {
function isValidIdentifier(id) {
@@ -34,9 +34,10 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
return {
+ //TODO: We need to move some of this to formHelper for saving, too many editors use this method for saving when this entire
+ //service should only be used for content/media/members
+
/** Used by the content editor and mini content editor to perform saving operations */
- // TODO: Make this a more helpful/reusable method for other form operations! we can simplify this form most forms
- // = this is already done in the formhelper service
contentEditorPerformSave: function (args) {
if (!angular.isObject(args)) {
throw "args must be an object";
@@ -53,18 +54,19 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
if (args.showNotifications === undefined) {
args.showNotifications = true;
}
-
- var redirectOnSuccess = args.redirectOnSuccess !== undefined ? args.redirectOnSuccess : true;
- var redirectOnFailure = args.redirectOnFailure !== undefined ? args.redirectOnFailure : true;
+ if (args.softRedirect === undefined) {
+ //when true, the url will change but it won't actually re-route
+ //this is merely here for compatibility, if only the content/media/members used this service we'd prob be ok but tons of editors
+ //use this service unfortunately and probably packages too.
+ args.softRedirect = false;
+ }
var self = this;
//we will use the default one for content if not specified
var rebindCallback = args.rebindCallback === undefined ? self.reBindChangedProperties : args.rebindCallback;
- if (!args.scope.busy && formHelper.submitForm({ scope: args.scope, action: args.action })) {
-
- args.scope.busy = true;
+ if (formHelper.submitForm({ scope: args.scope, action: args.action })) {
return args.saveMethod(args.content, $routeParams.create, fileManager.getFiles(), args.showNotifications)
.then(function (data) {
@@ -74,26 +76,30 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
self.handleSuccessfulSave({
scope: args.scope,
savedContent: data,
- redirectOnSuccess: redirectOnSuccess,
+ softRedirect: args.softRedirect,
rebindCallback: function () {
rebindCallback.apply(self, [args.content, data]);
}
});
- args.scope.busy = false;
+ //update editor state to what is current
+ editorState.set(args.content);
+
return $q.resolve(data);
}, function (err) {
self.handleSaveError({
showNotifications: args.showNotifications,
- redirectOnFailure: redirectOnFailure,
+ softRedirect: args.softRedirect,
err: err,
rebindCallback: function () {
rebindCallback.apply(self, [args.content, err.data]);
}
});
- args.scope.busy = false;
+ //update editor state to what is current
+ editorState.set(args.content);
+
return $q.reject(err);
});
}
@@ -265,7 +271,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
// if publishing is allowed also allow schedule publish
// we add this manually becuase it doesn't have a permission so it wont
// get picked up by the loop through permissions
- if( _.contains(args.content.allowedActions, "U")) {
+ if (_.contains(args.content.allowedActions, "U")) {
buttons.subButtons.push(createButtonDefinition("SCHEDULE"));
buttons.subButtons.push(createButtonDefinition("PUBLISH_DESCENDANTS"));
}
@@ -274,7 +280,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
// so long as it's already published and if the user has access to publish
// and the user has access to unpublish (may have been removed via Event)
if (!args.create) {
- var hasPublishedVariant = args.content.variants.filter(function(variant) { return (variant.state === "Published" || variant.state === "PublishedPendingChanges"); }).length > 0;
+ var hasPublishedVariant = args.content.variants.filter(function (variant) { return (variant.state === "Published" || variant.state === "PublishedPendingChanges"); }).length > 0;
if (hasPublishedVariant && _.contains(args.content.allowedActions, "U") && _.contains(args.content.allowedActions, "Z")) {
buttons.subButtons.push(createButtonDefinition("Z"));
}
@@ -444,7 +450,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
var shouldIgnore = function (propName) {
return _.some([
"variants",
-
+
"tabs",
"properties",
"apps",
@@ -574,15 +580,16 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
* A function to handle what happens when we have validation issues from the server side
*
*/
+
+ //TODO: Too many editors use this method for saving when this entire service should only be used for content/media/members,
+ // there is formHelper.handleError for other editors which should be used!
+
handleSaveError: function (args) {
if (!args.err) {
throw "args.err cannot be null";
}
- if (args.redirectOnFailure === undefined || args.redirectOnFailure === null) {
- throw "args.redirectOnFailure must be set to true or false";
- }
-
+
//When the status is a 400 status with a custom header: X-Status-Reason: Validation failed, we have validation errors.
//Otherwise the error is probably due to invalid data (i.e. someone mucking around with the ids or something).
//Or, some strange server error
@@ -600,16 +607,16 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
}
}
- if (!args.redirectOnFailure || !this.redirectToCreatedContent(args.err.data.id, args.err.data.ModelState)) {
- //we are not redirecting because this is not new content, it is existing content. In this case
- // we need to detect what properties have changed and re-bind them with the server data. Then we need
- // to re-bind any server validation errors after the digest takes place.
+ if (!this.redirectToCreatedContent(args.err.data.id) || args.softRedirect) {
+ // If we are not redirecting it's because this is not newly created content, else in some cases we are
+ // soft-redirecting which means the URL will change but the route wont (i.e. creating content).
+ // In this case we need to detect what properties have changed and re-bind them with the server data.
if (args.rebindCallback && angular.isFunction(args.rebindCallback)) {
args.rebindCallback();
}
- //notify all validators (don't clear the server validations though since we need to maintain their state because of
+ // In this case notify all validators (don't clear the server validations though since we need to maintain their state because of
// how the variant switcher works in content). server validation state is always cleared when an editor first loads
// and in theory when an editor is destroyed.
serverValidationManager.notify();
@@ -633,6 +640,10 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
* ensure the notifications are displayed and that the appropriate events are fired. This will also check if we need to redirect
* when we're creating new content.
*/
+
+ //TODO: We need to move some of this to formHelper for saving, too many editors use this method for saving when this entire
+ //service should only be used for content/media/members
+
handleSuccessfulSave: function (args) {
if (!args) {
@@ -642,14 +653,12 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
throw "args.savedContent cannot be null";
}
- // the default behaviour is to redirect on success. This adds option to prevent when false
- args.redirectOnSuccess = args.redirectOnSuccess !== undefined ? args.redirectOnSuccess : true;
+ if (!this.redirectToCreatedContent(args.redirectId ? args.redirectId : args.savedContent.id) || args.softRedirect) {
- if (!args.redirectOnSuccess || !this.redirectToCreatedContent(args.redirectId ? args.redirectId : args.savedContent.id)) {
+ // If we are not redirecting it's because this is not newly created content, else in some cases we are
+ // soft-redirecting which means the URL will change but the route wont (i.e. creating content).
- //we are not redirecting because this is not new content, it is existing content. In this case
- // we need to detect what properties have changed and re-bind them with the server data.
- //call the callback
+ // In this case we need to detect what properties have changed and re-bind them with the server data.
if (args.rebindCallback && angular.isFunction(args.rebindCallback)) {
args.rebindCallback();
}
@@ -667,7 +676,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
* We need to decide if we need to redirect to edito mode or if we will remain in create mode.
* We will only need to maintain create mode if we have not fulfilled the basic requirements for creating an entity which is at least having a name and ID
*/
- redirectToCreatedContent: function (id, modelState) {
+ redirectToCreatedContent: function (id) {
//only continue if we are currently in create mode and not in infinite mode and if the resulting ID is valid
if ($routeParams.create && (isValidIdentifier(id))) {
@@ -679,7 +688,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
//clear the query strings
navigationService.clearSearch(["cculture"]);
-
+
//change to new path
$location.path("/" + $routeParams.section + "/" + $routeParams.tree + "/" + $routeParams.method + "/" + id);
//don't add a browser history for this
@@ -699,6 +708,10 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
* For some editors like scripts or entites that have names as ids, these names can change and we need to redirect
* to their new paths, this is helper method to do that.
*/
+
+ //TODO: We need to move some of this to formHelper for saving, too many editors use this method for saving when this entire
+ //service should only be used for content/media/members
+
redirectToRenamedContent: function (id) {
//clear the query strings
navigationService.clearSearch();
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/editorstate.service.js b/src/Umbraco.Web.UI.Client/src/common/services/editorstate.service.js
index 5e42af9c5e..d00edae410 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/editorstate.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/editorstate.service.js
@@ -5,13 +5,15 @@
*
* @description
* Tracks the parent object for complex editors by exposing it as
- * an object reference via editorState.current.entity
+ * an object reference via editorState.current.getCurrent().
+ * The state is cleared on each successful route.
*
* it is possible to modify this object, so should be used with care
*/
-angular.module('umbraco.services').factory("editorState", function() {
+angular.module('umbraco.services').factory("editorState", function ($rootScope) {
var current = null;
+
var state = {
/**
@@ -40,7 +42,7 @@ angular.module('umbraco.services').factory("editorState", function() {
* Since the editorstate entity is read-only, you cannot set it to null
* only through the reset() method
*/
- reset: function() {
+ reset: function () {
current = null;
},
@@ -59,9 +61,10 @@ angular.module('umbraco.services').factory("editorState", function() {
* editorState.current can not be overwritten, you should only read values from it
* since modifying individual properties should be handled by the property editors
*/
- getCurrent: function() {
+ getCurrent: function () {
return current;
- }
+ },
+
};
// TODO: This shouldn't be removed! use getCurrent() method instead of a hacked readonly property which is confusing.
@@ -76,5 +79,13 @@ angular.module('umbraco.services').factory("editorState", function() {
}
});
+ //execute on each successful route (this is only bound once per application since a service is a singleton)
+ $rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
+
+ //reset the editorState on each successful route chage
+ state.reset();
+
+ });
+
return state;
});
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/filemanager.service.js b/src/Umbraco.Web.UI.Client/src/common/services/filemanager.service.js
index 6d319ad90a..8fe6761c94 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/filemanager.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/filemanager.service.js
@@ -8,11 +8,12 @@
* that need to attach files.
* When a route changes successfully, we ensure that the collection is cleared.
*/
-function fileManager() {
+function fileManager($rootScope) {
var fileCollection = [];
- return {
+
+ var mgr = {
/**
* @ngdoc function
* @name umbraco.services.fileManager#addFiles
@@ -24,7 +25,7 @@ function fileManager() {
* for the files collection that effectively clears the files for the specified editor.
*/
setFiles: function (args) {
-
+
//propertyAlias, files
if (!angular.isString(args.propertyAlias)) {
throw "args.propertyAlias must be a non empty string";
@@ -52,7 +53,7 @@ function fileManager() {
fileCollection.push({ alias: args.propertyAlias, file: args.files[i], culture: args.culture, metaData: metaData });
}
},
-
+
/**
* @ngdoc function
* @name umbraco.services.fileManager#getFiles
@@ -62,10 +63,10 @@ function fileManager() {
* @description
* Returns all of the files attached to the file manager
*/
- getFiles: function() {
+ getFiles: function () {
return fileCollection;
},
-
+
/**
* @ngdoc function
* @name umbraco.services.fileManager#clearFiles
@@ -78,7 +79,17 @@ function fileManager() {
clearFiles: function () {
fileCollection = [];
}
-};
+ };
+
+ //execute on each successful route (this is only bound once per application since a service is a singleton)
+ $rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
+ //reset the file manager on each route change, the file collection is only relavent
+ // when working in an editor and submitting data to the server.
+ //This ensures that memory remains clear of any files and that the editors don't have to manually clear the files.
+ mgr.clearFiles();
+ });
+
+ return mgr;
}
angular.module('umbraco.services').factory('fileManager', fileManager);
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js
index b6bcafbddf..0555318bae 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js
@@ -40,7 +40,7 @@ function formHelper(angularHelper, serverValidationManager, notificationsService
else {
currentForm = args.formCtrl;
}
-
+
//the first thing any form must do is broadcast the formSubmitting event
args.scope.$broadcast("formSubmitting", { scope: args.scope, action: args.action });
@@ -53,10 +53,10 @@ function formHelper(angularHelper, serverValidationManager, notificationsService
//reset the server validations
serverValidationManager.reset();
-
+
return true;
},
-
+
/**
* @ngdoc function
* @name umbraco.services.formHelper#submitForm
@@ -75,21 +75,21 @@ function formHelper(angularHelper, serverValidationManager, notificationsService
if (!args.scope) {
throw "args.scope cannot be null";
}
-
+
args.scope.$broadcast("formSubmitted", { scope: args.scope });
},
showNotifications: function (args) {
- if (!args || !args.notifications) {
- return false;
- }
- if (angular.isArray(args.notifications)) {
- for (var i = 0; i < args.notifications.length; i++) {
- notificationsService.showNotification(args.notifications[i]);
+ if (!args || !args.notifications) {
+ return false;
}
- return true;
- }
- return false;
+ if (angular.isArray(args.notifications)) {
+ for (var i = 0; i < args.notifications.length; i++) {
+ notificationsService.showNotification(args.notifications[i]);
+ }
+ return true;
+ }
+ return false;
},
/**
@@ -104,7 +104,12 @@ function formHelper(angularHelper, serverValidationManager, notificationsService
*
* @param {object} err The error object returned from the http promise
*/
- handleError: function (err) {
+ handleError: function (err) {
+
+ //TODO: Potentially add in the logic to showNotifications like the contentEditingHelper.handleSaveError does so that
+ // non content editors can just use this method instead of contentEditingHelper.handleSaveError which they should not use
+ // and they won't need to manually do it.
+
//When the status is a 400 status with a custom header: X-Status-Reason: Validation failed, we have validation errors.
//Otherwise the error is probably due to invalid data (i.e. someone mucking around with the ids or something).
//Or, some strange server error
@@ -116,7 +121,7 @@ function formHelper(angularHelper, serverValidationManager, notificationsService
this.handleServerValidation(err.data.ModelState);
//execute all server validation events and subscribers
- serverValidationManager.notifyAndClearAllSubscriptions();
+ serverValidationManager.notifyAndClearAllSubscriptions();
}
}
else {
@@ -124,7 +129,7 @@ function formHelper(angularHelper, serverValidationManager, notificationsService
// TODO: All YSOD handling should be done with an interceptor
overlayService.ysod(err);
}
-
+
},
/**
@@ -184,8 +189,7 @@ function formHelper(angularHelper, serverValidationManager, notificationsService
serverValidationManager.addPropertyError(propertyAlias, culture, "", modelState[e][0]);
}
- }
- else {
+ } else {
//Everthing else is just a 'Field'... the field name could contain any level of 'parts' though, for example:
// Groups[0].Properties[2].Alias
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js
index 16c5b38a79..d85a59d836 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js
@@ -143,27 +143,21 @@ function mediaHelper(umbRequestHelper) {
*/
resolveFileFromEntity: function (mediaEntity, thumbnail) {
- if (!angular.isObject(mediaEntity.metaData)) {
+ if (!angular.isObject(mediaEntity.metaData) || !mediaEntity.metaData.MediaPath) {
throw "Cannot resolve the file url from the mediaEntity, it does not contain the required metaData";
}
- var values = _.values(mediaEntity.metaData);
- for (var i = 0; i < values.length; i++) {
- var val = values[i];
- if (angular.isObject(val) && val.PropertyEditorAlias) {
- for (var resolver in _mediaFileResolvers) {
- if (val.PropertyEditorAlias === resolver) {
- //we need to format a property variable that coincides with how the property would be structured
- // if it came from the mediaResource just to keep things slightly easier for the file resolvers.
- var property = { value: val.Value };
-
- return _mediaFileResolvers[resolver](property, mediaEntity, thumbnail);
- }
- }
+ if (thumbnail) {
+ if (this.detectIfImageByExtension(mediaEntity.metaData.MediaPath)) {
+ return this.getThumbnailFromPath(mediaEntity.metaData.MediaPath);
+ }
+ else {
+ return null;
}
}
-
- return "";
+ else {
+ return mediaEntity.metaData.MediaPath;
+ }
},
/**
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
index ba8334d307..e51b7b818e 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
@@ -13,7 +13,7 @@
* Section navigation and search, and maintain their state for the entire application lifetime
*
*/
-function navigationService($routeParams, $location, $q, $timeout, $injector, eventsService, umbModelMapper, treeService, appState) {
+function navigationService($routeParams, $location, $q, $injector, eventsService, umbModelMapper, treeService, appState) {
//the promise that will be resolved when the navigation is ready
var navReadyPromise = $q.defer();
@@ -31,7 +31,8 @@ function navigationService($routeParams, $location, $q, $timeout, $injector, eve
//A list of query strings defined that when changed will not cause a reload of the route
var nonRoutingQueryStrings = ["mculture", "cculture", "lq"];
var retainedQueryStrings = ["mculture"];
-
+ //A list of trees that don't cause a route when creating new items (TODO: eventually all trees should do this!)
+ var nonRoutingTreesOnCreate = ["content", "contentblueprints"];
function setMode(mode) {
switch (mode) {
@@ -115,16 +116,17 @@ function navigationService($routeParams, $location, $q, $timeout, $injector, eve
}
var service = {
-
+
/**
* @ngdoc method
* @name umbraco.services.navigationService#isRouteChangingNavigation
* @methodOf umbraco.services.navigationService
*
* @description
- * Detects if the route param differences will cause a navigation change or if the route param differences are
+ * Detects if the route param differences will cause a navigation/route change or if the route param differences are
* only tracking state changes.
- * This is used for routing operations where reloadOnSearch is false and when detecting form dirty changes when navigating to a different page.
+ * This is used for routing operations where "reloadOnSearch: false" or "reloadOnUrl: false", when detecting form dirty changes when navigating to a different page,
+ * and when we are creating new entities and moving from a route with the ?create=true parameter to an ID based parameter once it's created.
* @param {object} currUrlParams Either a string path or a dictionary of route parameters
* @param {object} nextUrlParams Either a string path or a dictionary of route parameters
*/
@@ -138,6 +140,14 @@ function navigationService($routeParams, $location, $q, $timeout, $injector, eve
nextUrlParams = pathToRouteParts(nextUrlParams);
}
+ //first check if this is a ?create=true url being redirected to it's true url
+ if (currUrlParams.create === "true" && currUrlParams.id && currUrlParams.section && currUrlParams.tree && currUrlParams.method === "edit" &&
+ !nextUrlParams.create && nextUrlParams.id && nextUrlParams.section === currUrlParams.section && nextUrlParams.tree === currUrlParams.tree && nextUrlParams.method === currUrlParams.method &&
+ nonRoutingTreesOnCreate.indexOf(nextUrlParams.tree.toLowerCase()) >= 0) {
+ //this means we're coming from a path like /content/content/edit/1234?create=true to the created path like /content/content/edit/9999
+ return false;
+ }
+
var allowRoute = true;
//The only time that we want to not route is if only any of the nonRoutingQueryStrings have changed/added.
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/overlay.service.js b/src/Umbraco.Web.UI.Client/src/common/services/overlay.service.js
index e853e07092..2165c1b7cb 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/overlay.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/overlay.service.js
@@ -77,4 +77,5 @@
angular.module("umbraco.services").factory("overlayService", overlayService);
+
})();
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/search.service.js b/src/Umbraco.Web.UI.Client/src/common/services/search.service.js
index a2010d20f2..04c431767c 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/search.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/search.service.js
@@ -42,11 +42,7 @@ angular.module('umbraco.services')
throw "args.term is required";
}
- var options = {
- searchFrom: args.searchFrom
- }
-
- return entityResource.search(args.term, "Member", options).then(function (data) {
+ return entityResource.search(args.term, "Member", args.searchFrom).then(function (data) {
_.each(data, function (item) {
searchResultFormatter.configureMemberResult(item);
});
@@ -71,12 +67,7 @@ angular.module('umbraco.services')
throw "args.term is required";
}
- var options = {
- searchFrom: args.searchFrom,
- ignoreUserStartNodes: args.ignoreUserStartNodes
- }
-
- return entityResource.search(args.term, "Document", options, args.canceler).then(function (data) {
+ return entityResource.search(args.term, "Document", args.searchFrom, args.canceler).then(function (data) {
_.each(data, function (item) {
searchResultFormatter.configureContentResult(item);
});
@@ -101,12 +92,7 @@ angular.module('umbraco.services')
throw "args.term is required";
}
- var options = {
- searchFrom: args.searchFrom,
- ignoreUserStartNodes: args.ignoreUserStartNodes
- }
-
- return entityResource.search(args.term, "Media", options).then(function (data) {
+ return entityResource.search(args.term, "Media", args.searchFrom).then(function (data) {
_.each(data, function (item) {
searchResultFormatter.configureMediaResult(item);
});
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/servervalidationmgr.service.js b/src/Umbraco.Web.UI.Client/src/common/services/servervalidationmgr.service.js
index 43022d0e86..b9bfa51122 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/servervalidationmgr.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/servervalidationmgr.service.js
@@ -13,12 +13,15 @@ function serverValidationManager($timeout) {
var callbacks = [];
/** calls the callback specified with the errors specified, used internally */
- function executeCallback(self, errorsForCallback, callback) {
+ function executeCallback(self, errorsForCallback, callback, culture) {
callback.apply(self, [
- false, //pass in a value indicating it is invalid
- errorsForCallback, //pass in the errors for this item
- self.items]); //pass in all errors in total
+ false, // pass in a value indicating it is invalid
+ errorsForCallback, // pass in the errors for this item
+ self.items, // pass in all errors in total
+ culture // pass the culture that we are listing for.
+ ]
+ );
}
function getFieldErrors(self, fieldName) {
@@ -28,7 +31,7 @@ function serverValidationManager($timeout) {
//find errors for this field name
return _.filter(self.items, function (item) {
- return (item.propertyAlias === null && item.culture === null && item.fieldName === fieldName);
+ return (item.propertyAlias === null && item.culture === "invariant" && item.fieldName === fieldName);
});
}
@@ -39,27 +42,50 @@ function serverValidationManager($timeout) {
if (fieldName && !angular.isString(fieldName)) {
throw "fieldName must be a string";
}
+
+ if (!culture) {
+ culture = "invariant";
+ }
//find all errors for this property
- return _.filter(self.items, function (item) {
+ return _.filter(self.items, function (item) {
return (item.propertyAlias === propertyAlias && item.culture === culture && (item.fieldName === fieldName || (fieldName === undefined || fieldName === "")));
});
}
+
+ function getCultureErrors(self, culture) {
+
+ if (!culture) {
+ culture = "invariant";
+ }
+
+ //find all errors for this property
+ return _.filter(self.items, function (item) {
+ return (item.culture === culture);
+ });
+ }
function notifyCallbacks(self) {
for (var cb in callbacks) {
- if (callbacks[cb].propertyAlias === null) {
+ if (callbacks[cb].propertyAlias === null && callbacks[cb].fieldName !== null) {
//its a field error callback
var fieldErrors = getFieldErrors(self, callbacks[cb].fieldName);
if (fieldErrors.length > 0) {
- executeCallback(self, fieldErrors, callbacks[cb].callback);
+ executeCallback(self, fieldErrors, callbacks[cb].callback, callbacks[cb].culture);
}
}
- else {
+ else if (callbacks[cb].propertyAlias != null) {
//its a property error
var propErrors = getPropertyErrors(self, callbacks[cb].propertyAlias, callbacks[cb].culture, callbacks[cb].fieldName);
if (propErrors.length > 0) {
- executeCallback(self, propErrors, callbacks[cb].callback);
+ executeCallback(self, propErrors, callbacks[cb].callback, callbacks[cb].culture);
+ }
+ }
+ else {
+ //its a culture error
+ var cultureErrors = getCultureErrors(self, callbacks[cb].culture);
+ if (cultureErrors.length > 0) {
+ executeCallback(self, cultureErrors, callbacks[cb].callback, callbacks[cb].culture);
}
}
}
@@ -130,11 +156,14 @@ function serverValidationManager($timeout) {
}
var id = String.CreateGuid();
-
+ if (!culture) {
+ culture = "invariant";
+ }
+
if (propertyAlias === null) {
callbacks.push({
propertyAlias: null,
- culture: null,
+ culture: culture,
fieldName: fieldName,
callback: callback,
id: id
@@ -142,12 +171,11 @@ function serverValidationManager($timeout) {
}
else if (propertyAlias !== undefined) {
//normalize culture to null
- if (!culture) {
- culture = null;
- }
+
callbacks.push({
propertyAlias: propertyAlias,
- culture: culture, fieldName: fieldName,
+ culture: culture,
+ fieldName: fieldName,
callback: callback,
id: id
});
@@ -173,21 +201,20 @@ function serverValidationManager($timeout) {
*/
unsubscribe: function (propertyAlias, culture, fieldName) {
+ //normalize culture to null
+ if (!culture) {
+ culture = "invariant";
+ }
+
if (propertyAlias === null) {
//remove all callbacks for the content field
callbacks = _.reject(callbacks, function (item) {
- return item.propertyAlias === null && item.culture === null && item.fieldName === fieldName;
+ return item.propertyAlias === null && item.culture === culture && item.fieldName === fieldName;
});
}
else if (propertyAlias !== undefined) {
-
- //normalize culture to null
- if (!culture) {
- culture = null;
- }
-
//remove all callbacks for the content property
callbacks = _.reject(callbacks, function (item) {
return item.propertyAlias === propertyAlias && item.culture === culture &&
@@ -213,7 +240,7 @@ function serverValidationManager($timeout) {
//normalize culture to null
if (!culture) {
- culture = null;
+ culture = "invariant";
}
var found = _.filter(callbacks, function (item) {
@@ -235,7 +262,24 @@ function serverValidationManager($timeout) {
getFieldCallbacks: function (fieldName) {
var found = _.filter(callbacks, function (item) {
//returns any callback that have been registered directly against the field
- return (item.propertyAlias === null && item.culture === null && item.fieldName === fieldName);
+ return (item.propertyAlias === null && item.culture === "invariant" && item.fieldName === fieldName);
+ });
+ return found;
+ },
+
+ /**
+ * @ngdoc function
+ * @name getCultureCallbacks
+ * @methodOf umbraco.services.serverValidationManager
+ * @function
+ *
+ * @description
+ * Gets all callbacks that has been registered using the subscribe method for the culture.
+ */
+ getCultureCallbacks: function (culture) {
+ var found = _.filter(callbacks, function (item) {
+ //returns any callback that have been registered directly/ONLY against the culture
+ return (item.culture === culture && item.propertyAlias === null && item.fieldName === null);
});
return found;
},
@@ -258,7 +302,7 @@ function serverValidationManager($timeout) {
if (!this.hasFieldError(fieldName)) {
this.items.push({
propertyAlias: null,
- culture: null,
+ culture: "invariant",
fieldName: fieldName,
errorMsg: errorMsg
});
@@ -270,7 +314,7 @@ function serverValidationManager($timeout) {
var cbs = this.getFieldCallbacks(fieldName);
//call each callback for this error
for (var cb in cbs) {
- executeCallback(this, errorsForCallback, cbs[cb].callback);
+ executeCallback(this, errorsForCallback, cbs[cb].callback, null);
}
},
@@ -288,9 +332,9 @@ function serverValidationManager($timeout) {
return;
}
- //normalize culture to null
+ //normalize culture to "invariant"
if (!culture) {
- culture = null;
+ culture = "invariant";
}
//only add the item if it doesn't exist
@@ -309,9 +353,16 @@ function serverValidationManager($timeout) {
var cbs = this.getPropertyCallbacks(propertyAlias, culture, fieldName);
//call each callback for this error
for (var cb in cbs) {
- executeCallback(this, errorsForCallback, cbs[cb].callback);
+ executeCallback(this, errorsForCallback, cbs[cb].callback, culture);
}
- },
+
+ //execute culture specific callbacks here too when a propery error is added
+ var cultureCbs = this.getCultureCallbacks(culture);
+ //call each callback for this error
+ for (var cb in cultureCbs) {
+ executeCallback(this, errorsForCallback, cultureCbs[cb].callback, culture);
+ }
+ },
/**
* @ngdoc function
@@ -330,7 +381,7 @@ function serverValidationManager($timeout) {
//normalize culture to null
if (!culture) {
- culture = null;
+ culture = "invariant";
}
//remove the item
@@ -384,7 +435,7 @@ function serverValidationManager($timeout) {
//normalize culture to null
if (!culture) {
- culture = null;
+ culture = "invariant";
}
var err = _.find(this.items, function (item) {
@@ -406,7 +457,7 @@ function serverValidationManager($timeout) {
getFieldError: function (fieldName) {
var err = _.find(this.items, function (item) {
//return true if the property alias matches and if an empty field name is specified or the field name matches
- return (item.propertyAlias === null && item.culture === null && item.fieldName === fieldName);
+ return (item.propertyAlias === null && item.culture === "invariant" && item.fieldName === fieldName);
});
return err;
},
@@ -424,7 +475,7 @@ function serverValidationManager($timeout) {
//normalize culture to null
if (!culture) {
- culture = null;
+ culture = "invariant";
}
var err = _.find(this.items, function (item) {
@@ -446,11 +497,33 @@ function serverValidationManager($timeout) {
hasFieldError: function (fieldName) {
var err = _.find(this.items, function (item) {
//return true if the property alias matches and if an empty field name is specified or the field name matches
- return (item.propertyAlias === null && item.culture === null && item.fieldName === fieldName);
+ return (item.propertyAlias === null && item.culture === "invariant" && item.fieldName === fieldName);
});
return err ? true : false;
},
+
+ /**
+ * @ngdoc function
+ * @name hasCultureError
+ * @methodOf umbraco.services.serverValidationManager
+ * @function
+ *
+ * @description
+ * Checks if the given culture has an error
+ */
+ hasCultureError: function (culture) {
+
+ //normalize culture to null
+ if (!culture) {
+ culture = "invariant";
+ }
+
+ var err = _.find(this.items, function (item) {
+ return item.culture === culture;
+ });
+ return err ? true : false;
+ },
/** The array of error messages */
items: []
};
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
index 555e276485..f72c447627 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
@@ -422,23 +422,12 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
insertMediaInEditor: function (editor, img) {
if (img) {
- var hasUdi = img.udi ? true : false;
-
var data = {
alt: img.altText || "",
src: (img.url) ? img.url : "nothing.jpg",
- id: '__mcenew'
+ id: '__mcenew',
+ 'data-udi': img.udi
};
-
- if (hasUdi) {
- data["data-udi"] = img.udi;
- } else {
- //Considering these fixed because UDI will now be used and thus
- // we have no need for rel http://issues.umbraco.org/issue/U4-6228, http://issues.umbraco.org/issue/U4-6595
- //TODO: Kill rel attribute
- data["rel"] = img.id;
- data["data-id"] = img.id;
- }
editor.selection.setContent(editor.dom.createHTML('img', data));
@@ -990,7 +979,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
}
}
- if (!href) {
+ if (!href && !target.anchor) {
editor.execCommand('unlink');
return;
}
@@ -1004,6 +993,10 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
return;
}
+ if (!href) {
+ href = "";
+ }
+
// Is email and not //user@domain.com and protocol (e.g. mailto:, sip:) is not specified
if (href.indexOf('@') > 0 && href.indexOf('//') === -1 && href.indexOf(':') === -1) {
// assume it's a mailto link
@@ -1153,25 +1146,11 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
let self = this;
- function getIgnoreUserStartNodes(args) {
- var ignoreUserStartNodes = false;
- // Most property editors have a "config" property with ignoreUserStartNodes on then
- if (args.model.config) {
- ignoreUserStartNodes = Object.toBoolean(args.model.config.ignoreUserStartNodes);
- }
- // EXCEPT for the grid's TinyMCE editor, that one wants to be special and the config is called "configuration" instead
- else if (args.model.configuration) {
- ignoreUserStartNodes = Object.toBoolean(args.model.configuration.ignoreUserStartNodes);
- }
- return ignoreUserStartNodes;
- }
-
//create link picker
self.createLinkPicker(args.editor, function (currentTarget, anchorElement) {
var linkPicker = {
currentTarget: currentTarget,
anchors: editorState.current ? self.getAnchorNames(JSON.stringify(editorState.current.properties)) : [],
- ignoreUserStartNodes: getIgnoreUserStartNodes(args),
submit: function (model) {
self.insertLinkInEditor(args.editor, model.target, anchorElement);
editorService.close();
@@ -1185,25 +1164,13 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
//Create the insert media plugin
self.createMediaPicker(args.editor, function (currentTarget, userData) {
-
- var startNodeId = userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0];
- var startNodeIsVirtual = userData.startMediaIds.length !== 1;
-
- var ignoreUserStartNodes = getIgnoreUserStartNodes(args);
- if (ignoreUserStartNodes) {
- ignoreUserStartNodes = true;
- startNodeId = -1;
- startNodeIsVirtual = true;
- }
-
var mediaPicker = {
currentTarget: currentTarget,
onlyImages: true,
showDetails: true,
disableFolderSelect: true,
- startNodeId: startNodeId,
- startNodeIsVirtual: startNodeIsVirtual,
- ignoreUserStartNodes: ignoreUserStartNodes,
+ startNodeId: userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0],
+ startNodeIsVirtual: userData.startMediaIds.length !== 1,
submit: function (model) {
self.insertMediaInEditor(args.editor, model.selection[0]);
editorService.close();
diff --git a/src/Umbraco.Web.UI.Client/src/init.js b/src/Umbraco.Web.UI.Client/src/init.js
index eaa2fe7b31..e169d78b36 100644
--- a/src/Umbraco.Web.UI.Client/src/init.js
+++ b/src/Umbraco.Web.UI.Client/src/init.js
@@ -1,6 +1,6 @@
/** Executed when the application starts, binds to events and set global state */
-app.run(['userService', '$q', '$log', '$rootScope', '$route', '$location', 'urlHelper', 'navigationService', 'appState', 'editorState', 'fileManager', 'assetsService', 'eventsService', '$cookies', '$templateCache', 'localStorageService', 'tourService', 'dashboardResource',
- function (userService, $q, $log, $rootScope, $route, $location, urlHelper, navigationService, appState, editorState, fileManager, assetsService, eventsService, $cookies, $templateCache, localStorageService, tourService, dashboardResource) {
+app.run(['$rootScope', '$route', '$location', 'urlHelper', 'navigationService', 'appState', 'assetsService', 'eventsService', '$cookies', 'tourService',
+ function ($rootScope, $route, $location, urlHelper, navigationService, appState, assetsService, eventsService, $cookies, tourService) {
//This sets the default jquery ajax headers to include our csrf token, we
// need to user the beforeSend method because our token changes per user/login so
@@ -91,13 +91,6 @@ app.run(['userService', '$q', '$log', '$rootScope', '$route', '$location', 'urlH
$rootScope.locationTitle = "Umbraco - " + $location.$$host;
}
- //reset the editorState on each successful route chage
- editorState.reset();
-
- //reset the file manager on each route change, the file collection is only relavent
- // when working in an editor and submitting data to the server.
- //This ensures that memory remains clear of any files and that the editors don't have to manually clear the files.
- fileManager.clearFiles();
});
/** When the route change is rejected - based on checkAuth - we'll prevent the rejected route from executing including
@@ -122,7 +115,7 @@ app.run(['userService', '$q', '$log', '$rootScope', '$route', '$location', 'urlH
});
//Bind to $routeUpdate which will execute anytime a location changes but the route is not triggered.
- //This is the case when a route uses reloadOnSearch: false which is the case for many or our routes so that we are able to maintain
+ //This is the case when a route uses "reloadOnSearch: false" or "reloadOnUrl: false" which is the case for many or our routes so that we are able to maintain
//global state query strings without force re-loading views.
//We can then detect if it's a location change that should force a route or not programatically.
$rootScope.$on('$routeUpdate', function (event, next) {
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/editor.less b/src/Umbraco.Web.UI.Client/src/less/components/editor.less
index 21d459c598..52dd7ea678 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/editor.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/editor.less
@@ -174,6 +174,8 @@ a.umb-editor-header__close-split-view:hover {
max-width: 50%;
white-space: nowrap;
+ user-select: none;
+
span {
text-overflow: ellipsis;
overflow: hidden;
@@ -189,6 +191,25 @@ a.umb-variant-switcher__toggle {
color: @ui-action-discreet-type-hover;
}
}
+
+ &.--error {
+ &::before {
+ content: '!';
+ position: absolute;
+ top: -8px;
+ right: -10px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 20px;
+ height: 20px;
+ border-radius: 10px;
+ text-align: center;
+ font-weight: bold;
+ background-color: @errorBackground;
+ color: @errorText;
+ }
+ }
}
.umb-variant-switcher__expand {
@@ -205,20 +226,16 @@ a.umb-variant-switcher__toggle {
align-items: center;
border-bottom: 1px solid @gray-9;
position: relative;
- &:hover .umb-variant-switcher__name-wrapper {
-
- }
}
.umb-variant-switcher__item:last-child {
border-bottom: none;
}
-.umb-variant-switcher_item--current {
+.umb-variant-switcher__item.--current {
color: @ui-light-active-type;
}
-.umb-variant-switcher_item--current .umb-variant-switcher__name-wrapper {
- //background-color: @gray-10;
+.umb-variant-switcher__item.--current .umb-variant-switcher__name-wrapper {
border-left: 4px solid @ui-active;
}
@@ -227,7 +244,7 @@ a.umb-variant-switcher__toggle {
outline: none;
}
-.umb-variant-switcher_item--not-allowed:not(.umb-variant-switcher_item--current) .umb-variant-switcher__name-wrapper:hover {
+.umb-variant-switcher__item.--not-allowed:not(.--current) .umb-variant-switcher__name-wrapper:hover {
//background-color: @white !important;
cursor: default;
}
@@ -237,6 +254,29 @@ a.umb-variant-switcher__toggle {
cursor: pointer;
}
+.umb-variant-switcher__item.--error {
+ .umb-variant-switcher__name {
+ color: @red;
+ &::after {
+ content: '!';
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ margin-left: 5px;
+ top: -6px;
+ width: 14px;
+ height: 14px;
+ border-radius: 7px;
+ font-size: 8px;
+ text-align: center;
+ font-weight: bold;
+ background-color: @errorBackground;
+ color: @errorText;
+ }
+ }
+}
+
.umb-variant-switcher__name-wrapper {
font-size: 14px;
flex: 1;
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-logviewer.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-logviewer.less
index f7aa0e4558..7b8845542e 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/umb-logviewer.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-logviewer.less
@@ -20,6 +20,15 @@
.umb-logviewer__sidebar {
flex: 0 0 @sidebarwidth;
+
+ .flatpickr-input {
+ background-color: @white;
+ border: 0;
+ width: 100%;
+ text-align: center;
+ font-size: larger;
+ padding-top: 20px;
+ }
}
@media (max-width: 768px) {
diff --git a/src/Umbraco.Web.UI.Client/src/less/rte.less b/src/Umbraco.Web.UI.Client/src/less/rte.less
index a13dbaeb43..9f537a7931 100644
--- a/src/Umbraco.Web.UI.Client/src/less/rte.less
+++ b/src/Umbraco.Web.UI.Client/src/less/rte.less
@@ -72,3 +72,7 @@
line-height: 20px;
}
}
+
+.mce-fullscreen {
+ position:absolute;
+}
diff --git a/src/Umbraco.Web.UI.Client/src/routes.js b/src/Umbraco.Web.UI.Client/src/routes.js
index e2a2cfe938..556a4d6aef 100644
--- a/src/Umbraco.Web.UI.Client/src/routes.js
+++ b/src/Umbraco.Web.UI.Client/src/routes.js
@@ -228,6 +228,7 @@ app.config(function ($routeProvider) {
},
reloadOnSearch: false,
+ reloadOnUrl: false,
resolve: canRoute(true)
})
.otherwise({ redirectTo: '/login' });
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
index fb93df28f9..6568cfb567 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
@@ -28,11 +28,9 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
searchFromName: null,
showSearch: false,
results: [],
- selectedSearchResults: [],
- ignoreUserStartNodes: dialogOptions.ignoreUserStartNodes
+ selectedSearchResults: []
};
- $scope.customTreeParams = dialogOptions.ignoreUserStartNodes ? "ignoreUserStartNodes=" + dialogOptions.ignoreUserStartNodes : "";
$scope.showTarget = $scope.model.hideTarget !== true;
// this ensures that we only sync the tree once and only when it's ready
@@ -89,11 +87,7 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
});
// get the content properties to build the anchor name list
-
- var options = {};
- options.ignoreUserStartNodes = dialogOptions.ignoreUserStartNodes;
-
- contentResource.getById(id, options).then(function (resp) {
+ contentResource.getById(id).then(function (resp) {
handleContentTarget(resp);
});
}
@@ -143,11 +137,9 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
if (args.node.id < 0) {
$scope.model.target.url = "/";
} else {
- var options = {};
- options.ignoreUserStartNodes = dialogOptions.ignoreUserStartNodes;
-
- contentResource.getById(args.node.id, options).then(function (resp) {
+ contentResource.getById(args.node.id).then(function (resp) {
handleContentTarget(resp);
+
});
}
@@ -170,17 +162,9 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
$scope.switchToMediaPicker = function () {
userService.getCurrentUser().then(function (userData) {
- var startNodeId = userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0];
- var startNodeIsVirtual = userData.startMediaIds.length !== 1;
- if (dialogOptions.ignoreUserStartNodes) {
- startNodeId = -1;
- startNodeIsVirtual = true;
- }
-
var mediaPicker = {
- startNodeId: startNodeId,
- startNodeIsVirtual: startNodeIsVirtual,
- ignoreUserStartNodes: dialogOptions.ignoreUserStartNodes,
+ startNodeId: userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0],
+ startNodeIsVirtual: userData.startMediaIds.length !== 1,
submit: function (model) {
var media = model.selection[0];
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.html
index b7f63cfe22..0bb91d8da6 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.html
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.html
@@ -66,7 +66,6 @@
search-from-id="{{searchInfo.searchFromId}}"
search-from-name="{{searchInfo.searchFromName}}"
show-search="{{searchInfo.showSearch}}"
- ignore-user-start-nodes="{{searchInfo.ignoreUserStartNodes}}"
section="{{section}}">
@@ -83,7 +82,6 @@
section="content"
hideheader="true"
hideoptions="true"
- customtreeparams="{{customTreeParams}}"
api="dialogTreeApi"
on-init="onTreeInit()"
enablelistviewexpand="true"
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
index f37e1156a8..3a0deb812e 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
@@ -1,7 +1,7 @@
//used for the media picker dialog
angular.module("umbraco")
.controller("Umbraco.Editors.MediaPickerController",
- function ($scope, mediaResource, entityResource, mediaHelper, mediaTypeHelper, eventsService, userService, treeService, localStorageService, localizationService, editorService) {
+ function($scope, mediaResource, entityResource, mediaHelper, mediaTypeHelper, eventsService, treeService, localStorageService, localizationService, editorService) {
if (!$scope.model.title) {
localizationService.localizeMany(["defaultdialogs_selectMedia", "general_includeFromsubFolders"])
@@ -20,13 +20,11 @@ angular.module("umbraco")
$scope.showDetails = dialogOptions.showDetails;
$scope.multiPicker = (dialogOptions.multiPicker && dialogOptions.multiPicker !== "0") ? true : false;
$scope.startNodeId = dialogOptions.startNodeId ? dialogOptions.startNodeId : -1;
- $scope.ignoreUserStartNodes = Object.toBoolean(dialogOptions.ignoreUserStartNodes);
$scope.cropSize = dialogOptions.cropSize;
$scope.lastOpenedNode = localStorageService.get("umbLastOpenedMediaNodeId");
$scope.lockedFolder = true;
$scope.allowMediaEdit = dialogOptions.allowMediaEdit ? dialogOptions.allowMediaEdit : false;
- var userStartNodes = [];
var umbracoSettings = Umbraco.Sys.ServerVariables.umbracoSettings;
var allowedUploadFiles = mediaHelper.formatFileTypes(umbracoSettings.allowedUploadFiles);
if ($scope.onlyImages) {
@@ -56,8 +54,7 @@ angular.module("umbraco")
pageSize: 100,
totalItems: 0,
totalPages: 0,
- filter: "",
- ignoreUserStartNodes: $scope.model.ignoreUserStartNodes
+ filter: ''
};
//preload selected item
@@ -67,19 +64,15 @@ angular.module("umbraco")
}
function onInit() {
- userService.getCurrentUser().then(function(userData) {
- userStartNodes = userData.startMediaIds;
-
- if ($scope.startNodeId !== -1) {
- entityResource.getById($scope.startNodeId, "media")
- .then(function(ent) {
- $scope.startNodeId = ent.id;
- run();
- });
- } else {
- run();
- }
- });
+ if ($scope.startNodeId !== -1) {
+ entityResource.getById($scope.startNodeId, "media")
+ .then(function (ent) {
+ $scope.startNodeId = ent.id;
+ run();
+ });
+ } else {
+ run();
+ }
}
function run() {
@@ -150,7 +143,7 @@ angular.module("umbraco")
}
};
- $scope.gotoFolder = function (folder) {
+ $scope.gotoFolder = function(folder) {
if (!$scope.multiPicker) {
deselectAllImages($scope.model.selection);
}
@@ -159,10 +152,8 @@ angular.module("umbraco")
folder = { id: -1, name: "Media", icon: "icon-folder" };
}
- var options = {};
if (folder.id > 0) {
- options.ignoreUserStartNodes = $scope.model.ignoreUserStartNodes;
- entityResource.getAncestors(folder.id, "media", options)
+ entityResource.getAncestors(folder.id, "media")
.then(function(anc) {
$scope.path = _.filter(anc,
function(f) {
@@ -178,26 +169,13 @@ angular.module("umbraco")
$scope.path = [];
}
- $scope.lockedFolder = (folder.id === -1 && $scope.model.startNodeIsVirtual) || hasFolderAccess(folder) === false;
-
+ $scope.lockedFolder = folder.id === -1 && $scope.model.startNodeIsVirtual;
$scope.currentFolder = folder;
localStorageService.set("umbLastOpenedMediaNodeId", folder.id);
- options.ignoreUserStartNodes = $scope.ignoreUserStartNodes;
- return getChildren(folder.id, options);
+ return getChildren(folder.id);
};
- function hasFolderAccess(node) {
- var nodePath = node.path ? node.path.split(',') : [node.id];
-
- for (var i = 0; i < nodePath.length; i++) {
- if (userStartNodes.indexOf(parseInt(nodePath[i])) !== -1)
- return true;
- }
-
- return false;
- }
-
$scope.clickHandler = function(image, event, index) {
if (image.isFolder) {
if ($scope.disableFolderSelect) {
@@ -321,8 +299,7 @@ angular.module("umbraco")
pageSize: 100,
totalItems: 0,
totalPages: 0,
- filter: "",
- ignoreUserStartNodes: $scope.model.ignoreUserStartNodes
+ filter: ''
};
getChildren($scope.currentFolder.id);
}
@@ -390,9 +367,9 @@ angular.module("umbraco")
}
}
- function getChildren(id, options) {
+ function getChildren(id) {
$scope.loading = true;
- return mediaResource.getChildren(id, options)
+ return mediaResource.getChildren(id)
.then(function(data) {
$scope.searchOptions.filter = "";
$scope.images = data.items ? data.items : [];
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js
index 247f694470..915abf62b0 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js
@@ -36,7 +36,6 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController",
selectedSearchResults: []
}
vm.startNodeId = $scope.model.startNodeId;
- vm.ignoreUserStartNodes = $scope.model.ignoreUserStartNodes;
//Used for toggling an empty-state message
//Some trees can have no items (dictionary & forms email templates)
vm.hasItems = true;
@@ -172,9 +171,6 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController",
if (vm.startNodeId) {
queryParams["startNodeId"] = $scope.model.startNodeId;
}
- if (vm.ignoreUserStartNodes) {
- queryParams["ignoreUserStartNodes"] = $scope.model.ignoreUserStartNodes;
- }
if (vm.selectedLanguage && vm.selectedLanguage.id) {
queryParams["culture"] = vm.selectedLanguage.culture;
}
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.html
index acd838f7bf..c592b4ec3b 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.html
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.html
@@ -27,7 +27,7 @@
{{language.name}}
-
+
-
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
index c937360693..d7cac59348 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
@@ -7,12 +7,9 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
var multiPicker = $scope.model.config.multiPicker && $scope.model.config.multiPicker !== '0' ? true : false;
var onlyImages = $scope.model.config.onlyImages && $scope.model.config.onlyImages !== '0' ? true : false;
var disableFolderSelect = $scope.model.config.disableFolderSelect && $scope.model.config.disableFolderSelect !== '0' ? true : false;
- var ignoreUserStartNodes = Object.toBoolean($scope.model.config.ignoreUserStartNodes);
$scope.allowEditMedia = false;
$scope.allowAddMedia = false;
-
-
function setupViewModel() {
$scope.mediaItems = [];
$scope.ids = [];
@@ -108,16 +105,12 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
}
function init() {
+
userService.getCurrentUser().then(function (userData) {
if (!$scope.model.config.startNodeId) {
$scope.model.config.startNodeId = userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0];
$scope.model.config.startNodeIsVirtual = userData.startMediaIds.length !== 1;
}
- if (ignoreUserStartNodes === true) {
- $scope.model.config.startNodeId = -1;
- $scope.model.config.startNodeIsVirtual = true;
- }
-
// only allow users to add and edit media if they have access to the media section
var hasAccessToMedia = userData.allowedSections.indexOf("media") !== -1;
$scope.allowEditMedia = hasAccessToMedia;
@@ -175,7 +168,6 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
var mediaPicker = {
startNodeId: $scope.model.config.startNodeId,
startNodeIsVirtual: $scope.model.config.startNodeIsVirtual,
- ignoreUserStartNodes: ignoreUserStartNodes,
multiPicker: multiPicker,
onlyImages: onlyImages,
disableFolderSelect: disableFolderSelect,
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js
index f20cfd3caa..734b06536d 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js
@@ -68,10 +68,9 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
url: link.url,
target: link.target
} : null;
-
+
var linkPicker = {
currentTarget: target,
- ignoreUserStartNodes: Object.toBoolean($scope.model.config.ignoreUserStartNodes),
submit: function (model) {
if (model.target.url || model.target.anchor) {
// if an anchor exists, check that it is appropriately prefixed
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
index 979baef0f7..d54a17e15a 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
@@ -25,7 +25,6 @@
section: "content",
treeAlias: "content",
multiPicker: false,
- ignoreUserStartNodes: Object.toBoolean($scope.model.config.ignoreUserStartNodes),
idType: $scope.model.config.idType ? $scope.model.config.idType : "int",
submit: function (model) {
select(model.selection[0]);
@@ -48,7 +47,6 @@
section: "content",
treeAlias: "content",
multiPicker: false,
- ignoreUserStartNodes: Object.toBoolean($scope.model.config.ignoreUserStartNodes),
idType: $scope.model.config.idType ? $scope.model.config.idType : "udi",
submit: function (model) {
select(model.selection[0]);
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js
index d1fedf7db6..3ed5f49b92 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js
@@ -20,8 +20,8 @@ angular.module("umbraco")
editorConfig.maxImageSize = tinyMceService.defaultPrevalues().maxImageSize;
}
- var width = parseInt(editorConfig.dimensions.width, 10) || null;
- var height = parseInt(editorConfig.dimensions.height, 10) || null;
+ var width = editorConfig.dimensions ? parseInt(editorConfig.dimensions.width, 10) || null : null;
+ var height = editorConfig.dimensions ? parseInt(editorConfig.dimensions.height, 10) || null : null;
$scope.containerWidth = editorConfig.mode === "distraction-free" ? (width ? width : "auto") : "auto";
$scope.containerHeight = editorConfig.mode === "distraction-free" ? (height ? height : "auto") : "auto";
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.html
index 0d083f95b9..4aa424396d 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.html
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.html
@@ -24,13 +24,6 @@
text="{{css.name}}"/>
-
-
-
-
-
diff --git a/src/Umbraco.Web.UI.Client/src/views/relationtypes/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/relationtypes/edit.controller.js
index 1667a89c35..7bcbe0716e 100644
--- a/src/Umbraco.Web.UI.Client/src/views/relationtypes/edit.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/relationtypes/edit.controller.js
@@ -119,7 +119,6 @@ function RelationTypeEditController($scope, $routeParams, relationTypeResource,
}, function (error) {
contentEditingHelper.handleSaveError({
- redirectOnFailure: false,
err: error
});
diff --git a/src/Umbraco.Web.UI.Client/src/views/scripts/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/scripts/edit.controller.js
index 2ca93fba4c..34702230b8 100644
--- a/src/Umbraco.Web.UI.Client/src/views/scripts/edit.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/scripts/edit.controller.js
@@ -45,10 +45,6 @@
saveMethod: codefileResource.save,
scope: $scope,
content: vm.script,
- // We do not redirect on failure for scripts - this is because it is not possible to actually save the script
- // when server side validation fails - as opposed to content where we are capable of saving the content
- // item if server side validation fails
- redirectOnFailure: false,
rebindCallback: function (orignal, saved) {}
}).then(function (saved) {
diff --git a/src/Umbraco.Web.UI.Client/src/views/stylesheets/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/stylesheets/edit.controller.js
index 541d329e05..75e59605d2 100644
--- a/src/Umbraco.Web.UI.Client/src/views/stylesheets/edit.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/stylesheets/edit.controller.js
@@ -68,10 +68,6 @@
saveMethod: codefileResource.save,
scope: $scope,
content: vm.stylesheet,
- // We do not redirect on failure for style sheets - this is because it is not possible to actually save the style sheet
- // when server side validation fails - as opposed to content where we are capable of saving the content
- // item if server side validation fails
- redirectOnFailure: false,
rebindCallback: function (orignal, saved) {}
}).then(function (saved) {
diff --git a/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js
index d17f556b2f..69b60746c6 100644
--- a/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js
@@ -83,10 +83,6 @@
saveMethod: templateResource.save,
scope: $scope,
content: vm.template,
- // We do not redirect on failure for templates - this is because it is not possible to actually save the template
- // type when server side validation fails - as opposed to content where we are capable of saving the content
- // item if server side validation fails
- redirectOnFailure: false,
rebindCallback: function (orignal, saved) {}
}).then(function (saved) {
diff --git a/src/Umbraco.Web.UI.Client/src/views/users/group.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/group.controller.js
index f37cc95174..d110e5d329 100644
--- a/src/Umbraco.Web.UI.Client/src/views/users/group.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/users/group.controller.js
@@ -81,10 +81,6 @@
saveMethod: userGroupsResource.saveUserGroup,
scope: $scope,
content: vm.userGroup,
- // We do not redirect on failure for users - this is because it is not possible to actually save a user
- // when server side validation fails - as opposed to content where we are capable of saving the content
- // item if server side validation fails
- redirectOnFailure: false,
rebindCallback: function (orignal, saved) { }
}).then(function (saved) {
diff --git a/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js
index 2d9fccc399..4cbd779236 100644
--- a/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js
@@ -136,7 +136,10 @@
//anytime a user is changing another user's password, we are in effect resetting it so we need to set that flag here
if (vm.user.changePassword) {
- vm.user.changePassword.reset = !vm.user.changePassword.oldPassword && !vm.user.isCurrentUser;
+ //NOTE: the check for allowManuallyChangingPassword is due to this legacy user membership provider setting, if that is true, then the current user
+ //can change their own password without entering their current one (this is a legacy setting since that is a security issue but we need to maintain compat).
+ //if allowManuallyChangingPassword=false, then we are using default settings and the user will need to enter their old password to change their own password.
+ vm.user.changePassword.reset = (!vm.user.changePassword.oldPassword && !vm.user.isCurrentUser) || vm.changePasswordModel.config.allowManuallyChangingPassword;
}
vm.page.saveButtonState = "busy";
@@ -169,7 +172,6 @@
}, function (err) {
contentEditingHelper.handleSaveError({
- redirectOnFailure: false,
err: err,
showNotifications: true
});
diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html b/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html
index fdae716b39..031bff0a47 100644
--- a/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html
+++ b/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html
@@ -261,7 +261,8 @@
-
-
+
+ paste
@@ -47,6 +48,7 @@
directionalitytabfocussearchreplace
+ fullscreen
(
controller => controller.PostChangePassword(null))
- },
+ },
{
"entityApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetById(0, UmbracoEntityTypes.Media))
@@ -307,7 +307,7 @@ namespace Umbraco.Web.Editors
},
{
"logViewerApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
- controller => controller.GetNumberOfErrors())
+ controller => controller.GetNumberOfErrors(null, null))
}
}
},
diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs
index de65689353..754d5aca1e 100644
--- a/src/Umbraco.Web/Editors/ContentController.cs
+++ b/src/Umbraco.Web/Editors/ContentController.cs
@@ -576,8 +576,13 @@ namespace Umbraco.Web.Editors
Services.ContentService.SaveBlueprint(contentItem.PersistedContent, Security.CurrentUser.Id);
//we need to reuse the underlying logic so return the result that it wants
return OperationResult.Succeed(new EventMessages());
+ },
+ content =>
+ {
+ var display = MapToDisplay(content);
+ SetupBlueprint(display, content);
+ return display;
});
- SetupBlueprint(contentItemDisplay, contentItemDisplay.PersistedContent);
return contentItemDisplay;
}
@@ -591,11 +596,15 @@ namespace Umbraco.Web.Editors
[OutgoingEditorModelEvent]
public ContentItemDisplay PostSave([ModelBinder(typeof(ContentItemBinder))] ContentItemSave contentItem)
{
- var contentItemDisplay = PostSaveInternal(contentItem, content => Services.ContentService.Save(contentItem.PersistedContent, Security.CurrentUser.Id));
+ var contentItemDisplay = PostSaveInternal(
+ contentItem,
+ content => Services.ContentService.Save(contentItem.PersistedContent, Security.CurrentUser.Id),
+ MapToDisplay);
+
return contentItemDisplay;
}
- private ContentItemDisplay PostSaveInternal(ContentItemSave contentItem, Func saveMethod)
+ private ContentItemDisplay PostSaveInternal(ContentItemSave contentItem, Func saveMethod, Func mapToDisplay)
{
//Recent versions of IE/Edge may send in the full client side file path instead of just the file name.
//To ensure similar behavior across all browsers no matter what they do - we strip the FileName property of all
@@ -626,7 +635,7 @@ namespace Umbraco.Web.Editors
{
//ok, so the absolute mandatory data is invalid and it's new, we cannot actually continue!
// add the model state to the outgoing object and throw a validation message
- var forDisplay = MapToDisplay(contentItem.PersistedContent);
+ var forDisplay = mapToDisplay(contentItem.PersistedContent);
forDisplay.Errors = ModelState.ToErrorDictionary();
throw new HttpResponseException(Request.CreateValidationErrorResponse(forDisplay));
}
@@ -717,11 +726,7 @@ namespace Umbraco.Web.Editors
case ContentSaveAction.PublishNew:
{
var publishStatus = PublishInternal(contentItem, defaultCulture, cultureForInvariantErrors, out wasCancelled, out var successfulCultures);
- //global notifications
- AddMessageForPublishStatus(new[] { publishStatus }, globalNotifications, successfulCultures);
- //variant specific notifications
- foreach (var c in successfulCultures)
- AddMessageForPublishStatus(new[] { publishStatus }, notifications.GetOrCreate(c), successfulCultures);
+ AddPublishStatusNotifications(new[] { publishStatus }, globalNotifications, notifications, successfulCultures);
}
break;
case ContentSaveAction.PublishWithDescendants:
@@ -737,12 +742,7 @@ namespace Umbraco.Web.Editors
}
var publishStatus = PublishBranchInternal(contentItem, false, cultureForInvariantErrors, out wasCancelled, out var successfulCultures).ToList();
-
- //global notifications
- AddMessageForPublishStatus(publishStatus, globalNotifications, successfulCultures);
- //variant specific notifications
- foreach (var c in successfulCultures)
- AddMessageForPublishStatus(publishStatus, notifications.GetOrCreate(c), successfulCultures);
+ AddPublishStatusNotifications(publishStatus, globalNotifications, notifications, successfulCultures);
}
break;
case ContentSaveAction.PublishWithDescendantsForce:
@@ -758,12 +758,7 @@ namespace Umbraco.Web.Editors
}
var publishStatus = PublishBranchInternal(contentItem, true, cultureForInvariantErrors, out wasCancelled, out var successfulCultures).ToList();
-
- //global notifications
- AddMessageForPublishStatus(publishStatus, globalNotifications, successfulCultures);
- //variant specific notifications
- foreach (var c in successfulCultures)
- AddMessageForPublishStatus(publishStatus, notifications.GetOrCreate(c), successfulCultures);
+ AddPublishStatusNotifications(publishStatus, globalNotifications, notifications, successfulCultures);
}
break;
default:
@@ -771,7 +766,7 @@ namespace Umbraco.Web.Editors
}
//get the updated model
- var display = MapToDisplay(contentItem.PersistedContent);
+ var display = mapToDisplay(contentItem.PersistedContent);
//merge the tracked success messages with the outgoing model
display.Notifications.AddRange(globalNotifications.Notifications);
@@ -801,6 +796,15 @@ namespace Umbraco.Web.Editors
return display;
}
+ private void AddPublishStatusNotifications(IReadOnlyCollection publishStatus, SimpleNotificationModel globalNotifications, Dictionary variantNotifications, string[] successfulCultures)
+ {
+ //global notifications
+ AddMessageForPublishStatus(publishStatus, globalNotifications, successfulCultures);
+ //variant specific notifications
+ foreach (var c in successfulCultures ?? Array.Empty())
+ AddMessageForPublishStatus(publishStatus, variantNotifications.GetOrCreate(c), successfulCultures);
+ }
+
///
/// Validates critical data for persistence and updates the ModelState and result accordingly
///
@@ -1143,7 +1147,7 @@ namespace Umbraco.Web.Editors
var publishStatus = Services.ContentService.SaveAndPublishBranch(contentItem.PersistedContent, force, userId: Security.CurrentUser.Id);
// TODO: Deal with multiple cancellations
wasCancelled = publishStatus.Any(x => x.Result == PublishResultType.FailedPublishCancelledByEvent);
- successfulCultures = Array.Empty();
+ successfulCultures = null; //must be null! this implies invariant
return publishStatus;
}
@@ -1215,7 +1219,7 @@ namespace Umbraco.Web.Editors
//its invariant, proceed normally
var publishStatus = Services.ContentService.SaveAndPublish(contentItem.PersistedContent, userId: Security.CurrentUser.Id);
wasCancelled = publishStatus.Result == PublishResultType.FailedPublishCancelledByEvent;
- successfulCultures = Array.Empty();
+ successfulCultures = null; //must be null! this implies invariant
return publishStatus;
}
@@ -2128,7 +2132,7 @@ namespace Umbraco.Web.Editors
{
foreach (var c in successfulCultures)
{
- var names = string.Join(", ", status.Select(x => $"'{x.Content.GetCultureName(c)}'"));
+ var names = string.Join(", ", status.Select(x => $"'{(x.Content.ContentType.VariesByCulture() ? x.Content.GetCultureName(c) : x.Content.Name)}'"));
display.AddWarningNotification(
Services.TextService.Localize("publish"),
Services.TextService.Localize("publish/contentPublishedFailedInvalid",
diff --git a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs
index e62438cc6f..9b8a098e21 100644
--- a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs
+++ b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs
@@ -304,9 +304,12 @@ namespace Umbraco.Web.Editors
//check if the type is trying to allow type 0 below itself - id zero refers to the currently unsaved type
//always filter these 0 types out
var allowItselfAsChild = false;
+ var allowIfselfAsChildSortOrder = -1;
if (contentTypeSave.AllowedContentTypes != null)
{
+ allowIfselfAsChildSortOrder = contentTypeSave.AllowedContentTypes.IndexOf(0);
allowItselfAsChild = contentTypeSave.AllowedContentTypes.Any(x => x == 0);
+
contentTypeSave.AllowedContentTypes = contentTypeSave.AllowedContentTypes.Where(x => x > 0).ToList();
}
@@ -335,10 +338,12 @@ namespace Umbraco.Web.Editors
saveContentType(newCt);
//we need to save it twice to allow itself under itself.
- if (allowItselfAsChild)
+ if (allowItselfAsChild && newCt != null)
{
- //NOTE: This will throw if the composition isn't right... but it shouldn't be at this stage
- newCt.AddContentType(newCt);
+ newCt.AllowedContentTypes =
+ newCt.AllowedContentTypes.Union(
+ new []{ new ContentTypeSort(newCt.Id, allowIfselfAsChildSortOrder) }
+ );
saveContentType(newCt);
}
return newCt;
diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs
index 3ef8a92cdc..dbd17205bb 100644
--- a/src/Umbraco.Web/Editors/EntityController.cs
+++ b/src/Umbraco.Web/Editors/EntityController.cs
@@ -99,25 +99,8 @@ namespace Umbraco.Web.Editors
/// A starting point for the search, generally a node id, but for members this is a member type alias
///
///
- [Obsolete("This method is obsolete, use the overload with ignoreUserStartNodes instead", false)]
[HttpGet]
public IEnumerable Search(string query, UmbracoEntityTypes type, string searchFrom = null)
- {
- return Search(query, type, ignoreUserStartNodes: false, searchFrom);
- }
-
- ///
- /// Searches for results based on the entity type
- ///
- ///
- ///
- ///
- /// A starting point for the search, generally a node id, but for members this is a member type alias
- ///
- /// If set to true, user and group start node permissions will be ignored.
- ///
- [HttpGet]
- public IEnumerable Search(string query, UmbracoEntityTypes type, bool? ignoreUserStartNodes, string searchFrom = null)
{
// TODO: Should we restrict search results based on what app the user has access to?
// - Theoretically you shouldn't be able to see member data if you don't have access to members right?
@@ -127,7 +110,7 @@ namespace Umbraco.Web.Editors
//TODO: This uses the internal UmbracoTreeSearcher, this instead should delgate to the ISearchableTree implementation for the type
- return ExamineSearch(query, type, searchFrom, ignoreUserStartNodes != null && ignoreUserStartNodes.Value);
+ return ExamineSearch(query, type, searchFrom);
}
///
@@ -549,7 +532,6 @@ namespace Umbraco.Web.Editors
}
}
- [Obsolete("This method is obsolete, use the overload with ignoreUserStartNodes instead", false)]
public PagedResult GetPagedDescendants(
int id,
UmbracoEntityTypes type,
@@ -558,20 +540,6 @@ namespace Umbraco.Web.Editors
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
string filter = "")
- {
- return GetPagedDescendants(id, type, pageNumber, pageSize,
- ignoreUserStartNodes: false, orderBy, orderDirection, filter);
- }
-
- public PagedResult GetPagedDescendants(
- int id,
- UmbracoEntityTypes type,
- int pageNumber,
- int pageSize,
- bool ignoreUserStartNodes,
- string orderBy = "SortOrder",
- Direction orderDirection = Direction.Ascending,
- string filter = "")
{
if (pageNumber <= 0)
throw new HttpResponseException(HttpStatusCode.NotFound);
@@ -599,7 +567,7 @@ namespace Umbraco.Web.Editors
break;
}
- entities = aids == null || aids.Contains(Constants.System.Root) || ignoreUserStartNodes
+ entities = aids == null || aids.Contains(Constants.System.Root)
? Services.EntityService.GetPagedDescendants(objectType.Value, pageNumber - 1, pageSize, out totalRecords,
SqlContext.Query().Where(x => x.Name.Contains(filter)),
Ordering.By(orderBy, orderDirection), includeTrashed: false)
@@ -641,15 +609,9 @@ namespace Umbraco.Web.Editors
}
}
- [Obsolete("This method is obsolete, use the overload with ignoreUserStartNodes instead", false)]
- public IEnumerable GetAncestors(int id, UmbracoEntityTypes type, [ModelBinder(typeof(HttpQueryStringModelBinder))] FormDataCollection queryStrings)
+ public IEnumerable GetAncestors(int id, UmbracoEntityTypes type, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormDataCollection queryStrings)
{
- return GetResultForAncestors(id, type, queryStrings, ignoreUserStartNodes: false);
- }
-
- public IEnumerable GetAncestors(int id, UmbracoEntityTypes type, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormDataCollection queryStrings, bool ignoreUserStartNodes)
- {
- return GetResultForAncestors(id, type, queryStrings, ignoreUserStartNodes);
+ return GetResultForAncestors(id, type, queryStrings);
}
///
@@ -658,11 +620,10 @@ namespace Umbraco.Web.Editors
///
///
///
- /// If set to true, user and group start node permissions will be ignored.
///
- private IEnumerable ExamineSearch(string query, UmbracoEntityTypes entityType, string searchFrom = null, bool ignoreUserStartNodes = false)
+ private IEnumerable ExamineSearch(string query, UmbracoEntityTypes entityType, string searchFrom = null)
{
- return _treeSearcher.ExamineSearch(query, entityType, 200, 0, out _, ignoreUserStartNodes, searchFrom);
+ return _treeSearcher.ExamineSearch(query, entityType, 200, 0, out _, searchFrom);
}
private IEnumerable GetResultForChildren(int id, UmbracoEntityTypes entityType)
@@ -688,7 +649,7 @@ namespace Umbraco.Web.Editors
}
}
- private IEnumerable GetResultForAncestors(int id, UmbracoEntityTypes entityType, FormDataCollection queryStrings = null, bool ignoreUserStartNodes = false)
+ private IEnumerable GetResultForAncestors(int id, UmbracoEntityTypes entityType, FormDataCollection queryStrings = null)
{
var objectType = ConvertToObjectType(entityType);
if (objectType.HasValue)
@@ -697,38 +658,35 @@ namespace Umbraco.Web.Editors
var ids = Services.EntityService.Get(id).Path.Split(',').Select(int.Parse).Distinct().ToArray();
- if (ignoreUserStartNodes == false)
+ int[] aids = null;
+ switch (entityType)
{
- int[] aids = null;
- switch (entityType)
- {
- case UmbracoEntityTypes.Document:
- aids = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService);
- break;
- case UmbracoEntityTypes.Media:
- aids = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService);
- break;
- }
+ case UmbracoEntityTypes.Document:
+ aids = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService);
+ break;
+ case UmbracoEntityTypes.Media:
+ aids = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService);
+ break;
+ }
- if (aids != null)
+ if (aids != null)
+ {
+ var lids = new List();
+ var ok = false;
+ foreach (var i in ids)
{
- var lids = new List();
- var ok = false;
- foreach (var i in ids)
+ if (ok)
{
- if (ok)
- {
- lids.Add(i);
- continue;
- }
- if (aids.Contains(i))
- {
- lids.Add(i);
- ok = true;
- }
+ lids.Add(i);
+ continue;
+ }
+ if (aids.Contains(i))
+ {
+ lids.Add(i);
+ ok = true;
}
- ids = lids.ToArray();
}
+ ids = lids.ToArray();
}
var culture = queryStrings?.GetValue("culture");
diff --git a/src/Umbraco.Web/Editors/ImagesController.cs b/src/Umbraco.Web/Editors/ImagesController.cs
index 0eb0f54882..b29c166765 100644
--- a/src/Umbraco.Web/Editors/ImagesController.cs
+++ b/src/Umbraco.Web/Editors/ImagesController.cs
@@ -61,7 +61,7 @@ namespace Umbraco.Web.Editors
//redirect to ImageProcessor thumbnail with rnd generated from last modified time of original media file
var response = Request.CreateResponse(HttpStatusCode.Found);
var imageLastModified = _mediaFileSystem.GetLastModified(imagePath);
- response.Headers.Location = new Uri($"{imagePath}?rnd={imageLastModified:yyyyMMddHHmmss}&upscale=false&width={width}", UriKind.Relative);
+ response.Headers.Location = new Uri($"{imagePath}?rnd={imageLastModified:yyyyMMddHHmmss}&upscale=false&width={width}&animationprocessmode=first&mode=max", UriKind.Relative);
return response;
}
diff --git a/src/Umbraco.Web/Editors/LanguageController.cs b/src/Umbraco.Web/Editors/LanguageController.cs
index 2ee77ca418..650dcea6e9 100644
--- a/src/Umbraco.Web/Editors/LanguageController.cs
+++ b/src/Umbraco.Web/Editors/LanguageController.cs
@@ -46,7 +46,7 @@ namespace Umbraco.Web.Editors
{
var allLanguages = Services.LocalizationService.GetAllLanguages();
- return Mapper.MapEnumerable(allLanguages);
+ return Mapper.Map, IEnumerable>(allLanguages);
}
[HttpGet]
diff --git a/src/Umbraco.Web/Editors/LogViewerController.cs b/src/Umbraco.Web/Editors/LogViewerController.cs
index e5c75926f6..79eb3bb312 100644
--- a/src/Umbraco.Web/Editors/LogViewerController.cs
+++ b/src/Umbraco.Web/Editors/LogViewerController.cs
@@ -22,69 +22,97 @@ namespace Umbraco.Web.Editors
_logViewer = logViewer;
}
- private bool CanViewLogs()
+ private bool CanViewLogs(LogTimePeriod logTimePeriod)
{
//Can the interface deal with Large Files
if (_logViewer.CanHandleLargeLogs)
return true;
//Interface CheckCanOpenLogs
- return _logViewer.CheckCanOpenLogs(startDate: DateTime.Now.AddDays(-1), endDate: DateTime.Now);
+ return _logViewer.CheckCanOpenLogs(logTimePeriod);
}
[HttpGet]
- public bool GetCanViewLogs()
+ public bool GetCanViewLogs([FromUri] DateTime? startDate = null,[FromUri] DateTime? endDate = null)
{
- return CanViewLogs();
+ var logTimePeriod = GetTimePeriod(startDate, endDate);
+ return CanViewLogs(logTimePeriod);
}
[HttpGet]
- public int GetNumberOfErrors()
+ public int GetNumberOfErrors([FromUri] DateTime? startDate = null,[FromUri] DateTime? endDate = null)
{
+ var logTimePeriod = GetTimePeriod(startDate, endDate);
//We will need to stop the request if trying to do this on a 1GB file
- if (CanViewLogs() == false)
+ if (CanViewLogs(logTimePeriod) == false)
{
throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse("Unable to view logs, due to size"));
}
- return _logViewer.GetNumberOfErrors(startDate: DateTime.Now.AddDays(-1), endDate: DateTime.Now);
+ return _logViewer.GetNumberOfErrors(logTimePeriod);
}
[HttpGet]
- public LogLevelCounts GetLogLevelCounts()
+ public LogLevelCounts GetLogLevelCounts([FromUri] DateTime? startDate = null,[FromUri] DateTime? endDate = null)
{
+ var logTimePeriod = GetTimePeriod(startDate, endDate);
//We will need to stop the request if trying to do this on a 1GB file
- if (CanViewLogs() == false)
+ if (CanViewLogs(logTimePeriod) == false)
{
throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse("Unable to view logs, due to size"));
}
- return _logViewer.GetLogLevelCounts(startDate: DateTime.Now.AddDays(-1), endDate: DateTime.Now);
+ return _logViewer.GetLogLevelCounts(logTimePeriod);
}
[HttpGet]
- public IEnumerable GetMessageTemplates()
+ public IEnumerable GetMessageTemplates([FromUri] DateTime? startDate = null,[FromUri] DateTime? endDate = null)
{
+ var logTimePeriod = GetTimePeriod(startDate, endDate);
//We will need to stop the request if trying to do this on a 1GB file
- if (CanViewLogs() == false)
+ if (CanViewLogs(logTimePeriod) == false)
{
throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse("Unable to view logs, due to size"));
}
- return _logViewer.GetMessageTemplates(startDate: DateTime.Now.AddDays(-1), endDate: DateTime.Now);
+ return _logViewer.GetMessageTemplates(logTimePeriod);
}
[HttpGet]
- public PagedResult GetLogs(string orderDirection = "Descending", int pageNumber = 1, string filterExpression = null, [FromUri]string[] logLevels = null)
+ public PagedResult GetLogs(string orderDirection = "Descending", int pageNumber = 1, string filterExpression = null, [FromUri]string[] logLevels = null, [FromUri] DateTime? startDate = null,[FromUri] DateTime? endDate = null)
{
+ var logTimePeriod = GetTimePeriod(startDate, endDate);
+
//We will need to stop the request if trying to do this on a 1GB file
- if (CanViewLogs() == false)
+ if (CanViewLogs(logTimePeriod) == false)
{
throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse("Unable to view logs, due to size"));
}
var direction = orderDirection == "Descending" ? Direction.Descending : Direction.Ascending;
- return _logViewer.GetLogs(startDate: DateTime.Now.AddDays(-1), endDate: DateTime.Now, filterExpression: filterExpression, pageNumber: pageNumber, orderDirection: direction, logLevels: logLevels);
+
+
+
+ return _logViewer.GetLogs(logTimePeriod, filterExpression: filterExpression, pageNumber: pageNumber, orderDirection: direction, logLevels: logLevels);
+ }
+
+ private static LogTimePeriod GetTimePeriod(DateTime? startDate, DateTime? endDate)
+ {
+ if (startDate == null || endDate == null)
+ {
+ var now = DateTime.Now;
+ if (startDate == null)
+ {
+ startDate = now.AddDays(-1);
+ }
+
+ if (endDate == null)
+ {
+ endDate = now;
+ }
+ }
+
+ return new LogTimePeriod(startDate.Value, endDate.Value);
}
[HttpGet]
diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs
index 1097646830..a673f06e1d 100644
--- a/src/Umbraco.Web/Editors/MediaController.cs
+++ b/src/Umbraco.Web/Editors/MediaController.cs
@@ -246,7 +246,6 @@ namespace Umbraco.Web.Editors
///
[FilterAllowedOutgoingMedia(typeof(IEnumerable>), "Items")]
public PagedResult> GetChildren(int id,
- bool ignoreUserStartNodes,
int pageNumber = 0,
int pageSize = 0,
string orderBy = "SortOrder",
@@ -256,7 +255,7 @@ namespace Umbraco.Web.Editors
{
//if a request is made for the root node data but the user's start node is not the default, then
// we need to return their start nodes
- if (id == Constants.System.Root && UserStartNodes.Length > 0 && (UserStartNodes.Contains(Constants.System.Root) == false && ignoreUserStartNodes == false))
+ if (id == Constants.System.Root && UserStartNodes.Length > 0 && UserStartNodes.Contains(Constants.System.Root) == false)
{
if (pageNumber > 0)
return new PagedResult>(0, 0, 0);
@@ -312,7 +311,6 @@ namespace Umbraco.Web.Editors
}
///
- /// This method is obsolete, use the overload with ignoreUserStartNodes instead
/// Returns the child media objects - using the entity GUID id
///
///
@@ -323,34 +321,8 @@ namespace Umbraco.Web.Editors
///
///
///
- [Obsolete("This method is obsolete, use the overload with ignoreUserStartNodes instead", false)]
[FilterAllowedOutgoingMedia(typeof(IEnumerable>), "Items")]
public PagedResult> GetChildren(Guid id,
- int pageNumber = 0,
- int pageSize = 0,
- string orderBy = "SortOrder",
- Direction orderDirection = Direction.Ascending,
- bool orderBySystemField = true,
- string filter = "")
- {
- return GetChildren(id, ignoreUserStartNodes: false, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
- }
-
- ///
- /// Returns the child media objects - using the entity GUID id
- ///
- ///
- /// /// If set to true, user and group start node permissions will be ignored.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- [FilterAllowedOutgoingMedia(typeof(IEnumerable>), "Items")]
- public PagedResult> GetChildren(Guid id,
- bool ignoreUserStartNodes,
int pageNumber = 0,
int pageSize = 0,
string orderBy = "SortOrder",
@@ -361,13 +333,12 @@ namespace Umbraco.Web.Editors
var entity = Services.EntityService.Get(id);
if (entity != null)
{
- return GetChildren(entity.Id, ignoreUserStartNodes, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
+ return GetChildren(entity.Id, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
///
- /// This method is obsolete, use the overload with ignoreUserStartNodes instead
/// Returns the child media objects - using the entity UDI id
///
///
@@ -378,7 +349,6 @@ namespace Umbraco.Web.Editors
///
///
///
- [Obsolete("This method is obsolete, use the overload with ignoreUserStartNodes instead", false)]
[FilterAllowedOutgoingMedia(typeof(IEnumerable>), "Items")]
public PagedResult> GetChildren(Udi id,
int pageNumber = 0,
@@ -387,31 +357,6 @@ namespace Umbraco.Web.Editors
Direction orderDirection = Direction.Ascending,
bool orderBySystemField = true,
string filter = "")
- {
- return GetChildren(id, ignoreUserStartNodes: false, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
- }
-
- ///
- /// Returns the child media objects - using the entity UDI id
- ///
- ///
- /// If set to true, user and group start node permissions will be ignored.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- [FilterAllowedOutgoingMedia(typeof(IEnumerable>), "Items")]
- public PagedResult> GetChildren(Udi id,
- bool ignoreUserStartNodes,
- int pageNumber = 0,
- int pageSize = 0,
- string orderBy = "SortOrder",
- Direction orderDirection = Direction.Ascending,
- bool orderBySystemField = true,
- string filter = "")
{
var guidUdi = id as GuidUdi;
if (guidUdi != null)
@@ -419,7 +364,7 @@ namespace Umbraco.Web.Editors
var entity = Services.EntityService.Get(guidUdi.Guid);
if (entity != null)
{
- return GetChildren(entity.Id, ignoreUserStartNodes, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
+ return GetChildren(entity.Id, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
}
}
diff --git a/src/Umbraco.Web/Editors/PasswordChanger.cs b/src/Umbraco.Web/Editors/PasswordChanger.cs
index e124f3a9a4..2698a68b40 100644
--- a/src/Umbraco.Web/Editors/PasswordChanger.cs
+++ b/src/Umbraco.Web/Editors/PasswordChanger.cs
@@ -151,6 +151,8 @@ namespace Umbraco.Web.Editors
///
public Attempt ChangePasswordWithMembershipProvider(string username, ChangingPasswordModel passwordModel, MembershipProvider membershipProvider)
{
+ var umbracoBaseProvider = membershipProvider as MembershipProviderBase;
+
// YES! It is completely insane how many options you have to take into account based on the membership provider. yikes!
if (passwordModel == null) throw new ArgumentNullException(nameof(passwordModel));
@@ -179,7 +181,7 @@ namespace Umbraco.Web.Editors
//this is only possible when using a membership provider if the membership provider supports AllowManuallyChangingPassword
if (passwordModel.NewPassword.IsNullOrWhiteSpace() == false)
{
- if (membershipProvider is MembershipProviderBase umbracoBaseProvider && umbracoBaseProvider.AllowManuallyChangingPassword)
+ if (umbracoBaseProvider !=null && umbracoBaseProvider.AllowManuallyChangingPassword)
{
//this provider allows manually changing the password without the old password, so we can just do it
try
diff --git a/src/Umbraco.Web/Editors/UserGroupsController.cs b/src/Umbraco.Web/Editors/UserGroupsController.cs
index e79cfd625c..1b64722735 100644
--- a/src/Umbraco.Web/Editors/UserGroupsController.cs
+++ b/src/Umbraco.Web/Editors/UserGroupsController.cs
@@ -50,13 +50,8 @@ namespace Umbraco.Web.Editors
if (isAuthorized == false)
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized, isAuthorized.Result));
- //current user needs to be added to a new group if not an admin (possibly only if no other users are added?) to avoid a 401
- if(!Security.CurrentUser.IsAdmin() && (userGroupSave.Id == null || Convert.ToInt32(userGroupSave.Id) >= 0)/* && !userGroupSave.Users.Any() */)
- {
- var userIds = userGroupSave.Users.ToList();
- userIds.Add(Security.CurrentUser.Id);
- userGroupSave.Users = userIds;
- }
+ //need to ensure current user is in a group if not an admin to avoid a 401
+ EnsureNonAdminUserIsInSavedUserGroup(userGroupSave);
//save the group
Services.UserService.Save(userGroupSave.PersistedUserGroup, userGroupSave.Users.ToArray());
@@ -87,6 +82,23 @@ namespace Umbraco.Web.Editors
return display;
}
+ private void EnsureNonAdminUserIsInSavedUserGroup(UserGroupSave userGroupSave)
+ {
+ if (Security.CurrentUser.IsAdmin())
+ {
+ return;
+ }
+
+ var userIds = userGroupSave.Users.ToList();
+ if (userIds.Contains(Security.CurrentUser.Id))
+ {
+ return;
+ }
+
+ userIds.Add(Security.CurrentUser.Id);
+ userGroupSave.Users = userIds;
+ }
+
///
/// Returns the scaffold for creating a new user group
///
diff --git a/src/Umbraco.Web/ModelStateExtensions.cs b/src/Umbraco.Web/ModelStateExtensions.cs
index 3bbcdfb0ac..706ebf2825 100644
--- a/src/Umbraco.Web/ModelStateExtensions.cs
+++ b/src/Umbraco.Web/ModelStateExtensions.cs
@@ -148,11 +148,33 @@ namespace Umbraco.Web
var delimitedParts = string.Join(".", parts);
foreach (var memberName in result.MemberNames)
{
- modelState.AddModelError($"{delimitedParts}.{memberName}", result.ErrorMessage);
+ modelState.TryAddModelError($"{delimitedParts}.{memberName}", result.ErrorMessage);
withNames = true;
}
if (!withNames)
- modelState.AddModelError($"{delimitedParts}", result.ErrorMessage);
+ {
+ modelState.TryAddModelError($"{delimitedParts}", result.ErrorMessage);
+ }
+
+ }
+
+ ///
+ /// Will add an error to model state for a key if that key and error don't already exist
+ ///
+ ///
+ ///
+ ///
+ ///
+ private static bool TryAddModelError(this System.Web.Http.ModelBinding.ModelStateDictionary modelState, string key, string errorMsg)
+ {
+ if (modelState.TryGetValue(key, out var errs))
+ {
+ foreach(var e in errs.Errors)
+ if (e.ErrorMessage == errorMsg) return false; //if this same error message exists for the same key, just exit
+ }
+
+ modelState.AddModelError(key, errorMsg);
+ return true;
}
public static IDictionary ToErrorDictionary(this System.Web.Http.ModelBinding.ModelStateDictionary modelState)
diff --git a/src/Umbraco.Web/Models/ContentEditing/MessagesExtensions.cs b/src/Umbraco.Web/Models/ContentEditing/MessagesExtensions.cs
index 3a8496ac3f..1f526a50f3 100644
--- a/src/Umbraco.Web/Models/ContentEditing/MessagesExtensions.cs
+++ b/src/Umbraco.Web/Models/ContentEditing/MessagesExtensions.cs
@@ -1,10 +1,15 @@
+using System.Linq;
+using Umbraco.Core;
+
namespace Umbraco.Web.Models.ContentEditing
{
public static class MessagesExtensions
{
public static void AddNotification(this INotificationModel model, string header, string msg, NotificationStyle type)
{
+ if (model.Exists(header, msg, type)) return;
+
model.Notifications.Add(new Notification()
{
Header = header,
@@ -15,6 +20,8 @@ namespace Umbraco.Web.Models.ContentEditing
public static void AddSuccessNotification(this INotificationModel model, string header, string msg)
{
+ if (model.Exists(header, msg, NotificationStyle.Success)) return;
+
model.Notifications.Add(new Notification()
{
Header = header,
@@ -25,6 +32,8 @@ namespace Umbraco.Web.Models.ContentEditing
public static void AddErrorNotification(this INotificationModel model, string header, string msg)
{
+ if (model.Exists(header, msg, NotificationStyle.Error)) return;
+
model.Notifications.Add(new Notification()
{
Header = header,
@@ -35,6 +44,8 @@ namespace Umbraco.Web.Models.ContentEditing
public static void AddWarningNotification(this INotificationModel model, string header, string msg)
{
+ if (model.Exists(header, msg, NotificationStyle.Warning)) return;
+
model.Notifications.Add(new Notification()
{
Header = header,
@@ -45,6 +56,8 @@ namespace Umbraco.Web.Models.ContentEditing
public static void AddInfoNotification(this INotificationModel model, string header, string msg)
{
+ if (model.Exists(header, msg, NotificationStyle.Info)) return;
+
model.Notifications.Add(new Notification()
{
Header = header,
@@ -52,5 +65,7 @@ namespace Umbraco.Web.Models.ContentEditing
NotificationType = NotificationStyle.Info
});
}
+
+ private static bool Exists(this INotificationModel model, string header, string message, NotificationStyle notificationType) => model.Notifications.Any(x => x.Header.InvariantEquals(header) && x.Message.InvariantEquals(message) && x.NotificationType == notificationType);
}
}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentVariantMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentVariantMapper.cs
index 560d398a2c..c279ae2c70 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentVariantMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentVariantMapper.cs
@@ -59,7 +59,7 @@ namespace Umbraco.Web.Models.Mapping
variants.Remove(defaultLang);
//Sort the remaining languages a-z
- variants = variants.OrderBy(x => x.Name).ToList();
+ variants = variants.OrderBy(x => x.Language.Name).ToList();
//Insert the default language as the first item
variants.Insert(0, defaultLang);
diff --git a/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs
index 94698f84bd..2598523bd5 100644
--- a/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs
+++ b/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs
@@ -45,6 +45,12 @@ namespace Umbraco.Web.Models.Mapping
if (source.NodeObjectType == Constants.ObjectTypes.Member && target.Icon.IsNullOrWhiteSpace())
target.Icon = "icon-user";
+ if (source.NodeObjectType == Constants.ObjectTypes.Media && source is IContentEntitySlim contentSlim)
+ source.AdditionalData["ContentTypeAlias"] = contentSlim.ContentTypeAlias;
+
+ if (source.NodeObjectType == Constants.ObjectTypes.Media && source is IMediaEntitySlim mediaSlim)
+ source.AdditionalData["MediaPath"] = mediaSlim.MediaPath;
+
// NOTE: we're mapping the objects in AdditionalData by object reference here.
// it works fine for now, but it's something to keep in mind in the future
foreach(var kvp in source.AdditionalData)
diff --git a/src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs b/src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs
index 5653e3fe03..7879e2b42b 100644
--- a/src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs
+++ b/src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs
@@ -10,8 +10,5 @@ namespace Umbraco.Web.PropertyEditors
[ConfigurationField("startNodeId", "Start node", "treepicker")] // + config in configuration editor ctor
public Udi StartNodeId { get; set; }
-
- [ConfigurationField("ignoreUserStartNodes", "Ignore user start nodes", "boolean", Description = "Selecting this option allows a user to choose nodes that they normally don't have access to.")]
- public bool IgnoreUserStartNodes { get; set; }
}
}
diff --git a/src/Umbraco.Web/PropertyEditors/GridConfiguration.cs b/src/Umbraco.Web/PropertyEditors/GridConfiguration.cs
index 136ab88204..e2b46b360d 100644
--- a/src/Umbraco.Web/PropertyEditors/GridConfiguration.cs
+++ b/src/Umbraco.Web/PropertyEditors/GridConfiguration.cs
@@ -15,8 +15,5 @@ namespace Umbraco.Web.PropertyEditors
// TODO: Make these strongly typed, for now this works though
[ConfigurationField("rte", "Rich text editor", "views/propertyeditors/rte/rte.prevalues.html", Description = "Rich text editor configuration")]
public JObject Rte { get; set; }
-
- [ConfigurationField("ignoreUserStartNodes", "Ignore user start nodes", "boolean", Description = "Selecting this option allows a user to choose nodes that they normally don't have access to. Note: this applies to all editors in this grid editor except for the rich text editor, which has it's own option for that.")]
- public bool IgnoreUserStartNodes { get; set; }
}
}
diff --git a/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs b/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs
index fa430e103b..4844e2f822 100644
--- a/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs
+++ b/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs
@@ -19,8 +19,5 @@ namespace Umbraco.Web.PropertyEditors
[ConfigurationField("startNodeId", "Start node", "mediapicker")]
public Udi StartNodeId { get; set; }
-
- [ConfigurationField("ignoreUserStartNodes", "Ignore user start nodes", "boolean", Description = "Selecting this option allows a user to choose nodes that they normally don't have access to.")]
- public bool IgnoreUserStartNodes { get; set; }
}
}
diff --git a/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfiguration.cs b/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfiguration.cs
index a0a2467b1c..b6333c3140 100644
--- a/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfiguration.cs
+++ b/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfiguration.cs
@@ -22,8 +22,5 @@ namespace Umbraco.Web.PropertyEditors
[ConfigurationField("showOpenButton", "Show open button (this feature is in preview!)", "boolean", Description = "Opens the node in a dialog")]
public bool ShowOpen { get; set; }
-
- [ConfigurationField("ignoreUserStartNodes", "Ignore user start nodes", "boolean", Description = "Selecting this option allows a user to choose nodes that they normally don't have access to.")]
- public bool IgnoreUserStartNodes { get; set; }
}
}
diff --git a/src/Umbraco.Web/PropertyEditors/MultiUrlPickerConfiguration.cs b/src/Umbraco.Web/PropertyEditors/MultiUrlPickerConfiguration.cs
index ec9439ceea..515512eff8 100644
--- a/src/Umbraco.Web/PropertyEditors/MultiUrlPickerConfiguration.cs
+++ b/src/Umbraco.Web/PropertyEditors/MultiUrlPickerConfiguration.cs
@@ -9,8 +9,5 @@ namespace Umbraco.Web.PropertyEditors
[ConfigurationField("maxNumber", "Maximum number of items", "number")]
public int MaxNumber { get; set; }
-
- [ConfigurationField("ignoreUserStartNodes", "Ignore user start nodes", "boolean", Description = "Selecting this option allows a user to choose nodes that they normally don't have access to.")]
- public bool IgnoreUserStartNodes { get; set; }
}
}
diff --git a/src/Umbraco.Web/PropertyEditors/RichTextConfiguration.cs b/src/Umbraco.Web/PropertyEditors/RichTextConfiguration.cs
index d99c2b17e0..13bf269bcd 100644
--- a/src/Umbraco.Web/PropertyEditors/RichTextConfiguration.cs
+++ b/src/Umbraco.Web/PropertyEditors/RichTextConfiguration.cs
@@ -14,8 +14,5 @@ namespace Umbraco.Web.PropertyEditors
[ConfigurationField("hideLabel", "Hide Label", "boolean")]
public bool HideLabel { get; set; }
-
- [ConfigurationField("ignoreUserStartNodes", "Ignore user start nodes", "boolean", Description = "Selecting this option allows a user to choose nodes that they normally don't have access to.")]
- public bool IgnoreUserStartNodes { get; set; }
}
}
diff --git a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs
index c05a983346..297f9b7fb8 100644
--- a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs
@@ -90,7 +90,8 @@ namespace Umbraco.Web.PropertyEditors
if (editorValue.Value == null)
return null;
- var parsed = MacroTagParser.FormatRichTextContentForPersistence(editorValue.Value.ToString());
+ var editorValueWithMediaUrlsRemoved = TemplateUtilities.RemoveMediaUrlsFromTextString(editorValue.Value.ToString());
+ var parsed = MacroTagParser.FormatRichTextContentForPersistence(editorValueWithMediaUrlsRemoved);
return parsed;
}
}
diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs
index fbbf058c49..fa14bd8488 100644
--- a/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs
+++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs
@@ -89,32 +89,35 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
// Find all images with rel attribute
var imgNodes = doc.DocumentNode.SelectNodes("//img[@rel]");
+ var modified = false;
if (imgNodes != null)
{
- var modified = false;
-
foreach (var img in imgNodes)
{
- var firstOrDefault = img.Attributes.FirstOrDefault(x => x.Name == "rel");
- if (firstOrDefault != null)
+ var nodeId = img.GetAttributeValue("rel", string.Empty);
+ if (int.TryParse(nodeId, out _))
{
- var rel = firstOrDefault.Value;
-
- // Check that the rel attribute is a integer before removing
- int nodeId;
- if (int.TryParse(rel, out nodeId))
- {
- img.Attributes.Remove("rel");
- modified = true;
- }
+ img.Attributes.Remove("rel");
+ modified = true;
}
}
+ }
- if (modified)
+ // Find all a and img tags with a data-udi attribute
+ var dataUdiNodes = doc.DocumentNode.SelectNodes("(//a|//img)[@data-udi]");
+ if (dataUdiNodes != null)
+ {
+ foreach (var node in dataUdiNodes)
{
- return doc.DocumentNode.OuterHtml;
+ node.Attributes.Remove("data-udi");
+ modified = true;
}
}
+
+ if (modified)
+ {
+ return doc.DocumentNode.OuterHtml;
+ }
}
return sourceString;
diff --git a/src/Umbraco.Web/Routing/IContentFinder.cs b/src/Umbraco.Web/Routing/IContentFinder.cs
index fe5699ac7b..2e388c4814 100644
--- a/src/Umbraco.Web/Routing/IContentFinder.cs
+++ b/src/Umbraco.Web/Routing/IContentFinder.cs
@@ -8,9 +8,9 @@ namespace Umbraco.Web.Routing
///
/// Tries to find and assign an Umbraco document to a PublishedRequest.
///
- /// The PublishedRequest.
+ /// The PublishedRequest.
/// A value indicating whether an Umbraco document was found and assigned.
/// Optionally, can also assign the template or anything else on the document request, although that is not required.
- bool TryFindContent(PublishedRequest frequest);
+ bool TryFindContent(PublishedRequest request);
}
}
diff --git a/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs b/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs
index 7fb51a61eb..43db9ff0ba 100644
--- a/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs
+++ b/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs
@@ -39,7 +39,6 @@ namespace Umbraco.Web.Search
}
///
- /// This method is obsolete, use the overload with ignoreUserStartNodes instead
/// Searches for results based on the entity type
///
///
@@ -51,39 +50,11 @@ namespace Umbraco.Web.Search
///
///
///
- [Obsolete("This method is obsolete, use the overload with ignoreUserStartNodes instead", false)]
public IEnumerable ExamineSearch(
string query,
UmbracoEntityTypes entityType,
int pageSize,
- long pageIndex,
- out long totalFound,
- string searchFrom = null)
- {
- return ExamineSearch(query, entityType, pageSize, pageIndex, out totalFound, ignoreUserStartNodes: false, searchFrom);
- }
-
- ///
- /// Searches for results based on the entity type
- ///
- ///
- ///
- ///
- ///
- /// A starting point for the search, generally a node id, but for members this is a member type alias
- ///
- ///
- ///
- /// If set to true, user and group start node permissions will be ignored.
- ///
- public IEnumerable ExamineSearch(
- string query,
- UmbracoEntityTypes entityType,
- int pageSize,
- long pageIndex,
- out long totalFound,
- bool ignoreUserStartNodes,
- string searchFrom = null)
+ long pageIndex, out long totalFound, string searchFrom = null)
{
var sb = new StringBuilder();
@@ -114,12 +85,12 @@ namespace Umbraco.Web.Search
case UmbracoEntityTypes.Media:
type = "media";
var allMediaStartNodes = _umbracoContext.Security.CurrentUser.CalculateMediaStartNodeIds(_entityService);
- AppendPath(sb, UmbracoObjectTypes.Media, allMediaStartNodes, searchFrom, ignoreUserStartNodes, _entityService);
+ AppendPath(sb, UmbracoObjectTypes.Media, allMediaStartNodes, searchFrom, _entityService);
break;
case UmbracoEntityTypes.Document:
type = "content";
var allContentStartNodes = _umbracoContext.Security.CurrentUser.CalculateContentStartNodeIds(_entityService);
- AppendPath(sb, UmbracoObjectTypes.Document, allContentStartNodes, searchFrom, ignoreUserStartNodes, _entityService);
+ AppendPath(sb, UmbracoObjectTypes.Document, allContentStartNodes, searchFrom, _entityService);
break;
default:
throw new NotSupportedException("The " + typeof(UmbracoTreeSearcher) + " currently does not support searching against object type " + entityType);
@@ -317,7 +288,7 @@ namespace Umbraco.Web.Search
}
}
- private void AppendPath(StringBuilder sb, UmbracoObjectTypes objectType, int[] startNodeIds, string searchFrom, bool ignoreUserStartNodes, IEntityService entityService)
+ private void AppendPath(StringBuilder sb, UmbracoObjectTypes objectType, int[] startNodeIds, string searchFrom, IEntityService entityService)
{
if (sb == null) throw new ArgumentNullException(nameof(sb));
if (entityService == null) throw new ArgumentNullException(nameof(entityService));
@@ -340,7 +311,7 @@ namespace Umbraco.Web.Search
// make sure we don't find anything
sb.Append("+__Path:none ");
}
- else if (startNodeIds.Contains(-1) == false && ignoreUserStartNodes == false) // -1 = no restriction
+ else if (startNodeIds.Contains(-1) == false) // -1 = no restriction
{
var entityPaths = entityService.GetAllPaths(objectType, startNodeIds);
diff --git a/src/Umbraco.Web/Templates/TemplateUtilities.cs b/src/Umbraco.Web/Templates/TemplateUtilities.cs
index 98aacffe42..8e6e1dcfd0 100644
--- a/src/Umbraco.Web/Templates/TemplateUtilities.cs
+++ b/src/Umbraco.Web/Templates/TemplateUtilities.cs
@@ -157,9 +157,8 @@ namespace Umbraco.Web.Templates
// - 3 = anything after group 2 and before the data-udi attribute value begins
// - 4 = the data-udi attribute value
// - 5 = anything after group 4 until the image tag is closed
- var src = match.Groups[2].Value;
var udi = match.Groups[4].Value;
- if(src.IsNullOrWhiteSpace() || udi.IsNullOrWhiteSpace() || GuidUdi.TryParse(udi, out var guidUdi) == false)
+ if(udi.IsNullOrWhiteSpace() || GuidUdi.TryParse(udi, out var guidUdi) == false)
{
return match.Value;
}
@@ -175,5 +174,14 @@ namespace Umbraco.Web.Templates
return $"{match.Groups[1].Value}{url}{match.Groups[3].Value}{udi}{match.Groups[5].Value}";
});
}
+
+ ///
+ /// Removes media urls from <img> tags where a data-udi attribute is present
+ ///
+ ///
+ ///
+ internal static string RemoveMediaUrlsFromTextString(string text)
+ // see comment in ResolveMediaFromTextString for group reference
+ => ResolveImgPattern.Replace(text, "$1$3$4$5");
}
}
diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs
index 748c97c522..9e481fc4c9 100644
--- a/src/Umbraco.Web/Trees/ContentTreeController.cs
+++ b/src/Umbraco.Web/Trees/ContentTreeController.cs
@@ -201,9 +201,6 @@ namespace Umbraco.Web.Trees
return HasPathAccess(entity, queryStrings);
}
- internal override IEnumerable GetChildrenFromEntityService(int entityId)
- => Services.EntityService.GetChildren(entityId, UmbracoObjectType).ToList();
-
protected override IEnumerable GetChildEntities(string id, FormDataCollection queryStrings)
{
var result = base.GetChildEntities(id, queryStrings);
diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
index d01e9fffb4..1b8f3b1434 100644
--- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
+++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
@@ -69,7 +69,7 @@ namespace Umbraco.Web.Trees
{
var node = base.CreateRootNode(queryStrings);
- if (IsDialog(queryStrings) && UserStartNodes.Contains(Constants.System.Root) == false && IgnoreUserStartNodes(queryStrings) == false)
+ if (IsDialog(queryStrings) && UserStartNodes.Contains(Constants.System.Root) == false)
{
node.AdditionalData["noAccess"] = true;
}
@@ -90,11 +90,11 @@ namespace Umbraco.Web.Trees
internal TreeNode GetSingleTreeNodeWithAccessCheck(IEntitySlim e, string parentId, FormDataCollection queryStrings)
{
var entityIsAncestorOfStartNodes = Security.CurrentUser.IsInBranchOfStartNode(e, Services.EntityService, RecycleBinId, out var hasPathAccess);
- if (IgnoreUserStartNodes(queryStrings) == false && entityIsAncestorOfStartNodes == false)
+ if (entityIsAncestorOfStartNodes == false)
return null;
var treeNode = GetSingleTreeNode(e, parentId, queryStrings);
- if (IgnoreUserStartNodes(queryStrings) == false && hasPathAccess == false)
+ if (hasPathAccess == false)
{
treeNode.AdditionalData["noAccess"] = true;
}
@@ -134,7 +134,7 @@ namespace Umbraco.Web.Trees
// ensure that the user has access to that node, otherwise return the empty tree nodes collection
// TODO: in the future we could return a validation statement so we can have some UI to notify the user they don't have access
- if (IgnoreUserStartNodes(queryStrings) == false && HasPathAccess(id, queryStrings) == false)
+ if (HasPathAccess(id, queryStrings) == false)
{
Logger.Warn("User {Username} does not have access to node with id {Id}", Security.CurrentUser.Username, id);
return nodes;
@@ -214,12 +214,8 @@ namespace Umbraco.Web.Trees
return result;
}
- ///
- /// Abstract method to fetch the entities from the entity service
- ///
- ///
- ///
- internal abstract IEnumerable GetChildrenFromEntityService(int entityId);
+ internal virtual IEnumerable GetChildrenFromEntityService(int entityId)
+ => Services.EntityService.GetChildren(entityId, UmbracoObjectType).ToList();
///
/// Returns true or false if the current user has access to the node based on the user's allowed start node (path) access
@@ -255,9 +251,8 @@ namespace Umbraco.Web.Trees
///
protected sealed override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
{
- var ignoreUserStartNodes = queryStrings.GetValue(TreeQueryStringParameters.IgnoreUserStartNodes);
//check if we're rendering the root
- if (id == Constants.System.RootString && UserStartNodes.Contains(Constants.System.Root) || ignoreUserStartNodes)
+ if (id == Constants.System.RootString && UserStartNodes.Contains(Constants.System.Root))
{
var altStartId = string.Empty;
diff --git a/src/Umbraco.Web/Trees/MediaTreeController.cs b/src/Umbraco.Web/Trees/MediaTreeController.cs
index d050b51a91..22ad4ed355 100644
--- a/src/Umbraco.Web/Trees/MediaTreeController.cs
+++ b/src/Umbraco.Web/Trees/MediaTreeController.cs
@@ -167,11 +167,5 @@ namespace Umbraco.Web.Trees
return _treeSearcher.ExamineSearch(query, UmbracoEntityTypes.Media, pageSize, pageIndex, out totalFound, searchFrom);
}
- internal override IEnumerable GetChildrenFromEntityService(int entityId)
- // Not pretty having to cast the service, but it is the only way to get to use an internal method that we
- // do not want to make public on the interface. Unfortunately also prevents this from being unit tested.
- // See this issue for details on why we need this:
- // https://github.com/umbraco/Umbraco-CMS/issues/3457
- => ((EntityService)Services.EntityService).GetMediaChildrenWithoutPropertyData(entityId).ToList();
}
}
diff --git a/src/Umbraco.Web/Trees/TreeControllerBase.cs b/src/Umbraco.Web/Trees/TreeControllerBase.cs
index 2e409c2820..4acf807b77 100644
--- a/src/Umbraco.Web/Trees/TreeControllerBase.cs
+++ b/src/Umbraco.Web/Trees/TreeControllerBase.cs
@@ -369,16 +369,6 @@ namespace Umbraco.Web.Trees
return queryStrings.GetValue(TreeQueryStringParameters.Use) == "dialog";
}
- ///
- /// If the request should allows a user to choose nodes that they normally don't have access to
- ///
- ///
- ///
- protected bool IgnoreUserStartNodes(FormDataCollection queryStrings)
- {
- return queryStrings.GetValue(TreeQueryStringParameters.IgnoreUserStartNodes);
- }
-
///
/// An event that allows developers to modify the tree node collection that is being rendered
///
diff --git a/src/Umbraco.Web/Trees/TreeQueryStringParameters.cs b/src/Umbraco.Web/Trees/TreeQueryStringParameters.cs
index 0fcf5321e4..466aff5a1f 100644
--- a/src/Umbraco.Web/Trees/TreeQueryStringParameters.cs
+++ b/src/Umbraco.Web/Trees/TreeQueryStringParameters.cs
@@ -8,7 +8,6 @@
public const string Use = "use";
public const string Application = "application";
public const string StartNodeId = "startNodeId";
- public const string IgnoreUserStartNodes = "ignoreUserStartNodes";
//public const string OnNodeClick = "OnNodeClick";
//public const string RenderParent = "RenderParent";
}
diff --git a/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs b/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs
index 0c53838592..efee045890 100644
--- a/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs
+++ b/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs
@@ -11,7 +11,6 @@ using Umbraco.Core.Models;
using Umbraco.Web.Actions;
using Umbraco.Core.Security;
using System.Net;
-using System.Web;
namespace Umbraco.Web.WebApi.Filters
{
@@ -67,7 +66,7 @@ namespace Umbraco.Web.WebApi.Filters
//not logged in
throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized);
}
-
+
int nodeId;
if (_nodeId.HasValue == false)
{
@@ -117,29 +116,24 @@ namespace Umbraco.Web.WebApi.Filters
nodeId = _nodeId.Value;
}
- var queryStringCollection = HttpUtility.ParseQueryString(actionContext.Request.RequestUri.Query);
- bool.TryParse(queryStringCollection["ignoreUserStartNodes"], out var ignoreUserStartNodes);
- if (ignoreUserStartNodes == false)
+ var permissionResult = ContentPermissionsHelper.CheckPermissions(nodeId,
+ Current.UmbracoContext.Security.CurrentUser,
+ Current.Services.UserService,
+ Current.Services.ContentService,
+ Current.Services.EntityService,
+ out var contentItem,
+ _permissionToCheck.HasValue ? new[] { _permissionToCheck.Value } : null);
+
+ if (permissionResult == ContentPermissionsHelper.ContentAccess.NotFound)
+ throw new HttpResponseException(HttpStatusCode.NotFound);
+
+ if (permissionResult == ContentPermissionsHelper.ContentAccess.Denied)
+ throw new HttpResponseException(actionContext.Request.CreateUserNoAccessResponse());
+
+ if (contentItem != null)
{
- var permissionResult = ContentPermissionsHelper.CheckPermissions(nodeId,
- Current.UmbracoContext.Security.CurrentUser,
- Current.Services.UserService,
- Current.Services.ContentService,
- Current.Services.EntityService,
- out var contentItem,
- _permissionToCheck.HasValue ? new[] {_permissionToCheck.Value} : null);
-
- if (permissionResult == ContentPermissionsHelper.ContentAccess.NotFound)
- throw new HttpResponseException(HttpStatusCode.NotFound);
-
- if (permissionResult == ContentPermissionsHelper.ContentAccess.Denied)
- throw new HttpResponseException(actionContext.Request.CreateUserNoAccessResponse());
-
- if (contentItem != null)
- {
- //store the content item in request cache so it can be resolved in the controller without re-looking it up
- actionContext.Request.Properties[typeof(IContent).ToString()] = contentItem;
- }
+ //store the content item in request cache so it can be resolved in the controller without re-looking it up
+ actionContext.Request.Properties[typeof(IContent).ToString()] = contentItem;
}
base.OnActionExecuting(actionContext);
diff --git a/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs b/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs
index f8b02f08ca..21dc60e6cc 100644
--- a/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs
+++ b/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs
@@ -3,14 +3,12 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
-using System.Web;
using System.Web.Http.Filters;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Composing;
using Umbraco.Core.Security;
-using Umbraco.Web.Trees;
namespace Umbraco.Web.WebApi.Filters
{
@@ -74,12 +72,7 @@ namespace Umbraco.Web.WebApi.Filters
protected virtual void FilterItems(IUser user, IList items)
{
- bool.TryParse(HttpContext.Current.Request.QueryString.Get(TreeQueryStringParameters.IgnoreUserStartNodes), out var ignoreUserStartNodes);
-
- if (ignoreUserStartNodes == false)
- {
- FilterBasedOnStartNode(items, user);
- }
+ FilterBasedOnStartNode(items, user);
}
internal void FilterBasedOnStartNode(IList items, IUser user)