diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 7d3557a81d..3ef1df3bc5 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -241,8 +241,8 @@ namespace Umbraco.Core.Persistence.Repositories // see: http://issues.umbraco.org/issue/U4-6322 & http://issues.umbraco.org/issue/U4-5982 var descendants = GetPagedResultsByQuery(query, pageIndex, pageSize, out total, new Tuple("cmsDocument", "nodeId"), - ProcessQuery, "Path", Direction.Ascending); - + ProcessQuery, "Path", Direction.Ascending, orderBySystemField: true); + var xmlItems = (from descendant in descendants let xml = serializer(descendant) select new ContentXmlDto { NodeId = descendant.Id, Xml = xml.ToDataString() }).ToArray(); @@ -766,10 +766,11 @@ namespace Umbraco.Core.Persistence.Repositories /// Total records query would return without paging /// Field to order by /// Direction to order by + /// Flag to indicate when ordering by system field /// Search text filter /// An Enumerable list of objects public IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, string filter = "") + string orderBy, Direction orderDirection, bool orderBySystemField, string filter = "") { //NOTE: This uses the GetBaseQuery method but that does not take into account the required 'newest' field which is @@ -788,7 +789,7 @@ namespace Umbraco.Core.Persistence.Repositories return GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, new Tuple("cmsDocument", "nodeId"), - ProcessQuery, orderBy, orderDirection, + ProcessQuery, orderBy, orderDirection, orderBySystemField, filterCallback); } diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs index 9d3fcbb40b..ab176df6d0 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs @@ -84,9 +84,10 @@ namespace Umbraco.Core.Persistence.Repositories /// Total records query would return without paging /// Field to order by /// Direction to order by + /// Flag to indicate when ordering by system field /// Search text filter /// An Enumerable list of objects IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, string filter = ""); + string orderBy, Direction orderDirection, bool orderBySystemField, string filter = ""); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaRepository.cs index 46bce6a03c..907f9b62c5 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaRepository.cs @@ -9,7 +9,7 @@ namespace Umbraco.Core.Persistence.Repositories { public interface IMediaRepository : IRepositoryVersionable, IRecycleBinRepository, IDeleteMediaFilesRepository { - + /// /// Used to add/update published xml for the media item /// @@ -33,9 +33,10 @@ namespace Umbraco.Core.Persistence.Repositories /// Total records query would return without paging /// Field to order by /// Direction to order by + /// Flag to indicate when ordering by system field /// Search text filter /// An Enumerable list of objects IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, string filter = ""); + string orderBy, Direction orderDirection, bool orderBySystemField, string filter = ""); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMemberRepository.cs index 9cb74d1806..a24116f0e2 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMemberRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMemberRepository.cs @@ -44,16 +44,17 @@ namespace Umbraco.Core.Persistence.Repositories /// /// Gets paged member results /// - /// - /// - /// - /// - /// - /// - /// + /// The query. + /// Index of the page. + /// Size of the page. + /// The total records. + /// The order by column + /// The order direction. + /// Flag to indicate when ordering by system field + /// Search query /// IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, string filter = ""); + string orderBy, Direction orderDirection, bool orderBySystemField, string filter = ""); //IEnumerable GetPagedResultsByQuery( // Sql sql, int pageIndex, int pageSize, out int totalRecords, diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs index 162ad88ca0..bb54eebeec 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs @@ -232,7 +232,7 @@ namespace Umbraco.Core.Persistence.Repositories var processed = 0; do { - var descendants = GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "Path", Direction.Ascending); + var descendants = GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "Path", Direction.Ascending, orderBySystemField: true); var xmlItems = (from descendant in descendants let xml = serializer(descendant) @@ -442,10 +442,11 @@ namespace Umbraco.Core.Persistence.Repositories /// Total records query would return without paging /// Field to order by /// Direction to order by + /// Flag to indicate when ordering by system field /// Search text filter /// An Enumerable list of objects public IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, string filter = "") + string orderBy, Direction orderDirection, bool orderBySystemField, string filter = "") { var args = new List(); var sbWhere = new StringBuilder(); @@ -459,7 +460,7 @@ namespace Umbraco.Core.Persistence.Repositories return GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, new Tuple("cmsContentVersion", "contentId"), - ProcessQuery, orderBy, orderDirection, + ProcessQuery, orderBy, orderDirection, orderBySystemField, filterCallback); } @@ -468,7 +469,7 @@ namespace Umbraco.Core.Persistence.Repositories { //NOTE: This doesn't allow properties to be part of the query var dtos = Database.Fetch(sql); - + var ids = dtos.Select(x => x.ContentDto.ContentTypeId).ToArray(); //content types diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs index ac5529b523..e0718d0356 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs @@ -74,7 +74,7 @@ namespace Umbraco.Core.Persistence.Repositories } return ProcessQuery(sql); - + } protected override IEnumerable PerformGetByQuery(IQuery query) @@ -95,7 +95,7 @@ namespace Umbraco.Core.Persistence.Repositories baseQuery.Append(new Sql("WHERE umbracoNode.id IN (" + sql.SQL + ")", sql.Arguments)) .OrderBy(x => x.SortOrder); - return ProcessQuery(baseQuery); + return ProcessQuery(baseQuery); } else { @@ -103,7 +103,7 @@ namespace Umbraco.Core.Persistence.Repositories var sql = translator.Translate() .OrderBy(x => x.SortOrder); - return ProcessQuery(sql); + return ProcessQuery(sql); } } @@ -118,7 +118,7 @@ namespace Umbraco.Core.Persistence.Repositories sql.Select(isCount ? "COUNT(*)" : "*") .From() .InnerJoin() - .On(left => left.NodeId, right => right.NodeId) + .On(left => left.NodeId, right => right.NodeId) .InnerJoin() .On(left => left.NodeId, right => right.NodeId) //We're joining the type so we can do a query against the member type - not sure if this adds much overhead or not? @@ -269,7 +269,7 @@ namespace Umbraco.Core.Persistence.Repositories //Ensure that strings don't contain characters that are invalid in XML entity.SanitizeEntityPropertiesForXmlStorage(); - var dirtyEntity = (ICanBeDirty) entity; + var dirtyEntity = (ICanBeDirty)entity; //Look up parent to get and set the correct Path and update SortOrder if ParentId has changed if (dirtyEntity.IsPropertyDirty("ParentId")) @@ -308,9 +308,9 @@ namespace Umbraco.Core.Persistence.Repositories //Updates the current version - cmsContentVersion //Assumes a Version guid exists and Version date (modified date) has been set/updated Database.Update(dto.ContentVersionDto); - + //Updates the cmsMember entry if it has changed - + //NOTE: these cols are the REAL column names in the db var changedCols = new List(); @@ -330,13 +330,13 @@ namespace Umbraco.Core.Persistence.Repositories //only update the changed cols if (changedCols.Count > 0) { - Database.Update(dto, changedCols); + Database.Update(dto, changedCols); } //TODO ContentType for the Member entity //Create the PropertyData for this version - cmsPropertyData - var propertyFactory = new PropertyFactory(entity.ContentType.CompositionPropertyTypes.ToArray(), entity.Version, entity.Id); + var propertyFactory = new PropertyFactory(entity.ContentType.CompositionPropertyTypes.ToArray(), entity.Version, entity.Id); var keyDictionary = new Dictionary(); //Add Properties @@ -447,7 +447,7 @@ namespace Umbraco.Core.Persistence.Repositories var processed = 0; do { - var descendants = GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "Path", Direction.Ascending); + var descendants = GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "Path", Direction.Ascending, orderBySystemField: true); var xmlItems = (from descendant in descendants let xml = serializer(descendant) @@ -559,7 +559,7 @@ namespace Umbraco.Core.Persistence.Repositories var grpQry = new Query().Where(group => group.Name.Equals(groupName)); var memberGroup = _memberGroupRepository.GetByQuery(grpQry).FirstOrDefault(); if (memberGroup == null) return Enumerable.Empty(); - + var subQuery = new Sql().Select("Member").From().Where(dto => dto.MemberGroup == memberGroup.Id); var sql = GetBaseQuery(false) @@ -568,7 +568,7 @@ namespace Umbraco.Core.Persistence.Repositories .Append(new Sql("WHERE umbracoNode.id IN (" + subQuery.SQL + ")", subQuery.Arguments)) .OrderByDescending(x => x.VersionDate) .OrderBy(x => x.SortOrder); - + return ProcessQuery(sql); } @@ -593,7 +593,7 @@ namespace Umbraco.Core.Persistence.Repositories //get the COUNT base query var fullSql = GetBaseQuery(true) .Append(new Sql("WHERE umbracoNode.id IN (" + sql.SQL + ")", sql.Arguments)); - + return Database.ExecuteScalar(fullSql); } @@ -603,18 +603,19 @@ namespace Umbraco.Core.Persistence.Repositories /// /// The where clause, if this is null all records are queried /// - /// - /// - /// - /// - /// - /// + /// Index of the page. + /// Size of the page. + /// The total records. + /// The order by column + /// The order direction. + /// Flag to indicate when ordering by system field + /// Search query /// /// /// The query supplied will ONLY work with data specifically on the cmsMember table because we are using PetaPoco paging (SQL paging) /// public IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, string filter = "") + string orderBy, Direction orderDirection, bool orderBySystemField, string filter = "") { var args = new List(); var sbWhere = new StringBuilder(); @@ -625,14 +626,14 @@ namespace Umbraco.Core.Persistence.Repositories "OR (cmsMember.LoginName LIKE @0" + args.Count + "))"); args.Add("%" + filter + "%"); filterCallback = () => new Tuple(sbWhere.ToString().Trim(), args.ToArray()); - } + } return GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, new Tuple("cmsMember", "nodeId"), - ProcessQuery, orderBy, orderDirection, + ProcessQuery, orderBy, orderDirection, orderBySystemField, filterCallback); } - + public void AddOrUpdateContentXml(IMember content, Func xml) { _contentXmlRepository.AddOrUpdate(new ContentXmlEntity(content, xml)); @@ -682,7 +683,7 @@ namespace Umbraco.Core.Persistence.Repositories var dtosWithContentTypes = dtos //This select into and null check are required because we don't have a foreign damn key on the contentType column // http://issues.umbraco.org/issue/U4-5503 - .Select(x => new {dto = x, contentType = contentTypes.FirstOrDefault(ct => ct.Id == x.ContentVersionDto.ContentDto.ContentTypeId)}) + .Select(x => new { dto = x, contentType = contentTypes.FirstOrDefault(ct => ct.Id == x.ContentVersionDto.ContentDto.ContentTypeId) }) .Where(x => x.contentType != null) .ToArray(); @@ -694,12 +695,12 @@ namespace Umbraco.Core.Persistence.Repositories d.dto.ContentVersionDto.ContentDto.NodeDto.CreateDate, d.contentType)); - var propertyData = GetPropertyCollection(sql, docDefs); + var propertyData = GetPropertyCollection(sql, docDefs); return dtosWithContentTypes.Select(d => CreateMemberFromDto( d.dto, contentTypes.First(ct => ct.Id == d.dto.ContentVersionDto.ContentDto.ContentTypeId), - propertyData[d.dto.NodeId])); + propertyData[d.dto.NodeId])); } /// diff --git a/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs index 56b0b63ad5..acff02c892 100644 --- a/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs @@ -25,6 +25,7 @@ using Umbraco.Core.IO; namespace Umbraco.Core.Persistence.Repositories { + using SqlSyntax; internal abstract class VersionableRepositoryBase : PetaPocoRepositoryBase where TEntity : class, IAggregateRoot { @@ -61,11 +62,11 @@ namespace Umbraco.Core.Persistence.Repositories public virtual void DeleteVersion(Guid versionId) { var dto = Database.FirstOrDefault("WHERE versionId = @VersionId", new { VersionId = versionId }); - if(dto == null) return; + if (dto == null) return; //Ensure that the lastest version is not deleted var latestVersionDto = Database.FirstOrDefault("WHERE ContentId = @Id ORDER BY VersionDate DESC", new { Id = dto.NodeId }); - if(latestVersionDto.VersionId == dto.VersionId) + if (latestVersionDto.VersionId == dto.VersionId) return; using (var transaction = Database.GetTransaction()) @@ -83,7 +84,7 @@ namespace Umbraco.Core.Persistence.Repositories var list = Database.Fetch( "WHERE versionId <> @VersionId AND (ContentId = @Id AND VersionDate < @VersionDate)", - new {VersionId = latestVersionDto.VersionId, Id = id, VersionDate = versionDate}); + new { VersionId = latestVersionDto.VersionId, Id = id, VersionDate = versionDate }); if (list.Any() == false) return; using (var transaction = Database.GetTransaction()) @@ -244,23 +245,57 @@ namespace Umbraco.Core.Persistence.Repositories return filteredSql; } - private Sql GetSortedSqlForPagedResults(Sql sql, Direction orderDirection, string orderBy) + private Sql GetSortedSqlForPagedResults(Sql sql, Direction orderDirection, string orderBy, bool orderBySystemField) { //copy to var so that the original isn't changed var sortedSql = new Sql(sql.SQL, sql.Arguments); - // Apply order according to parameters - if (string.IsNullOrEmpty(orderBy) == false) + + if (orderBySystemField) { - var orderByParams = new[] { GetDatabaseFieldNameForOrderBy(orderBy) }; - if (orderDirection == Direction.Ascending) + // Apply order according to parameters + if (string.IsNullOrEmpty(orderBy) == false) { - sortedSql.OrderBy(orderByParams); + var orderByParams = new[] { GetDatabaseFieldNameForOrderBy(orderBy) }; + if (orderDirection == Direction.Ascending) + { + sortedSql.OrderBy(orderByParams); + } + else + { + sortedSql.OrderByDescending(orderByParams); + } } - else + } + else + { + // Sorting by a custom field, so set-up sub-query for ORDER BY clause to pull through valie + // from most recent content version for the given order by field + var sortedInt = string.Format(SqlSyntaxContext.SqlSyntaxProvider.ConvertIntegerToOrderableString, "dataInt"); + var sortedDate = string.Format(SqlSyntaxContext.SqlSyntaxProvider.ConvertDateToOrderableString, "dataDate"); + var sortedString = string.Format(SqlSyntaxContext.SqlSyntaxProvider.IsNull, "dataNvarchar", "''"); + + var orderBySql = string.Format(@"ORDER BY ( + SELECT CASE + WHEN dataInt Is Not Null THEN {0} + WHEN dataDate Is Not Null THEN {1} + ELSE {2} + END + FROM cmsContent c + INNER JOIN cmsContentVersion cv ON cv.ContentId = c.nodeId AND VersionDate = ( + SELECT Max(VersionDate) + FROM cmsContentVersion + WHERE ContentId = c.nodeId + ) + INNER JOIN cmsPropertyData cpd ON cpd.contentNodeId = c.nodeId + AND cpd.versionId = cv.VersionId + INNER JOIN cmsPropertyType cpt ON cpt.Id = cpd.propertytypeId + WHERE c.nodeId = umbracoNode.Id and cpt.Alias = @0)", sortedInt, sortedDate, sortedString); + + sortedSql.Append(orderBySql, orderBy); + if (orderDirection == Direction.Descending) { - sortedSql.OrderByDescending(orderByParams); + sortedSql.Append(" DESC"); } - return sortedSql; } return sortedSql; } @@ -279,13 +314,15 @@ namespace Umbraco.Core.Persistence.Repositories /// A callback to process the query result /// The order by column /// The order direction. + /// Flag to indicate when ordering by system field /// /// orderBy protected IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, Tuple nodeIdSelect, Func> processQuery, - string orderBy, + string orderBy, Direction orderDirection, + bool orderBySystemField, Func> defaultFilter = null) where TContentBase : class, IAggregateRoot, TEntity { @@ -297,18 +334,18 @@ namespace Umbraco.Core.Persistence.Repositories if (query == null) query = new Query(); var translator = new SqlTranslator(sqlBase, query); var sqlQuery = translator.Translate(); - + // Note we can't do multi-page for several DTOs like we can multi-fetch and are doing in PerformGetByQuery, // but actually given we are doing a Get on each one (again as in PerformGetByQuery), we only need the node Id. // So we'll modify the SQL. var sqlNodeIds = new Sql( - sqlQuery.SQL.Replace("SELECT *", string.Format("SELECT {0}.{1}",nodeIdSelect.Item1, nodeIdSelect.Item2)), + sqlQuery.SQL.Replace("SELECT *", string.Format("SELECT {0}.{1}", nodeIdSelect.Item1, nodeIdSelect.Item2)), sqlQuery.Arguments); - + //get sorted and filtered sql var sqlNodeIdsWithSort = GetSortedSqlForPagedResults( GetFilteredSqlForPagedResults(sqlNodeIds, defaultFilter), - orderDirection, orderBy); + orderDirection, orderBy, orderBySystemField); // Get page of results and total count IEnumerable result; @@ -324,7 +361,7 @@ namespace Umbraco.Core.Persistence.Repositories var args = sqlNodeIdsWithSort.Arguments; string sqlStringCount, sqlStringPage; Database.BuildPageQueries(pageIndex * pageSize, pageSize, sqlNodeIdsWithSort.SQL, ref args, out sqlStringCount, out sqlStringPage); - + //if this is for sql server, the sqlPage will start with a SELECT * but we don't want that, we only want to return the nodeId sqlStringPage = sqlStringPage .Replace("SELECT *", @@ -333,7 +370,7 @@ namespace Umbraco.Core.Persistence.Repositories "SELECT " + nodeIdSelect.Item2); //We need to make this an inner join on the paged query - var splitQuery = sqlQuery.SQL.Split(new[] {"WHERE "}, StringSplitOptions.None); + var splitQuery = sqlQuery.SQL.Split(new[] { "WHERE " }, StringSplitOptions.None); var withInnerJoinSql = new Sql(splitQuery[0]) .Append("INNER JOIN (") //join the paged query with the paged query arguments @@ -345,23 +382,9 @@ namespace Umbraco.Core.Persistence.Repositories //get sorted and filtered sql var fullQuery = GetSortedSqlForPagedResults( - GetFilteredSqlForPagedResults(withInnerJoinSql, defaultFilter), - orderDirection, orderBy); - - var content = processQuery(fullQuery) - .Cast() - .AsQueryable(); - - // Now we need to ensure this result is also ordered by the same order by clause - var orderByProperty = GetEntityPropertyNameForOrderBy(orderBy); - if (orderDirection == Direction.Ascending) - { - result = content.OrderBy(orderByProperty); - } - else - { - result = content.OrderByDescending(orderByProperty); - } + GetFilteredSqlForPagedResults(withInnerJoinSql, defaultFilter), + orderDirection, orderBy, orderBySystemField); + return processQuery(fullQuery); } else { @@ -394,9 +417,9 @@ INNER JOIN (" + string.Format(parsedOriginalSql, "cmsContent.nodeId, cmsContentVersion.VersionId") + @") as docData ON cmsPropertyData.versionId = docData.VersionId AND cmsPropertyData.contentNodeId = docData.nodeId LEFT OUTER JOIN cmsDataTypePreValues -ON cmsPropertyType.dataTypeId = cmsDataTypePreValues.datatypeNodeId", docSql.Arguments); +ON cmsPropertyType.dataTypeId = cmsDataTypePreValues.datatypeNodeId", docSql.Arguments); - var allPropertyData = Database.Fetch(propSql); + var allPropertyData = Database.Fetch(propSql); //This is a lazy access call to get all prevalue data for the data types that make up all of these properties which we use // below if any property requires tag support @@ -414,7 +437,7 @@ WHERE EXISTS( ON cmsPropertyType.contentTypeId = docData.contentType WHERE a.id = b.id)", docSql.Arguments); - return Database.Fetch(preValsSql); + return Database.Fetch(preValsSql); }); var result = new Dictionary(); @@ -432,8 +455,8 @@ WHERE EXISTS( var propertyDataDtos = allPropertyData.Where(x => x.NodeId == def.Id).Distinct(); var propertyFactory = new PropertyFactory(compositionProperties, def.Version, def.Id, def.CreateDate, def.VersionDate); - var properties = propertyFactory.BuildEntity(propertyDataDtos.ToArray()).ToArray(); - + var properties = propertyFactory.BuildEntity(propertyDataDtos.ToArray()).ToArray(); + var newProperties = properties.Where(x => x.HasIdentity == false && x.PropertyType.HasIdentity); foreach (var property in newProperties) @@ -481,7 +504,7 @@ WHERE EXISTS( Logger.Warn>("The query returned multiple property sets for document definition " + def.Id + ", " + def.Composition.Name); } result[def.Id] = new PropertyCollection(properties); - } + } } return result; @@ -521,6 +544,9 @@ WHERE EXISTS( case "OWNER": //TODO: This isn't going to work very nicely because it's going to order by ID, not by letter return "umbracoNode.nodeUser"; + // Members only + case "USERNAME": + return "cmsMember.LoginName"; default: //ensure invalid SQL cannot be submitted return Regex.Replace(orderBy, @"[^\w\.,`\[\]@-]", ""); diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs index 056d9c1d9a..e663c8e64b 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs @@ -70,6 +70,10 @@ namespace Umbraco.Core.Persistence.SqlSyntax bool SupportsIdentityInsert(); bool? SupportsCaseInsensitiveQueries(Database db); + string IsNull { get; } + string ConvertIntegerToOrderableString { get; } + string ConvertDateToOrderableString { get; } + IEnumerable GetTablesInSchema(Database db); IEnumerable GetColumnsInSchema(Database db); IEnumerable> GetConstraintsPerTable(Database db); diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs index c18a5f8477..c45aade707 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs @@ -18,7 +18,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax public MySqlSyntaxProvider(ILogger logger) { _logger = logger; - + AutoIncrementDefinition = "AUTO_INCREMENT"; IntColumnDefinition = "int(11)"; BoolColumnDefinition = "tinyint(1)"; @@ -26,7 +26,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax TimeColumnDefinition = "time"; DecimalColumnDefinition = "decimal(38,6)"; GuidColumnDefinition = "char(36)"; - + DefaultValueFormat = "DEFAULT {0}"; InitColumnTypeMap(); @@ -326,13 +326,13 @@ ORDER BY TABLE_NAME, INDEX_NAME", { case SystemMethods.NewGuid: return null; // NOT SUPPORTED! - //return "NEWID()"; + //return "NEWID()"; case SystemMethods.CurrentDateTime: return "CURRENT_TIMESTAMP"; - //case SystemMethods.NewSequentialId: - // return "NEWSEQUENTIALID()"; - //case SystemMethods.CurrentUTCDateTime: - // return "GETUTCDATE()"; + //case SystemMethods.NewSequentialId: + // return "NEWSEQUENTIALID()"; + //case SystemMethods.CurrentUTCDateTime: + // return "GETUTCDATE()"; } return null; @@ -360,6 +360,9 @@ ORDER BY TABLE_NAME, INDEX_NAME", public override string DropIndex { get { return "DROP INDEX {0} ON {1}"; } } public override string RenameColumn { get { return "ALTER TABLE {0} CHANGE {1} {2}"; } } + public override string IsNull { get { return "IFNULL({0},{1})"; } } + public override string ConvertIntegerToOrderableString { get { return "LPAD({0}, 8, '0')"; } } + public override string ConvertDateToOrderableString { get { return "DATE_FORMAT({0}, '%Y%m%d')"; } } public override bool? SupportsCaseInsensitiveQueries(Database db) { diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs index c2b81aa753..35c133ce6e 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs @@ -322,7 +322,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax GetQuotedColumnName(foreignKey.ForeignColumns.First()), GetQuotedTableName(foreignKey.PrimaryTable), GetQuotedColumnName(foreignKey.PrimaryColumns.First()), - FormatCascade("DELETE", foreignKey.OnDelete), + FormatCascade("DELETE", foreignKey.OnDelete), FormatCascade("UPDATE", foreignKey.OnUpdate)); } @@ -331,7 +331,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax var sb = new StringBuilder(); foreach (var column in columns) { - sb.Append(Format(column) +",\n"); + sb.Append(Format(column) + ",\n"); } return sb.ToString().TrimEnd(",\n"); } @@ -431,11 +431,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax return GetSpecialDbType(column.DbType); } - Type type = column.Type.HasValue + Type type = column.Type.HasValue ? DbTypeMap.ColumnDbTypeMap.First(x => x.Value == column.Type.Value).Key : column.PropertyType; - if (type == typeof (string)) + if (type == typeof(string)) { var valueOrDefault = column.Size != default(int) ? column.Size : DefaultStringLength; return string.Format(StringLengthColumnDefinitionFormat, valueOrDefault); @@ -536,5 +536,9 @@ namespace Umbraco.Core.Persistence.SqlSyntax public virtual string CreateConstraint { get { return "ALTER TABLE {0} ADD CONSTRAINT {1} {2} ({3})"; } } public virtual string DeleteConstraint { get { return "ALTER TABLE {0} DROP CONSTRAINT {1}"; } } public virtual string CreateForeignKeyConstraint { get { return "ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}){5}{6}"; } } + + public virtual string IsNull { get { return "ISNULL({0},{1})"; } } + public virtual string ConvertIntegerToOrderableString { get { return "RIGHT('00000000' + CAST({0} AS varchar(8)),8)"; } } + public virtual string ConvertDateToOrderableString { get { return "CONVERT(varchar, {0}, 102)"; } } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index e7298a5c6e..773d26a455 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -231,7 +231,7 @@ namespace Umbraco.Core.Services public IContent CreateContentWithIdentity(string name, int parentId, string contentTypeAlias, int userId = 0) { var contentType = FindContentTypeByAlias(contentTypeAlias); - var content = new Content(name, parentId, contentType); + var content = new Content(name, parentId, contentType); //NOTE: I really hate the notion of these Creating/Created events - they are so inconsistent, I've only just found // out that in these 'WithIdentity' methods, the Saving/Saved events were not fired, wtf. Anyways, they're added now. @@ -485,7 +485,7 @@ namespace Umbraco.Core.Services [Obsolete("Use the overload with 'long' parameter types instead")] [EditorBrowsable(EditorBrowsableState.Never)] public IEnumerable GetPagedChildren(int id, int pageIndex, int pageSize, out int totalChildren, - string orderBy, Direction orderDirection, string filter = "") + string orderBy, Direction orderDirection, bool orderBySystemField = true, string filter = "") { Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); Mandate.ParameterCondition(pageSize > 0, "pageSize"); @@ -499,7 +499,7 @@ namespace Umbraco.Core.Services query.Where(x => x.ParentId == id); } long total; - var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out total, orderBy, orderDirection, filter); + var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out total, orderBy, orderDirection, orderBySystemField, filter); totalChildren = Convert.ToInt32(total); return contents; } @@ -514,10 +514,11 @@ namespace Umbraco.Core.Services /// Total records query would return without paging /// Field to order by /// Direction to order by + /// Flag to indicate when ordering by system field /// Search text filter /// An Enumerable list of objects public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, - string orderBy, Direction orderDirection, string filter = "") + string orderBy, Direction orderDirection, bool orderBySystemField = true, string filter = "") { Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); Mandate.ParameterCondition(pageSize > 0, "pageSize"); @@ -530,7 +531,7 @@ namespace Umbraco.Core.Services { query.Where(x => x.ParentId == id); } - var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, filter); + var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter); return contents; } @@ -538,7 +539,7 @@ namespace Umbraco.Core.Services [Obsolete("Use the overload with 'long' parameter types instead")] [EditorBrowsable(EditorBrowsableState.Never)] - public IEnumerable GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "") + public IEnumerable GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, bool orderBySystemField = true, string filter = "") { Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); Mandate.ParameterCondition(pageSize > 0, "pageSize"); @@ -552,7 +553,7 @@ namespace Umbraco.Core.Services query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar)); } long total; - var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out total, orderBy, orderDirection, filter); + var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out total, orderBy, orderDirection, orderBySystemField, filter); totalChildren = Convert.ToInt32(total); return contents; } @@ -567,9 +568,10 @@ namespace Umbraco.Core.Services /// Total records query would return without paging /// Field to order by /// Direction to order by + /// Flag to indicate when ordering by system field /// Search text filter /// An Enumerable list of objects - public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "") + public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, bool orderBySystemField = true, string filter = "") { Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); Mandate.ParameterCondition(pageSize > 0, "pageSize"); @@ -582,7 +584,7 @@ namespace Umbraco.Core.Services { query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar)); } - var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, filter); + var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter); return contents; } @@ -906,7 +908,7 @@ namespace Umbraco.Core.Services { var originalPath = content.Path; - if (Trashing.IsRaisedEventCancelled( + if (Trashing.IsRaisedEventCancelled( new MoveEventArgs(evtMsgs, new MoveEventInfo(content, originalPath, Constants.System.RecycleBinContent)), this)) { @@ -1022,7 +1024,7 @@ namespace Umbraco.Core.Services /// True if unpublishing succeeded, otherwise False public bool UnPublish(IContent content, int userId = 0) { - return ((IContentServiceOperations) this).UnPublish(content, userId).Success; + return ((IContentServiceOperations)this).UnPublish(content, userId).Success; } /// @@ -1143,7 +1145,7 @@ namespace Umbraco.Core.Services using (new WriteLock(Locker)) { - if (Deleting.IsRaisedEventCancelled( + if (Deleting.IsRaisedEventCancelled( new DeleteEventArgs(content, evtMsgs), this)) { @@ -1168,10 +1170,10 @@ namespace Umbraco.Core.Services { repository.Delete(content); uow.Commit(); - + var args = new DeleteEventArgs(content, false, evtMsgs); Deleted.RaiseEvent(args, this); - + //remove any flagged media files repository.DeleteMediaFiles(args.MediaFilesToDelete); } @@ -1350,7 +1352,7 @@ namespace Umbraco.Core.Services /// Optional Id of the User deleting the Content public void MoveToRecycleBin(IContent content, int userId = 0) { - ((IContentServiceOperations) this).MoveToRecycleBin(content, userId); + ((IContentServiceOperations)this).MoveToRecycleBin(content, userId); } /// @@ -1654,7 +1656,7 @@ namespace Umbraco.Core.Services //TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable! _publishingStrategy.PublishingFinalized(shouldBePublished, false); } - + Audit(AuditType.Sort, "Sorting content performed by user", userId, 0); @@ -1902,13 +1904,13 @@ namespace Umbraco.Core.Services content = newest; var evtMsgs = EventMessagesFactory.Get(); - + var published = content.Published ? content : GetPublishedVersion(content.Id); // get the published version if (published == null) { return Attempt.Succeed(new UnPublishStatus(content, UnPublishedStatusType.SuccessAlreadyUnPublished, evtMsgs)); // already unpublished } - + var unpublished = _publishingStrategy.UnPublish(content, userId); if (unpublished == false) return Attempt.Fail(new UnPublishStatus(content, UnPublishedStatusType.FailedCancelledByEvent, evtMsgs)); @@ -2046,7 +2048,7 @@ namespace Umbraco.Core.Services if (raiseEvents) { - if (Saving.IsRaisedEventCancelled( + if (Saving.IsRaisedEventCancelled( new SaveEventArgs(content, evtMsgs), this)) { diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index c686cf4891..95333bee85 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -203,7 +203,7 @@ namespace Umbraco.Core.Services [Obsolete("Use the overload with 'long' parameter types instead")] [EditorBrowsable(EditorBrowsableState.Never)] IEnumerable GetPagedChildren(int id, int pageIndex, int pageSize, out int totalRecords, - string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = ""); + string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, bool orderBySystemField = true, string filter = ""); /// /// Gets a collection of objects by Parent Id @@ -214,15 +214,16 @@ namespace Umbraco.Core.Services /// Total records query would return without paging /// Field to order by /// Direction to order by + /// Flag to indicate when ordering by system field /// Search text filter /// An Enumerable list of objects IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords, - string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = ""); + string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, bool orderBySystemField = true, string filter = ""); [Obsolete("Use the overload with 'long' parameter types instead")] [EditorBrowsable(EditorBrowsableState.Never)] IEnumerable GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalRecords, - string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = ""); + string orderBy = "Path", Direction orderDirection = Direction.Ascending, bool orderBySystemField = true, string filter = ""); /// /// Gets a collection of objects by Parent Id @@ -233,11 +234,12 @@ namespace Umbraco.Core.Services /// Total records query would return without paging /// Field to order by /// Direction to order by + /// Flag to indicate when ordering by system field /// Search text filter /// An Enumerable list of objects IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords, - string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = ""); - + string orderBy = "Path", Direction orderDirection = Direction.Ascending, bool orderBySystemField = true, string filter = ""); + /// /// Gets a collection of an objects versions by its Id /// @@ -268,7 +270,7 @@ namespace Umbraco.Core.Services /// /// An Enumerable list of objects IEnumerable GetContentInRecycleBin(); - + /// /// Saves a single object /// @@ -467,7 +469,7 @@ namespace Umbraco.Core.Services /// Optional boolean indicating whether or not to raise save events. /// True if publishing succeeded, otherwise False Attempt SaveAndPublishWithStatus(IContent content, int userId = 0, bool raiseEvents = true); - + /// /// Permanently deletes an object. /// diff --git a/src/Umbraco.Core/Services/IMediaService.cs b/src/Umbraco.Core/Services/IMediaService.cs index d104b95ddc..51c01703d5 100644 --- a/src/Umbraco.Core/Services/IMediaService.cs +++ b/src/Umbraco.Core/Services/IMediaService.cs @@ -121,7 +121,7 @@ namespace Umbraco.Core.Services [Obsolete("Use the overload with 'long' parameter types instead")] [EditorBrowsable(EditorBrowsableState.Never)] IEnumerable GetPagedChildren(int id, int pageIndex, int pageSize, out int totalRecords, - string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = ""); + string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, bool orderBySystemField = true, string filter = ""); /// /// Gets a collection of objects by Parent Id @@ -132,15 +132,16 @@ namespace Umbraco.Core.Services /// Total records query would return without paging /// Field to order by /// Direction to order by + /// Flag to indicate when ordering by system field /// Search text filter /// An Enumerable list of objects IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords, - string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = ""); + string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, bool orderBySystemField = true, string filter = ""); [Obsolete("Use the overload with 'long' parameter types instead")] [EditorBrowsable(EditorBrowsableState.Never)] IEnumerable GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalRecords, - string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = ""); + string orderBy = "Path", Direction orderDirection = Direction.Ascending, bool orderBySystemField = true, string filter = ""); /// /// Gets a collection of objects by Parent Id @@ -151,10 +152,11 @@ namespace Umbraco.Core.Services /// Total records query would return without paging /// Field to order by /// Direction to order by + /// Flag to indicate when ordering by system field /// Search text filter /// An Enumerable list of objects IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords, - string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = ""); + string orderBy = "Path", Direction orderDirection = Direction.Ascending, bool orderBySystemField = true, string filter = ""); /// /// Gets descendants of a object by its Id @@ -220,7 +222,7 @@ namespace Umbraco.Core.Services /// The to delete /// Id of the User deleting the Media void Delete(IMedia media, int userId = 0); - + /// /// Saves a single object /// diff --git a/src/Umbraco.Core/Services/IMemberService.cs b/src/Umbraco.Core/Services/IMemberService.cs index 20eef54b3c..3756ca246d 100644 --- a/src/Umbraco.Core/Services/IMemberService.cs +++ b/src/Umbraco.Core/Services/IMemberService.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Services [Obsolete("Use the overload with 'long' parameter types instead")] [EditorBrowsable(EditorBrowsableState.Never)] IEnumerable GetAll(int pageIndex, int pageSize, out int totalRecords, - string orderBy, Direction orderDirection, string memberTypeAlias = null, string filter = ""); + string orderBy, Direction orderDirection, bool orderBySystemField = true, string memberTypeAlias = null, string filter = ""); /// /// Gets a list of paged objects @@ -34,14 +34,15 @@ namespace Umbraco.Core.Services /// Current page index /// Size of the page /// Total number of records found (out) - /// - /// + /// Field to order by + /// Direction to order by + /// Flag to indicate when ordering by system field /// - /// + /// Search text filter /// IEnumerable GetAll(long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, string memberTypeAlias = null, string filter = ""); - + string orderBy, Direction orderDirection, bool orderBySystemField = true, string memberTypeAlias = null, string filter = ""); + /// /// Creates an object without persisting it /// @@ -91,7 +92,7 @@ namespace Umbraco.Core.Services /// MemberType the Member should be based on /// IMember CreateMemberWithIdentity(string username, string email, string name, IMemberType memberType); - + /// /// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method /// @@ -115,7 +116,7 @@ namespace Umbraco.Core.Services /// Id of the Member /// True if the Member exists otherwise False bool Exists(int id); - + /// /// Gets a Member by the unique key /// @@ -160,7 +161,7 @@ namespace Umbraco.Core.Services /// Optional list of Member Ids /// IEnumerable GetAllMembers(params int[] ids); - + /// /// Delete Members of the specified MemberType id /// diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs index accbebfe0b..3bbf8860ea 100644 --- a/src/Umbraco.Core/Services/MediaService.cs +++ b/src/Umbraco.Core/Services/MediaService.cs @@ -35,7 +35,7 @@ namespace Umbraco.Core.Services private readonly EntityXmlSerializer _entitySerializer = new EntityXmlSerializer(); private readonly IDataTypeService _dataTypeService; private readonly IUserService _userService; - + public MediaService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, ILogger logger, IEventMessagesFactory eventMessagesFactory, IDataTypeService dataTypeService, IUserService userService) : base(provider, repositoryFactory, logger, eventMessagesFactory) { @@ -395,7 +395,7 @@ namespace Umbraco.Core.Services [Obsolete("Use the overload with 'long' parameter types instead")] [EditorBrowsable(EditorBrowsableState.Never)] public IEnumerable GetPagedChildren(int id, int pageIndex, int pageSize, out int totalChildren, - string orderBy, Direction orderDirection, string filter = "") + string orderBy, Direction orderDirection, bool orderBySystemField = true, string filter = "") { Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); Mandate.ParameterCondition(pageSize > 0, "pageSize"); @@ -403,9 +403,9 @@ namespace Umbraco.Core.Services { var query = Query.Builder; query.Where(x => x.ParentId == id); - + long total; - var medias = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out total, orderBy, orderDirection, filter); + var medias = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out total, orderBy, orderDirection, orderBySystemField, filter); totalChildren = Convert.ToInt32(total); return medias; @@ -421,10 +421,11 @@ namespace Umbraco.Core.Services /// Total records query would return without paging /// Field to order by /// Direction to order by + /// Flag to indicate when ordering by system field /// Search text filter /// An Enumerable list of objects public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, - string orderBy, Direction orderDirection, string filter = "") + string orderBy, Direction orderDirection, bool orderBySystemField = true, string filter = "") { Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); Mandate.ParameterCondition(pageSize > 0, "pageSize"); @@ -432,8 +433,8 @@ namespace Umbraco.Core.Services { var query = Query.Builder; query.Where(x => x.ParentId == id); - - var medias = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, filter); + + var medias = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter); return medias; } @@ -441,7 +442,7 @@ namespace Umbraco.Core.Services [Obsolete("Use the overload with 'long' parameter types instead")] [EditorBrowsable(EditorBrowsableState.Never)] - public IEnumerable GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "") + public IEnumerable GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, bool orderBySystemField = true, string filter = "") { Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); Mandate.ParameterCondition(pageSize > 0, "pageSize"); @@ -455,7 +456,7 @@ namespace Umbraco.Core.Services query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar)); } long total; - var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out total, orderBy, orderDirection, filter); + var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out total, orderBy, orderDirection, orderBySystemField, filter); totalChildren = Convert.ToInt32(total); return contents; } @@ -470,9 +471,10 @@ namespace Umbraco.Core.Services /// Total records query would return without paging /// Field to order by /// Direction to order by + /// Flag to indicate when ordering by system field /// Search text filter /// An Enumerable list of objects - public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "") + public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, bool orderBySystemField = true, string filter = "") { Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); Mandate.ParameterCondition(pageSize > 0, "pageSize"); @@ -485,7 +487,7 @@ namespace Umbraco.Core.Services { query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar)); } - var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, filter); + var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter); return contents; } @@ -727,7 +729,7 @@ namespace Umbraco.Core.Services /// Id of the User deleting the Media public void MoveToRecycleBin(IMedia media, int userId = 0) { - ((IMediaServiceOperations) this).MoveToRecycleBin(media, userId); + ((IMediaServiceOperations)this).MoveToRecycleBin(media, userId); } /// @@ -744,7 +746,7 @@ namespace Umbraco.Core.Services //TODO: IT would be much nicer to mass delete all in one trans in the repo level! var evtMsgs = EventMessagesFactory.Get(); - if (Deleting.IsRaisedEventCancelled( + if (Deleting.IsRaisedEventCancelled( new DeleteEventArgs(media, evtMsgs), this)) { return OperationStatus.Cancelled(evtMsgs); @@ -1025,7 +1027,7 @@ namespace Umbraco.Core.Services ((IMediaServiceOperations)this).Delete(media, userId); } - + /// /// Permanently deletes versions from an object prior to a specific date. @@ -1081,7 +1083,7 @@ namespace Umbraco.Core.Services Audit(AuditType.Delete, "Delete Media by version performed by user", userId, -1); } - + /// /// Saves a single object /// @@ -1090,7 +1092,7 @@ namespace Umbraco.Core.Services /// Optional boolean indicating whether or not to raise events. public void Save(IMedia media, int userId = 0, bool raiseEvents = true) { - ((IMediaServiceOperations)this).Save (media, userId, raiseEvents); + ((IMediaServiceOperations)this).Save(media, userId, raiseEvents); } /// diff --git a/src/Umbraco.Core/Services/MemberService.cs b/src/Umbraco.Core/Services/MemberService.cs index 4f0647dbf7..9991583719 100644 --- a/src/Umbraco.Core/Services/MemberService.cs +++ b/src/Umbraco.Core/Services/MemberService.cs @@ -30,7 +30,7 @@ namespace Umbraco.Core.Services private readonly EntityXmlSerializer _entitySerializer = new EntityXmlSerializer(); private readonly IDataTypeService _dataTypeService; private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(); - + public MemberService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, ILogger logger, IEventMessagesFactory eventMessagesFactory, IMemberGroupService memberGroupService, IDataTypeService dataTypeService) : base(provider, repositoryFactory, logger, eventMessagesFactory) { @@ -52,7 +52,7 @@ namespace Umbraco.Core.Services { using (var repository = RepositoryFactory.CreateMemberTypeRepository(UowProvider.GetUnitOfWork())) { - var types = repository.GetAll(new int[]{}).Select(x => x.Alias).ToArray(); + var types = repository.GetAll(new int[] { }).Select(x => x.Alias).ToArray(); if (types.Any() == false) { @@ -289,7 +289,7 @@ namespace Umbraco.Core.Services throw new ArgumentOutOfRangeException("matchType"); } - return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, "Name", Direction.Ascending); + return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, "Name", Direction.Ascending, orderBySystemField: true); } } @@ -340,7 +340,7 @@ namespace Umbraco.Core.Services throw new ArgumentOutOfRangeException("matchType"); } - return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, "Email", Direction.Ascending); + return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, "Email", Direction.Ascending, orderBySystemField: true); } } @@ -391,7 +391,7 @@ namespace Umbraco.Core.Services throw new ArgumentOutOfRangeException("matchType"); } - return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, "LoginName", Direction.Ascending); + return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, "LoginName", Direction.Ascending, orderBySystemField: true); } } @@ -688,33 +688,33 @@ namespace Umbraco.Core.Services var uow = UowProvider.GetUnitOfWork(); using (var repository = RepositoryFactory.CreateMemberRepository(uow)) { - return repository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, "LoginName", Direction.Ascending); + return repository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, "LoginName", Direction.Ascending, orderBySystemField: true); } } [Obsolete("Use the overload with 'long' parameter types instead")] [EditorBrowsable(EditorBrowsableState.Never)] public IEnumerable GetAll(int pageIndex, int pageSize, out int totalRecords, - string orderBy, Direction orderDirection, string memberTypeAlias = null, string filter = "") + string orderBy, Direction orderDirection, bool orderBySystemField = true, string memberTypeAlias = null, string filter = "") { long total; - var result = GetAll(Convert.ToInt64(pageIndex), pageSize, out total, orderBy, orderDirection, memberTypeAlias, filter); + var result = GetAll(Convert.ToInt64(pageIndex), pageSize, out total, orderBy, orderDirection, orderBySystemField, memberTypeAlias, filter); totalRecords = Convert.ToInt32(total); return result; } public IEnumerable GetAll(long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, string memberTypeAlias = null, string filter = "") + string orderBy, Direction orderDirection, bool orderBySystemField = true, string memberTypeAlias = null, string filter = "") { var uow = UowProvider.GetUnitOfWork(); using (var repository = RepositoryFactory.CreateMemberRepository(uow)) { if (memberTypeAlias == null) { - return repository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filter); + return repository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, orderBySystemField, filter); } var query = new Query().Where(x => x.ContentTypeAlias == memberTypeAlias); - return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filter); + return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, orderBySystemField, filter); } } @@ -1253,52 +1253,52 @@ namespace Umbraco.Core.Services var memType = new MemberType(-1); var propGroup = new PropertyGroup - { - Name = "Membership", - Id = --identity - }; + { + Name = "Membership", + Id = --identity + }; propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext, Constants.Conventions.Member.Comments) - { - Name = Constants.Conventions.Member.CommentsLabel, - SortOrder = 0, - Id = --identity, - Key = identity.ToGuid() - }); + { + Name = Constants.Conventions.Member.CommentsLabel, + SortOrder = 0, + Id = --identity, + Key = identity.ToGuid() + }); propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.TrueFalseAlias, DataTypeDatabaseType.Integer, Constants.Conventions.Member.IsApproved) - { - Name = Constants.Conventions.Member.IsApprovedLabel, - SortOrder = 3, - Id = --identity, - Key = identity.ToGuid() - }); + { + Name = Constants.Conventions.Member.IsApprovedLabel, + SortOrder = 3, + Id = --identity, + Key = identity.ToGuid() + }); propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.TrueFalseAlias, DataTypeDatabaseType.Integer, Constants.Conventions.Member.IsLockedOut) - { - Name = Constants.Conventions.Member.IsLockedOutLabel, - SortOrder = 4, - Id = --identity, - Key = identity.ToGuid() - }); + { + Name = Constants.Conventions.Member.IsLockedOutLabel, + SortOrder = 4, + Id = --identity, + Key = identity.ToGuid() + }); propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date, Constants.Conventions.Member.LastLockoutDate) - { - Name = Constants.Conventions.Member.LastLockoutDateLabel, - SortOrder = 5, - Id = --identity, - Key = identity.ToGuid() - }); + { + Name = Constants.Conventions.Member.LastLockoutDateLabel, + SortOrder = 5, + Id = --identity, + Key = identity.ToGuid() + }); propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date, Constants.Conventions.Member.LastLoginDate) - { - Name = Constants.Conventions.Member.LastLoginDateLabel, - SortOrder = 6, - Id = --identity, - Key = identity.ToGuid() - }); + { + Name = Constants.Conventions.Member.LastLoginDateLabel, + SortOrder = 6, + Id = --identity, + Key = identity.ToGuid() + }); propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date, Constants.Conventions.Member.LastPasswordChangeDate) - { - Name = Constants.Conventions.Member.LastPasswordChangeDateLabel, - SortOrder = 7, - Id = --identity, - Key = identity.ToGuid() - }); + { + Name = Constants.Conventions.Member.LastPasswordChangeDateLabel, + SortOrder = 7, + Id = --identity, + Key = identity.ToGuid() + }); memType.PropertyGroups.Add(propGroup); diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs index c8ccecdb95..e256e4082a 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs @@ -72,7 +72,7 @@ namespace Umbraco.Tests.Persistence.Repositories //create 100 non published for (var i = 0; i < 100; i++) - { + { var c1 = MockedContent.CreateSimpleContent(contentType1); repository.AddOrUpdate(c1); allCreated.Add(c1); @@ -176,7 +176,7 @@ namespace Umbraco.Tests.Persistence.Repositories for (var i = 0; i < 30; i++) { //These will be non-published so shouldn't show up - var c1 = MockedContent.CreateSimpleContent(contentType1); + var c1 = MockedContent.CreateSimpleContent(contentType1); repository.AddOrUpdate(c1); allCreated.Add(c1); } @@ -275,7 +275,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Assert Assert.That(contentType.HasIdentity, Is.True); Assert.That(textpage.HasIdentity, Is.True); - + } } @@ -299,7 +299,7 @@ namespace Umbraco.Tests.Persistence.Repositories Content textpage = MockedContent.CreateSimpleContent(contentType); // Act - + contentTypeRepository.AddOrUpdate(contentType); repository.AddOrUpdate(textpage); unitOfWork.Commit(); @@ -520,7 +520,7 @@ namespace Umbraco.Tests.Persistence.Repositories var unitOfWork = provider.GetUnitOfWork(); ContentTypeRepository contentTypeRepository; using (var repository = CreateRepository(unitOfWork, out contentTypeRepository)) - { + { var result = repository.GetAll().ToArray(); foreach (var content in result) { @@ -555,7 +555,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var query = Query.Builder.Where(x => x.Level == 2); long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Ascending); + var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Ascending, orderBySystemField: true); // Assert Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2)); @@ -576,7 +576,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var query = Query.Builder.Where(x => x.Level == 2); long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 1, 1, out totalRecords, "Name", Direction.Ascending); + var result = repository.GetPagedResultsByQuery(query, 1, 1, out totalRecords, "Name", Direction.Ascending, orderBySystemField: true); // Assert Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2)); @@ -597,7 +597,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var query = Query.Builder.Where(x => x.Level == 2); long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 0, 2, out totalRecords, "Name", Direction.Ascending); + var result = repository.GetPagedResultsByQuery(query, 0, 2, out totalRecords, "Name", Direction.Ascending, orderBySystemField: true); // Assert Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2)); @@ -618,7 +618,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var query = Query.Builder.Where(x => x.Level == 2); long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Descending); + var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Descending, orderBySystemField: true); // Assert Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2)); @@ -639,7 +639,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var query = Query.Builder.Where(x => x.Level == 2); long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Ascending, "Page 2"); + var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Ascending, true, "Page 2"); // Assert Assert.That(totalRecords, Is.EqualTo(1)); @@ -660,7 +660,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var query = Query.Builder.Where(x => x.Level == 2); long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Ascending, "Page"); + var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Ascending, true, "Page"); // Assert Assert.That(totalRecords, Is.EqualTo(2)); diff --git a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs index 60c49f89cd..32258a9961 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs @@ -27,7 +27,7 @@ namespace Umbraco.Tests.Persistence.Repositories [SetUp] public override void Initialize() - { + { base.Initialize(); CreateTestData(); @@ -51,12 +51,12 @@ namespace Umbraco.Tests.Persistence.Repositories { var mediaType = mediaTypeRepository.Get(1032); - + for (var i = 0; i < 100; i++) { var image = MockedMedia.CreateMediaImage(mediaType, -1); repository.AddOrUpdate(image); - } + } unitOfWork.Commit(); //delete all xml @@ -81,7 +81,7 @@ namespace Umbraco.Tests.Persistence.Repositories var imageMediaType = mediaTypeRepository.Get(1032); var fileMediaType = mediaTypeRepository.Get(1033); var folderMediaType = mediaTypeRepository.Get(1031); - + for (var i = 0; i < 30; i++) { var image = MockedMedia.CreateMediaImage(imageMediaType, -1); @@ -103,12 +103,12 @@ namespace Umbraco.Tests.Persistence.Repositories unitOfWork.Database.Execute("DELETE FROM cmsContentXml"); Assert.AreEqual(0, unitOfWork.Database.ExecuteScalar("SELECT COUNT(*) FROM cmsContentXml")); - repository.RebuildXmlStructures(media => new XElement("test"), 10, contentTypeIds: new[] {1032, 1033}); + repository.RebuildXmlStructures(media => new XElement("test"), 10, contentTypeIds: new[] { 1032, 1033 }); Assert.AreEqual(62, unitOfWork.Database.ExecuteScalar("SELECT COUNT(*) FROM cmsContentXml")); } } - + [Test] public void Can_Perform_Add_On_MediaRepository() { @@ -207,7 +207,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var media = repository.Get(NodeDto.NodeIdSeed + 1); - bool dirty = ((ICanBeDirty) media).IsDirty(); + bool dirty = ((ICanBeDirty)media).IsDirty(); // Assert Assert.That(dirty, Is.False); @@ -319,7 +319,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var query = Query.Builder.Where(x => x.Level == 2); long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "SortOrder", Direction.Ascending); + var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "SortOrder", Direction.Ascending, orderBySystemField: true); // Assert Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2)); @@ -340,7 +340,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var query = Query.Builder.Where(x => x.Level == 2); long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 1, 1, out totalRecords, "SortOrder", Direction.Ascending); + var result = repository.GetPagedResultsByQuery(query, 1, 1, out totalRecords, "SortOrder", Direction.Ascending, orderBySystemField: true); // Assert Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2)); @@ -361,7 +361,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var query = Query.Builder.Where(x => x.Level == 2); long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 0, 2, out totalRecords, "SortOrder", Direction.Ascending); + var result = repository.GetPagedResultsByQuery(query, 0, 2, out totalRecords, "SortOrder", Direction.Ascending, orderBySystemField: true); // Assert Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2)); @@ -382,7 +382,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var query = Query.Builder.Where(x => x.Level == 2); long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "SortOrder", Direction.Descending); + var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "SortOrder", Direction.Descending, orderBySystemField: true); // Assert Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2)); @@ -403,7 +403,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var query = Query.Builder.Where(x => x.Level == 2); long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Ascending); + var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Ascending, orderBySystemField: true); // Assert Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2)); @@ -424,7 +424,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var query = Query.Builder.Where(x => x.Level == 2); long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "SortOrder", Direction.Ascending, "File"); + var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "SortOrder", Direction.Ascending, true, "File"); // Assert Assert.That(totalRecords, Is.EqualTo(1)); @@ -445,7 +445,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var query = Query.Builder.Where(x => x.Level == 2); long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "SortOrder", Direction.Ascending, "Test"); + var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "SortOrder", Direction.Ascending, true, "Test"); // Assert Assert.That(totalRecords, Is.EqualTo(2)); diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs index 6c56c76ef7..26f29b581b 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs @@ -20,33 +20,33 @@ using Version = Lucene.Net.Util.Version; namespace Umbraco.Tests.UmbracoExamine { - /// - /// Used internally by test classes to initialize a new index from the template - /// - internal static class IndexInitializer - { - public static UmbracoContentIndexer GetUmbracoIndexer( - Directory luceneDir, - Analyzer analyzer = null, - IDataService dataService = null, - IContentService contentService = null, - IMediaService mediaService = null, - IDataTypeService dataTypeService = null, - IMemberService memberService = null, - IUserService userService = null) - { + /// + /// Used internally by test classes to initialize a new index from the template + /// + internal static class IndexInitializer + { + public static UmbracoContentIndexer GetUmbracoIndexer( + Directory luceneDir, + Analyzer analyzer = null, + IDataService dataService = null, + IContentService contentService = null, + IMediaService mediaService = null, + IDataTypeService dataTypeService = null, + IMemberService memberService = null, + IUserService userService = null) + { if (dataService == null) { dataService = new TestDataService(); } - if (contentService == null) - { + if (contentService == null) + { contentService = Mock.Of(); - } - if (userService == null) - { - userService = Mock.Of(x => x.GetProfileById(It.IsAny()) == Mock.Of(p => p.Id == (object)0 && p.Name == "admin")); - } + } + if (userService == null) + { + userService = Mock.Of(x => x.GetProfileById(It.IsAny()) == Mock.Of(p => p.Id == (object)0 && p.Name == "admin")); + } if (mediaService == null) { long totalRecs; @@ -56,25 +56,25 @@ namespace Umbraco.Tests.UmbracoExamine .Elements() .Select(x => Mock.Of( m => - m.Id == (int) x.Attribute("id") && - m.ParentId == (int) x.Attribute("parentID") && - m.Level == (int) x.Attribute("level") && + m.Id == (int)x.Attribute("id") && + m.ParentId == (int)x.Attribute("parentID") && + m.Level == (int)x.Attribute("level") && m.CreatorId == 0 && - m.SortOrder == (int) x.Attribute("sortOrder") && - m.CreateDate == (DateTime) x.Attribute("createDate") && - m.UpdateDate == (DateTime) x.Attribute("updateDate") && - m.Name == (string) x.Attribute("nodeName") && - m.Path == (string) x.Attribute("path") && + m.SortOrder == (int)x.Attribute("sortOrder") && + m.CreateDate == (DateTime)x.Attribute("createDate") && + m.UpdateDate == (DateTime)x.Attribute("updateDate") && + m.Name == (string)x.Attribute("nodeName") && + m.Path == (string)x.Attribute("path") && m.Properties == new PropertyCollection() && m.ContentType == Mock.Of(mt => - mt.Alias == (string) x.Attribute("nodeTypeAlias") && - mt.Id == (int) x.Attribute("nodeType")))) + mt.Alias == (string)x.Attribute("nodeTypeAlias") && + mt.Id == (int)x.Attribute("nodeType")))) .ToArray(); - + mediaService = Mock.Of( x => x.GetPagedDescendants( - It.IsAny(), It.IsAny(), It.IsAny(), out totalRecs, It.IsAny(), It.IsAny(), It.IsAny()) + It.IsAny(), It.IsAny(), It.IsAny(), out totalRecs, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()) == allRecs); } @@ -82,7 +82,7 @@ namespace Umbraco.Tests.UmbracoExamine { dataTypeService = Mock.Of(); } - + if (memberService == null) { memberService = Mock.Of(); @@ -93,51 +93,51 @@ namespace Umbraco.Tests.UmbracoExamine analyzer = new StandardAnalyzer(Version.LUCENE_29); } - var indexSet = new IndexSet(); + var indexSet = new IndexSet(); var indexCriteria = indexSet.ToIndexCriteria(dataService, UmbracoContentIndexer.IndexFieldPolicies); - var i = new UmbracoContentIndexer(indexCriteria, - luceneDir, //custom lucene directory - dataService, - contentService, - mediaService, - dataTypeService, - userService, - analyzer, - false); + var i = new UmbracoContentIndexer(indexCriteria, + luceneDir, //custom lucene directory + dataService, + contentService, + mediaService, + dataTypeService, + userService, + analyzer, + false); - //i.IndexSecondsInterval = 1; + //i.IndexSecondsInterval = 1; - i.IndexingError += IndexingError; + i.IndexingError += IndexingError; - return i; - } + return i; + } public static UmbracoExamineSearcher GetUmbracoSearcher(Directory luceneDir, Analyzer analyzer = null) - { + { if (analyzer == null) { analyzer = new StandardAnalyzer(Version.LUCENE_29); } return new UmbracoExamineSearcher(luceneDir, analyzer); - } - - public static LuceneSearcher GetLuceneSearcher(Directory luceneDir) - { - return new LuceneSearcher(luceneDir, new StandardAnalyzer(Version.LUCENE_29)); - } - - public static MultiIndexSearcher GetMultiSearcher(Directory pdfDir, Directory simpleDir, Directory conventionDir, Directory cwsDir) - { - var i = new MultiIndexSearcher(new[] { pdfDir, simpleDir, conventionDir, cwsDir }, new StandardAnalyzer(Version.LUCENE_29)); - return i; - } + } + + public static LuceneSearcher GetLuceneSearcher(Directory luceneDir) + { + return new LuceneSearcher(luceneDir, new StandardAnalyzer(Version.LUCENE_29)); + } + + public static MultiIndexSearcher GetMultiSearcher(Directory pdfDir, Directory simpleDir, Directory conventionDir, Directory cwsDir) + { + var i = new MultiIndexSearcher(new[] { pdfDir, simpleDir, conventionDir, cwsDir }, new StandardAnalyzer(Version.LUCENE_29)); + return i; + } - internal static void IndexingError(object sender, IndexingErrorEventArgs e) - { - throw new ApplicationException(e.Message, e.InnerException); - } + internal static void IndexingError(object sender, IndexingErrorEventArgs e) + { + throw new ApplicationException(e.Message, e.InnerException); + } - } + } } \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbtable.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbtable.directive.js index fe80d915da..bf593397b6 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbtable.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbtable.directive.js @@ -1,71 +1,71 @@ -(function() { - 'use strict'; - - function TableDirective() { - - function link(scope, el, attr, ctrl) { - - scope.clickItem = function(item, $event) { - if(scope.onClick) { - scope.onClick(item); - $event.stopPropagation(); - } - }; - - scope.selectItem = function(item, $index, $event) { - if(scope.onSelect) { - scope.onSelect(item, $index, $event); - $event.stopPropagation(); - } - }; - - scope.selectAll = function($event) { - if(scope.onSelectAll) { - scope.onSelectAll($event); - } - }; - - scope.isSelectedAll = function() { - if(scope.onSelectedAll && scope.items && scope.items.length > 0) { - return scope.onSelectedAll(); - } - }; - - scope.isSortDirection = function (col, direction) { - if (scope.onSortingDirection) { - return scope.onSortingDirection(col, direction); - } - }; - - scope.sort = function(field, allow) { - if(scope.onSort) { - scope.onSort(field, allow); - } - }; - - } - - var directive = { - restrict: 'E', - replace: true, - templateUrl: 'views/components/umb-table.html', - scope: { - items: '=', - itemProperties: '=', - allowSelectAll: '=', - onSelect: '=', - onClick: '=', - onSelectAll: '=', - onSelectedAll: '=', - onSortingDirection: '=', - onSort: '=' - }, - link: link - }; - - return directive; - } - - angular.module('umbraco.directives').directive('umbTable', TableDirective); - -})(); +(function () { + 'use strict'; + + function TableDirective() { + + function link(scope, el, attr, ctrl) { + + scope.clickItem = function (item, $event) { + if (scope.onClick) { + scope.onClick(item); + $event.stopPropagation(); + } + }; + + scope.selectItem = function (item, $index, $event) { + if (scope.onSelect) { + scope.onSelect(item, $index, $event); + $event.stopPropagation(); + } + }; + + scope.selectAll = function ($event) { + if (scope.onSelectAll) { + scope.onSelectAll($event); + } + }; + + scope.isSelectedAll = function () { + if (scope.onSelectedAll && scope.items && scope.items.length > 0) { + return scope.onSelectedAll(); + } + }; + + scope.isSortDirection = function (col, direction) { + if (scope.onSortingDirection) { + return scope.onSortingDirection(col, direction); + } + }; + + scope.sort = function (field, allow, isSystem) { + if (scope.onSort) { + scope.onSort(field, allow, isSystem); + } + }; + + } + + var directive = { + restrict: 'E', + replace: true, + templateUrl: 'views/components/umb-table.html', + scope: { + items: '=', + itemProperties: '=', + allowSelectAll: '=', + onSelect: '=', + onClick: '=', + onSelectAll: '=', + onSelectedAll: '=', + onSortingDirection: '=', + onSort: '=' + }, + link: link + }; + + return directive; + } + + angular.module('umbraco.directives').directive('umbTable', TableDirective); + +})(); 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 2cf7127707..60ecd16f19 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 @@ -25,634 +25,636 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) { - /** internal method process the saving of data and post processing the result */ - function saveContentItem(content, action, files) { - return umbRequestHelper.postSaveContent({ - restApiUrl: umbRequestHelper.getApiUrl( + /** internal method process the saving of data and post processing the result */ + function saveContentItem(content, action, files) { + return umbRequestHelper.postSaveContent({ + restApiUrl: umbRequestHelper.getApiUrl( "contentApiBaseUrl", "PostSave"), - content: content, - action: action, - files: files, - dataFormatter: function (c, a) { - return umbDataFormatter.formatContentPostData(c, a); - } - }); - } + content: content, + action: action, + files: files, + dataFormatter: function (c, a) { + return umbDataFormatter.formatContentPostData(c, a); + } + }); + } - return { - - getRecycleBin: function() { - return umbRequestHelper.resourcePromise( + return { + + getRecycleBin: function () { + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "GetRecycleBin")), + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "GetRecycleBin")), 'Failed to retrieve data for content recycle bin'); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.contentResource#sort - * @methodOf umbraco.resources.contentResource - * - * @description - * Sorts all children below a given parent node id, based on a collection of node-ids - * - * ##usage - *
-         * var ids = [123,34533,2334,23434];
-         * contentResource.sort({ parentId: 1244, sortedIds: ids })
-         *    .then(function() {
-         *        $scope.complete = true;
-         *    });
-         * 
- * @param {Object} args arguments object - * @param {Int} args.parentId the ID of the parent node - * @param {Array} options.sortedIds array of node IDs as they should be sorted - * @returns {Promise} resourcePromise object. - * - */ - sort: function (args) { - if (!args) { - throw "args cannot be null"; - } - if (!args.parentId) { - throw "args.parentId cannot be null"; - } - if (!args.sortedIds) { - throw "args.sortedIds cannot be null"; - } + /** + * @ngdoc method + * @name umbraco.resources.contentResource#sort + * @methodOf umbraco.resources.contentResource + * + * @description + * Sorts all children below a given parent node id, based on a collection of node-ids + * + * ##usage + *
+        * var ids = [123,34533,2334,23434];
+        * contentResource.sort({ parentId: 1244, sortedIds: ids })
+        *    .then(function() {
+        *        $scope.complete = true;
+        *    });
+        * 
+ * @param {Object} args arguments object + * @param {Int} args.parentId the ID of the parent node + * @param {Array} options.sortedIds array of node IDs as they should be sorted + * @returns {Promise} resourcePromise object. + * + */ + sort: function (args) { + if (!args) { + throw "args cannot be null"; + } + if (!args.parentId) { + throw "args.parentId cannot be null"; + } + if (!args.sortedIds) { + throw "args.sortedIds cannot be null"; + } - return umbRequestHelper.resourcePromise( + return umbRequestHelper.resourcePromise( $http.post(umbRequestHelper.getApiUrl("contentApiBaseUrl", "PostSort"), - { - parentId: args.parentId, - idSortOrder: args.sortedIds - }), + { + parentId: args.parentId, + idSortOrder: args.sortedIds + }), 'Failed to sort content'); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.contentResource#move - * @methodOf umbraco.resources.contentResource - * - * @description - * Moves a node underneath a new parentId - * - * ##usage - *
-         * contentResource.move({ parentId: 1244, id: 123 })
-         *    .then(function() {
-         *        alert("node was moved");
-         *    }, function(err){
-         *      alert("node didnt move:" + err.data.Message); 
-         *    });
-         * 
- * @param {Object} args arguments object - * @param {Int} args.idd the ID of the node to move - * @param {Int} args.parentId the ID of the parent node to move to - * @returns {Promise} resourcePromise object. - * - */ - move: function (args) { - if (!args) { - throw "args cannot be null"; - } - if (!args.parentId) { - throw "args.parentId cannot be null"; - } - if (!args.id) { - throw "args.id cannot be null"; - } + /** + * @ngdoc method + * @name umbraco.resources.contentResource#move + * @methodOf umbraco.resources.contentResource + * + * @description + * Moves a node underneath a new parentId + * + * ##usage + *
+        * contentResource.move({ parentId: 1244, id: 123 })
+        *    .then(function() {
+        *        alert("node was moved");
+        *    }, function(err){
+        *      alert("node didnt move:" + err.data.Message); 
+        *    });
+        * 
+ * @param {Object} args arguments object + * @param {Int} args.idd the ID of the node to move + * @param {Int} args.parentId the ID of the parent node to move to + * @returns {Promise} resourcePromise object. + * + */ + move: function (args) { + if (!args) { + throw "args cannot be null"; + } + if (!args.parentId) { + throw "args.parentId cannot be null"; + } + if (!args.id) { + throw "args.id cannot be null"; + } - return umbRequestHelper.resourcePromise( + return umbRequestHelper.resourcePromise( $http.post(umbRequestHelper.getApiUrl("contentApiBaseUrl", "PostMove"), - { - parentId: args.parentId, - id: args.id - }), + { + parentId: args.parentId, + id: args.id + }), 'Failed to move content'); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.contentResource#copy - * @methodOf umbraco.resources.contentResource - * - * @description - * Copies a node underneath a new parentId - * - * ##usage - *
-         * contentResource.copy({ parentId: 1244, id: 123 })
-         *    .then(function() {
-         *        alert("node was copied");
-         *    }, function(err){
-         *      alert("node wasnt copy:" + err.data.Message); 
-         *    });
-         * 
- * @param {Object} args arguments object - * @param {Int} args.id the ID of the node to copy - * @param {Int} args.parentId the ID of the parent node to copy to - * @param {Boolean} args.relateToOriginal if true, relates the copy to the original through the relation api - * @returns {Promise} resourcePromise object. - * - */ - copy: function (args) { - if (!args) { - throw "args cannot be null"; - } - if (!args.parentId) { - throw "args.parentId cannot be null"; - } - if (!args.id) { - throw "args.id cannot be null"; - } + /** + * @ngdoc method + * @name umbraco.resources.contentResource#copy + * @methodOf umbraco.resources.contentResource + * + * @description + * Copies a node underneath a new parentId + * + * ##usage + *
+        * contentResource.copy({ parentId: 1244, id: 123 })
+        *    .then(function() {
+        *        alert("node was copied");
+        *    }, function(err){
+        *      alert("node wasnt copy:" + err.data.Message); 
+        *    });
+        * 
+ * @param {Object} args arguments object + * @param {Int} args.id the ID of the node to copy + * @param {Int} args.parentId the ID of the parent node to copy to + * @param {Boolean} args.relateToOriginal if true, relates the copy to the original through the relation api + * @returns {Promise} resourcePromise object. + * + */ + copy: function (args) { + if (!args) { + throw "args cannot be null"; + } + if (!args.parentId) { + throw "args.parentId cannot be null"; + } + if (!args.id) { + throw "args.id cannot be null"; + } - return umbRequestHelper.resourcePromise( + return umbRequestHelper.resourcePromise( $http.post(umbRequestHelper.getApiUrl("contentApiBaseUrl", "PostCopy"), - args), + args), 'Failed to copy content'); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.contentResource#unPublish - * @methodOf umbraco.resources.contentResource - * - * @description - * Unpublishes a content item with a given Id - * - * ##usage - *
-         * contentResource.unPublish(1234)
-         *    .then(function() {
-         *        alert("node was unpulished");
-         *    }, function(err){
-         *      alert("node wasnt unpublished:" + err.data.Message); 
-         *    });
-         * 
- * @param {Int} id the ID of the node to unpublish - * @returns {Promise} resourcePromise object. - * - */ - unPublish: function (id) { - if (!id) { - throw "id cannot be null"; - } - - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "PostUnPublish", - [{ id: id }])), - 'Failed to publish content with id ' + id); - }, - /** - * @ngdoc method - * @name umbraco.resources.contentResource#emptyRecycleBin - * @methodOf umbraco.resources.contentResource - * - * @description - * Empties the content recycle bin - * - * ##usage - *
-         * contentResource.emptyRecycleBin()
-         *    .then(function() {
-         *        alert('its empty!');
-         *    });
-         * 
- * - * @returns {Promise} resourcePromise object. - * - */ - emptyRecycleBin: function() { - return umbRequestHelper.resourcePromise( + /** + * @ngdoc method + * @name umbraco.resources.contentResource#unPublish + * @methodOf umbraco.resources.contentResource + * + * @description + * Unpublishes a content item with a given Id + * + * ##usage + *
+        * contentResource.unPublish(1234)
+        *    .then(function() {
+        *        alert("node was unpulished");
+        *    }, function(err){
+        *      alert("node wasnt unpublished:" + err.data.Message); 
+        *    });
+        * 
+ * @param {Int} id the ID of the node to unpublish + * @returns {Promise} resourcePromise object. + * + */ + unPublish: function (id) { + if (!id) { + throw "id cannot be null"; + } + + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "PostUnPublish", + [{ id: id }])), + 'Failed to publish content with id ' + id); + }, + /** + * @ngdoc method + * @name umbraco.resources.contentResource#emptyRecycleBin + * @methodOf umbraco.resources.contentResource + * + * @description + * Empties the content recycle bin + * + * ##usage + *
+        * contentResource.emptyRecycleBin()
+        *    .then(function() {
+        *        alert('its empty!');
+        *    });
+        * 
+ * + * @returns {Promise} resourcePromise object. + * + */ + emptyRecycleBin: function () { + return umbRequestHelper.resourcePromise( $http.post( - umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "EmptyRecycleBin")), + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "EmptyRecycleBin")), 'Failed to empty the recycle bin'); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.contentResource#deleteById - * @methodOf umbraco.resources.contentResource - * - * @description - * Deletes a content item with a given id - * - * ##usage - *
-         * contentResource.deleteById(1234)
-         *    .then(function() {
-         *        alert('its gone!');
-         *    });
-         * 
- * - * @param {Int} id id of content item to delete - * @returns {Promise} resourcePromise object. - * - */ - deleteById: function(id) { - return umbRequestHelper.resourcePromise( + /** + * @ngdoc method + * @name umbraco.resources.contentResource#deleteById + * @methodOf umbraco.resources.contentResource + * + * @description + * Deletes a content item with a given id + * + * ##usage + *
+        * contentResource.deleteById(1234)
+        *    .then(function() {
+        *        alert('its gone!');
+        *    });
+        * 
+ * + * @param {Int} id id of content item to delete + * @returns {Promise} resourcePromise object. + * + */ + deleteById: function (id) { + return umbRequestHelper.resourcePromise( $http.post( - umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "DeleteById", - [{ id: id }])), + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "DeleteById", + [{ id: id }])), 'Failed to delete item ' + id); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.contentResource#getById - * @methodOf umbraco.resources.contentResource - * - * @description - * Gets a content item with a given id - * - * ##usage - *
-         * contentResource.getById(1234)
-         *    .then(function(content) {
-         *        var myDoc = content; 
-         *        alert('its here!');
-         *    });
-         * 
- * - * @param {Int} id id of content item to return - * @returns {Promise} resourcePromise object containing the content item. - * - */ - getById: function (id) { - return umbRequestHelper.resourcePromise( + /** + * @ngdoc method + * @name umbraco.resources.contentResource#getById + * @methodOf umbraco.resources.contentResource + * + * @description + * Gets a content item with a given id + * + * ##usage + *
+        * contentResource.getById(1234)
+        *    .then(function(content) {
+        *        var myDoc = content; 
+        *        alert('its here!');
+        *    });
+        * 
+ * + * @param {Int} id id of content item to return + * @returns {Promise} resourcePromise object containing the content item. + * + */ + getById: function (id) { + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "GetById", - [{ id: id }])), + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "GetById", + [{ id: id }])), 'Failed to retrieve data for content id ' + id); - }, - - /** - * @ngdoc method - * @name umbraco.resources.contentResource#getByIds - * @methodOf umbraco.resources.contentResource - * - * @description - * Gets an array of content items, given a collection of ids - * - * ##usage - *
-         * contentResource.getByIds( [1234,2526,28262])
-         *    .then(function(contentArray) {
-         *        var myDoc = contentArray; 
-         *        alert('they are here!');
-         *    });
-         * 
- * - * @param {Array} ids ids of content items to return as an array - * @returns {Promise} resourcePromise object containing the content items array. - * - */ - getByIds: function (ids) { - - var idQuery = ""; - _.each(ids, function(item) { - idQuery += "ids=" + item + "&"; - }); + }, - return umbRequestHelper.resourcePromise( + /** + * @ngdoc method + * @name umbraco.resources.contentResource#getByIds + * @methodOf umbraco.resources.contentResource + * + * @description + * Gets an array of content items, given a collection of ids + * + * ##usage + *
+        * contentResource.getByIds( [1234,2526,28262])
+        *    .then(function(contentArray) {
+        *        var myDoc = contentArray; 
+        *        alert('they are here!');
+        *    });
+        * 
+ * + * @param {Array} ids ids of content items to return as an array + * @returns {Promise} resourcePromise object containing the content items array. + * + */ + getByIds: function (ids) { + + var idQuery = ""; + _.each(ids, function (item) { + idQuery += "ids=" + item + "&"; + }); + + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "GetByIds", - idQuery)), + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "GetByIds", + idQuery)), 'Failed to retrieve data for content with multiple ids'); - }, + }, - - /** - * @ngdoc method - * @name umbraco.resources.contentResource#getScaffold - * @methodOf umbraco.resources.contentResource - * - * @description - * Returns a scaffold of an empty content item, given the id of the content item to place it underneath and the content type alias. - * - * - Parent Id must be provided so umbraco knows where to store the content - * - Content Type alias must be provided so umbraco knows which properties to put on the content scaffold - * - * The scaffold is used to build editors for content that has not yet been populated with data. - * - * ##usage - *
-         * contentResource.getScaffold(1234, 'homepage')
-         *    .then(function(scaffold) {
-         *        var myDoc = scaffold;
-         *        myDoc.name = "My new document"; 
-         *
-         *        contentResource.publish(myDoc, true)
-         *            .then(function(content){
-         *                alert("Retrieved, updated and published again");
-         *            });
-         *    });
-         * 
- * - * @param {Int} parentId id of content item to return - * @param {String} alias contenttype alias to base the scaffold on - * @returns {Promise} resourcePromise object containing the content scaffold. - * - */ - getScaffold: function (parentId, alias) { - - return umbRequestHelper.resourcePromise( + + /** + * @ngdoc method + * @name umbraco.resources.contentResource#getScaffold + * @methodOf umbraco.resources.contentResource + * + * @description + * Returns a scaffold of an empty content item, given the id of the content item to place it underneath and the content type alias. + * + * - Parent Id must be provided so umbraco knows where to store the content + * - Content Type alias must be provided so umbraco knows which properties to put on the content scaffold + * + * The scaffold is used to build editors for content that has not yet been populated with data. + * + * ##usage + *
+        * contentResource.getScaffold(1234, 'homepage')
+        *    .then(function(scaffold) {
+        *        var myDoc = scaffold;
+        *        myDoc.name = "My new document"; 
+        *
+        *        contentResource.publish(myDoc, true)
+        *            .then(function(content){
+        *                alert("Retrieved, updated and published again");
+        *            });
+        *    });
+        * 
+ * + * @param {Int} parentId id of content item to return + * @param {String} alias contenttype alias to base the scaffold on + * @returns {Promise} resourcePromise object containing the content scaffold. + * + */ + getScaffold: function (parentId, alias) { + + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "GetEmpty", - [{ contentTypeAlias: alias }, { parentId: parentId }])), + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "GetEmpty", + [{ contentTypeAlias: alias }, { parentId: parentId }])), 'Failed to retrieve data for empty content item type ' + alias); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.contentResource#getNiceUrl - * @methodOf umbraco.resources.contentResource - * - * @description - * Returns a url, given a node ID - * - * ##usage - *
-         * contentResource.getNiceUrl(id)
-         *    .then(function(url) {
-         *        alert('its here!');
-         *    });
-         * 
- * - * @param {Int} id Id of node to return the public url to - * @returns {Promise} resourcePromise object containing the url. - * - */ - getNiceUrl: function (id) { - return umbRequestHelper.resourcePromise( + /** + * @ngdoc method + * @name umbraco.resources.contentResource#getNiceUrl + * @methodOf umbraco.resources.contentResource + * + * @description + * Returns a url, given a node ID + * + * ##usage + *
+        * contentResource.getNiceUrl(id)
+        *    .then(function(url) {
+        *        alert('its here!');
+        *    });
+        * 
+ * + * @param {Int} id Id of node to return the public url to + * @returns {Promise} resourcePromise object containing the url. + * + */ + getNiceUrl: function (id) { + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "GetNiceUrl",[{id: id}])), + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "GetNiceUrl", [{ id: id }])), 'Failed to retrieve url for id:' + id); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.contentResource#getChildren - * @methodOf umbraco.resources.contentResource - * - * @description - * Gets children of a content item with a given id - * - * ##usage - *
-         * contentResource.getChildren(1234, {pageSize: 10, pageNumber: 2})
-         *    .then(function(contentArray) {
-         *        var children = contentArray; 
-         *        alert('they are here!');
-         *    });
-         * 
- * - * @param {Int} parentid id of content item to return children of - * @param {Object} options optional options object - * @param {Int} options.pageSize if paging data, number of nodes per page, default = 0 - * @param {Int} options.pageNumber if paging data, current page index, default = 0 - * @param {String} options.filter if provided, query will only return those with names matching the filter - * @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Ascending` - * @param {String} options.orderBy property to order items by, default: `SortOrder` - * @returns {Promise} resourcePromise object containing an array of content items. - * - */ - getChildren: function (parentId, options) { + /** + * @ngdoc method + * @name umbraco.resources.contentResource#getChildren + * @methodOf umbraco.resources.contentResource + * + * @description + * Gets children of a content item with a given id + * + * ##usage + *
+        * contentResource.getChildren(1234, {pageSize: 10, pageNumber: 2})
+        *    .then(function(contentArray) {
+        *        var children = contentArray; 
+        *        alert('they are here!');
+        *    });
+        * 
+ * + * @param {Int} parentid id of content item to return children of + * @param {Object} options optional options object + * @param {Int} options.pageSize if paging data, number of nodes per page, default = 0 + * @param {Int} options.pageNumber if paging data, current page index, default = 0 + * @param {String} options.filter if provided, query will only return those with names matching the filter + * @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Ascending` + * @param {String} options.orderBy property to order items by, default: `SortOrder` + * @returns {Promise} resourcePromise object containing an array of content items. + * + */ + getChildren: function (parentId, options) { - var defaults = { - pageSize: 0, - pageNumber: 0, - filter: '', - orderDirection: "Ascending", - orderBy: "SortOrder" - }; - 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; - //change asc/desct - if (options.orderDirection === "asc") { - options.orderDirection = "Ascending"; - } - else if (options.orderDirection === "desc") { - options.orderDirection = "Descending"; - } + var defaults = { + pageSize: 0, + pageNumber: 0, + filter: '', + orderDirection: "Ascending", + orderBy: "SortOrder", + orderBySystemField: true + }; + 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; + //change asc/desct + if (options.orderDirection === "asc") { + options.orderDirection = "Ascending"; + } + else if (options.orderDirection === "desc") { + options.orderDirection = "Descending"; + } - return umbRequestHelper.resourcePromise( + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "GetChildren", - [ - { id: parentId }, - { pageNumber: options.pageNumber }, - { pageSize: options.pageSize }, - { orderBy: options.orderBy }, - { orderDirection: options.orderDirection }, - { filter: options.filter } - ])), + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "GetChildren", + [ + { id: parentId }, + { pageNumber: options.pageNumber }, + { pageSize: options.pageSize }, + { orderBy: options.orderBy }, + { orderDirection: options.orderDirection }, + { orderBySystemField: options.orderBySystemField }, + { filter: options.filter } + ])), 'Failed to retrieve children for content item ' + parentId); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.contentResource#hasPermission - * @methodOf umbraco.resources.contentResource - * - * @description - * Returns true/false given a permission char to check against a nodeID - * for the current user - * - * ##usage - *
-         * contentResource.hasPermission('p',1234)
-         *    .then(function() {
-         *        alert('You are allowed to publish this item');
-         *    });
-         * 
- * - * @param {String} permission char representing the permission to check - * @param {Int} id id of content item to delete - * @returns {Promise} resourcePromise object. - * - */ - checkPermission: function(permission, id) { - return umbRequestHelper.resourcePromise( + /** + * @ngdoc method + * @name umbraco.resources.contentResource#hasPermission + * @methodOf umbraco.resources.contentResource + * + * @description + * Returns true/false given a permission char to check against a nodeID + * for the current user + * + * ##usage + *
+        * contentResource.hasPermission('p',1234)
+        *    .then(function() {
+        *        alert('You are allowed to publish this item');
+        *    });
+        * 
+ * + * @param {String} permission char representing the permission to check + * @param {Int} id id of content item to delete + * @returns {Promise} resourcePromise object. + * + */ + checkPermission: function (permission, id) { + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "HasPermission", - [{ permissionToCheck: permission },{ nodeId: id }])), + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "HasPermission", + [{ permissionToCheck: permission }, { nodeId: id }])), 'Failed to check permission for item ' + id); - }, + }, - getPermissions: function (nodeIds) { - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "GetPermissions"), - nodeIds), - 'Failed to get permissions'); - }, + getPermissions: function (nodeIds) { + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "GetPermissions"), + nodeIds), + 'Failed to get permissions'); + }, - /** - * @ngdoc method - * @name umbraco.resources.contentResource#save - * @methodOf umbraco.resources.contentResource - * - * @description - * Saves changes made to a content item to its current version, if the content item is new, the isNew paramater must be passed to force creation - * if the content item needs to have files attached, they must be provided as the files param and passed separately - * - * - * ##usage - *
-         * contentResource.getById(1234)
-         *    .then(function(content) {
-         *          content.name = "I want a new name!";
-         *          contentResource.save(content, false)
-         *            .then(function(content){
-         *                alert("Retrieved, updated and saved again");
-         *            });
-         *    });
-         * 
- * - * @param {Object} content The content item object with changes applied - * @param {Bool} isNew set to true to create a new item or to update an existing - * @param {Array} files collection of files for the document - * @returns {Promise} resourcePromise object containing the saved content item. - * - */ - save: function (content, isNew, files) { - return saveContentItem(content, "save" + (isNew ? "New" : ""), files); - }, + /** + * @ngdoc method + * @name umbraco.resources.contentResource#save + * @methodOf umbraco.resources.contentResource + * + * @description + * Saves changes made to a content item to its current version, if the content item is new, the isNew paramater must be passed to force creation + * if the content item needs to have files attached, they must be provided as the files param and passed separately + * + * + * ##usage + *
+        * contentResource.getById(1234)
+        *    .then(function(content) {
+        *          content.name = "I want a new name!";
+        *          contentResource.save(content, false)
+        *            .then(function(content){
+        *                alert("Retrieved, updated and saved again");
+        *            });
+        *    });
+        * 
+ * + * @param {Object} content The content item object with changes applied + * @param {Bool} isNew set to true to create a new item or to update an existing + * @param {Array} files collection of files for the document + * @returns {Promise} resourcePromise object containing the saved content item. + * + */ + save: function (content, isNew, files) { + return saveContentItem(content, "save" + (isNew ? "New" : ""), files); + }, - /** - * @ngdoc method - * @name umbraco.resources.contentResource#publish - * @methodOf umbraco.resources.contentResource - * - * @description - * Saves and publishes changes made to a content item to a new version, if the content item is new, the isNew paramater must be passed to force creation - * if the content item needs to have files attached, they must be provided as the files param and passed separately - * - * - * ##usage - *
-         * contentResource.getById(1234)
-         *    .then(function(content) {
-         *          content.name = "I want a new name, and be published!";
-         *          contentResource.publish(content, false)
-         *            .then(function(content){
-         *                alert("Retrieved, updated and published again");
-         *            });
-         *    });
-         * 
- * - * @param {Object} content The content item object with changes applied - * @param {Bool} isNew set to true to create a new item or to update an existing - * @param {Array} files collection of files for the document - * @returns {Promise} resourcePromise object containing the saved content item. - * - */ - publish: function (content, isNew, files) { - return saveContentItem(content, "publish" + (isNew ? "New" : ""), files); - }, - - - /** - * @ngdoc method - * @name umbraco.resources.contentResource#sendToPublish - * @methodOf umbraco.resources.contentResource - * - * @description - * Saves changes made to a content item, and notifies any subscribers about a pending publication - * - * ##usage - *
-         * contentResource.getById(1234)
-         *    .then(function(content) {
-         *          content.name = "I want a new name, and be published!";
-         *          contentResource.sendToPublish(content, false)
-         *            .then(function(content){
-         *                alert("Retrieved, updated and notication send off");
-         *            });
-         *    });
-         * 
- * - * @param {Object} content The content item object with changes applied - * @param {Bool} isNew set to true to create a new item or to update an existing - * @param {Array} files collection of files for the document - * @returns {Promise} resourcePromise object containing the saved content item. - * - */ - sendToPublish: function (content, isNew, files) { - return saveContentItem(content, "sendPublish" + (isNew ? "New" : ""), files); - }, - - /** - * @ngdoc method - * @name umbraco.resources.contentResource#publishByid - * @methodOf umbraco.resources.contentResource - * - * @description - * Publishes a content item with a given ID - * - * ##usage - *
-         * contentResource.publishById(1234)
-         *    .then(function(content) {
-         *        alert("published");
-         *    });
-         * 
- * - * @param {Int} id The ID of the conten to publish - * @returns {Promise} resourcePromise object containing the published content item. - * - */ - publishById: function(id){ - - if (!id) { - throw "id cannot be null"; - } - - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "PostPublishById", - [{ id: id }])), - 'Failed to publish content with id ' + id); - - } + /** + * @ngdoc method + * @name umbraco.resources.contentResource#publish + * @methodOf umbraco.resources.contentResource + * + * @description + * Saves and publishes changes made to a content item to a new version, if the content item is new, the isNew paramater must be passed to force creation + * if the content item needs to have files attached, they must be provided as the files param and passed separately + * + * + * ##usage + *
+        * contentResource.getById(1234)
+        *    .then(function(content) {
+        *          content.name = "I want a new name, and be published!";
+        *          contentResource.publish(content, false)
+        *            .then(function(content){
+        *                alert("Retrieved, updated and published again");
+        *            });
+        *    });
+        * 
+ * + * @param {Object} content The content item object with changes applied + * @param {Bool} isNew set to true to create a new item or to update an existing + * @param {Array} files collection of files for the document + * @returns {Promise} resourcePromise object containing the saved content item. + * + */ + publish: function (content, isNew, files) { + return saveContentItem(content, "publish" + (isNew ? "New" : ""), files); + }, - }; + /** + * @ngdoc method + * @name umbraco.resources.contentResource#sendToPublish + * @methodOf umbraco.resources.contentResource + * + * @description + * Saves changes made to a content item, and notifies any subscribers about a pending publication + * + * ##usage + *
+        * contentResource.getById(1234)
+        *    .then(function(content) {
+        *          content.name = "I want a new name, and be published!";
+        *          contentResource.sendToPublish(content, false)
+        *            .then(function(content){
+        *                alert("Retrieved, updated and notication send off");
+        *            });
+        *    });
+        * 
+ * + * @param {Object} content The content item object with changes applied + * @param {Bool} isNew set to true to create a new item or to update an existing + * @param {Array} files collection of files for the document + * @returns {Promise} resourcePromise object containing the saved content item. + * + */ + sendToPublish: function (content, isNew, files) { + return saveContentItem(content, "sendPublish" + (isNew ? "New" : ""), files); + }, + + /** + * @ngdoc method + * @name umbraco.resources.contentResource#publishByid + * @methodOf umbraco.resources.contentResource + * + * @description + * Publishes a content item with a given ID + * + * ##usage + *
+        * contentResource.publishById(1234)
+        *    .then(function(content) {
+        *        alert("published");
+        *    });
+        * 
+ * + * @param {Int} id The ID of the conten to publish + * @returns {Promise} resourcePromise object containing the published content item. + * + */ + publishById: function (id) { + + if (!id) { + throw "id cannot be null"; + } + + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "PostPublishById", + [{ id: id }])), + 'Failed to publish content with id ' + id); + + } + + + }; } angular.module('umbraco.resources').factory('contentResource', contentResource); 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 9a2310299f..a85b2cc104 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 @@ -4,470 +4,472 @@ * @description Loads in data for media **/ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { - - /** internal method process the saving of data and post processing the result */ - function saveMediaItem(content, action, files) { - return umbRequestHelper.postSaveContent({ - restApiUrl: umbRequestHelper.getApiUrl( + + /** internal method process the saving of data and post processing the result */ + function saveMediaItem(content, action, files) { + return umbRequestHelper.postSaveContent({ + restApiUrl: umbRequestHelper.getApiUrl( "mediaApiBaseUrl", "PostSave"), - content: content, - action: action, - files: files, - dataFormatter: function (c, a) { - return umbDataFormatter.formatMediaPostData(c, a); - } - }); - } + content: content, + action: action, + files: files, + dataFormatter: function (c, a) { + return umbDataFormatter.formatMediaPostData(c, a); + } + }); + } - return { - - getRecycleBin: function () { - return umbRequestHelper.resourcePromise( + return { + + getRecycleBin: function () { + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "mediaApiBaseUrl", - "GetRecycleBin")), + umbRequestHelper.getApiUrl( + "mediaApiBaseUrl", + "GetRecycleBin")), 'Failed to retrieve data for media recycle bin'); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.mediaResource#sort - * @methodOf umbraco.resources.mediaResource - * - * @description - * Sorts all children below a given parent node id, based on a collection of node-ids - * - * ##usage - *
-         * var ids = [123,34533,2334,23434];
-         * mediaResource.sort({ sortedIds: ids })
-         *    .then(function() {
-         *        $scope.complete = true;
-         *    });
-         * 
- * @param {Object} args arguments object - * @param {Int} args.parentId the ID of the parent node - * @param {Array} options.sortedIds array of node IDs as they should be sorted - * @returns {Promise} resourcePromise object. - * - */ - sort: function (args) { - if (!args) { - throw "args cannot be null"; - } - if (!args.parentId) { - throw "args.parentId cannot be null"; - } - if (!args.sortedIds) { - throw "args.sortedIds cannot be null"; - } + /** + * @ngdoc method + * @name umbraco.resources.mediaResource#sort + * @methodOf umbraco.resources.mediaResource + * + * @description + * Sorts all children below a given parent node id, based on a collection of node-ids + * + * ##usage + *
+        * var ids = [123,34533,2334,23434];
+        * mediaResource.sort({ sortedIds: ids })
+        *    .then(function() {
+        *        $scope.complete = true;
+        *    });
+        * 
+ * @param {Object} args arguments object + * @param {Int} args.parentId the ID of the parent node + * @param {Array} options.sortedIds array of node IDs as they should be sorted + * @returns {Promise} resourcePromise object. + * + */ + sort: function (args) { + if (!args) { + throw "args cannot be null"; + } + if (!args.parentId) { + throw "args.parentId cannot be null"; + } + if (!args.sortedIds) { + throw "args.sortedIds cannot be null"; + } - return umbRequestHelper.resourcePromise( + return umbRequestHelper.resourcePromise( $http.post(umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostSort"), - { - parentId: args.parentId, - idSortOrder: args.sortedIds - }), + { + parentId: args.parentId, + idSortOrder: args.sortedIds + }), 'Failed to sort media'); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.mediaResource#move - * @methodOf umbraco.resources.mediaResource - * - * @description - * Moves a node underneath a new parentId - * - * ##usage - *
-         * mediaResource.move({ parentId: 1244, id: 123 })
-         *    .then(function() {
-         *        alert("node was moved");
-         *    }, function(err){
-         *      alert("node didnt move:" + err.data.Message); 
-         *    });
-         * 
- * @param {Object} args arguments object - * @param {Int} args.idd the ID of the node to move - * @param {Int} args.parentId the ID of the parent node to move to - * @returns {Promise} resourcePromise object. - * - */ - move: function (args) { - if (!args) { - throw "args cannot be null"; - } - if (!args.parentId) { - throw "args.parentId cannot be null"; - } - if (!args.id) { - throw "args.id cannot be null"; - } + /** + * @ngdoc method + * @name umbraco.resources.mediaResource#move + * @methodOf umbraco.resources.mediaResource + * + * @description + * Moves a node underneath a new parentId + * + * ##usage + *
+        * mediaResource.move({ parentId: 1244, id: 123 })
+        *    .then(function() {
+        *        alert("node was moved");
+        *    }, function(err){
+        *      alert("node didnt move:" + err.data.Message); 
+        *    });
+        * 
+ * @param {Object} args arguments object + * @param {Int} args.idd the ID of the node to move + * @param {Int} args.parentId the ID of the parent node to move to + * @returns {Promise} resourcePromise object. + * + */ + move: function (args) { + if (!args) { + throw "args cannot be null"; + } + if (!args.parentId) { + throw "args.parentId cannot be null"; + } + if (!args.id) { + throw "args.id cannot be null"; + } - return umbRequestHelper.resourcePromise( + return umbRequestHelper.resourcePromise( $http.post(umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostMove"), - { - parentId: args.parentId, - id: args.id - }), + { + parentId: args.parentId, + id: args.id + }), 'Failed to move media'); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.mediaResource#getById - * @methodOf umbraco.resources.mediaResource - * - * @description - * Gets a media item with a given id - * - * ##usage - *
-         * mediaResource.getById(1234)
-         *    .then(function(media) {
-         *        var myMedia = media; 
-         *        alert('its here!');
-         *    });
-         * 
- * - * @param {Int} id id of media item to return - * @returns {Promise} resourcePromise object containing the media item. - * - */ - getById: function (id) { - - return umbRequestHelper.resourcePromise( + /** + * @ngdoc method + * @name umbraco.resources.mediaResource#getById + * @methodOf umbraco.resources.mediaResource + * + * @description + * Gets a media item with a given id + * + * ##usage + *
+        * mediaResource.getById(1234)
+        *    .then(function(media) {
+        *        var myMedia = media; 
+        *        alert('its here!');
+        *    });
+        * 
+ * + * @param {Int} id id of media item to return + * @returns {Promise} resourcePromise object containing the media item. + * + */ + getById: function (id) { + + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "mediaApiBaseUrl", - "GetById", - [{ id: id }])), + umbRequestHelper.getApiUrl( + "mediaApiBaseUrl", + "GetById", + [{ id: id }])), 'Failed to retrieve data for media id ' + id); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.mediaResource#deleteById - * @methodOf umbraco.resources.mediaResource - * - * @description - * Deletes a media item with a given id - * - * ##usage - *
-         * mediaResource.deleteById(1234)
-         *    .then(function() {
-         *        alert('its gone!');
-         *    });
-         * 
- * - * @param {Int} id id of media item to delete - * @returns {Promise} resourcePromise object. - * - */ - deleteById: function(id) { - return umbRequestHelper.resourcePromise( + /** + * @ngdoc method + * @name umbraco.resources.mediaResource#deleteById + * @methodOf umbraco.resources.mediaResource + * + * @description + * Deletes a media item with a given id + * + * ##usage + *
+        * mediaResource.deleteById(1234)
+        *    .then(function() {
+        *        alert('its gone!');
+        *    });
+        * 
+ * + * @param {Int} id id of media item to delete + * @returns {Promise} resourcePromise object. + * + */ + deleteById: function (id) { + return umbRequestHelper.resourcePromise( $http.post( - umbRequestHelper.getApiUrl( - "mediaApiBaseUrl", - "DeleteById", - [{ id: id }])), + umbRequestHelper.getApiUrl( + "mediaApiBaseUrl", + "DeleteById", + [{ id: id }])), 'Failed to delete item ' + id); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.mediaResource#getByIds - * @methodOf umbraco.resources.mediaResource - * - * @description - * Gets an array of media items, given a collection of ids - * - * ##usage - *
-         * mediaResource.getByIds( [1234,2526,28262])
-         *    .then(function(mediaArray) {
-         *        var myDoc = contentArray; 
-         *        alert('they are here!');
-         *    });
-         * 
- * - * @param {Array} ids ids of media items to return as an array - * @returns {Promise} resourcePromise object containing the media items array. - * - */ - getByIds: function (ids) { - - var idQuery = ""; - _.each(ids, function(item) { - idQuery += "ids=" + item + "&"; - }); + /** + * @ngdoc method + * @name umbraco.resources.mediaResource#getByIds + * @methodOf umbraco.resources.mediaResource + * + * @description + * Gets an array of media items, given a collection of ids + * + * ##usage + *
+        * mediaResource.getByIds( [1234,2526,28262])
+        *    .then(function(mediaArray) {
+        *        var myDoc = contentArray; 
+        *        alert('they are here!');
+        *    });
+        * 
+ * + * @param {Array} ids ids of media items to return as an array + * @returns {Promise} resourcePromise object containing the media items array. + * + */ + getByIds: function (ids) { - return umbRequestHelper.resourcePromise( + var idQuery = ""; + _.each(ids, function (item) { + idQuery += "ids=" + item + "&"; + }); + + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "mediaApiBaseUrl", - "GetByIds", - idQuery)), + umbRequestHelper.getApiUrl( + "mediaApiBaseUrl", + "GetByIds", + idQuery)), 'Failed to retrieve data for media ids ' + ids); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.mediaResource#getScaffold - * @methodOf umbraco.resources.mediaResource - * - * @description - * Returns a scaffold of an empty media item, given the id of the media item to place it underneath and the media type alias. - * - * - Parent Id must be provided so umbraco knows where to store the media - * - Media Type alias must be provided so umbraco knows which properties to put on the media scaffold - * - * The scaffold is used to build editors for media that has not yet been populated with data. - * - * ##usage - *
-         * mediaResource.getScaffold(1234, 'folder')
-         *    .then(function(scaffold) {
-         *        var myDoc = scaffold;
-         *        myDoc.name = "My new media item"; 
-         *
-         *        mediaResource.save(myDoc, true)
-         *            .then(function(media){
-         *                alert("Retrieved, updated and saved again");
-         *            });
-         *    });
-         * 
- * - * @param {Int} parentId id of media item to return - * @param {String} alias mediatype alias to base the scaffold on - * @returns {Promise} resourcePromise object containing the media scaffold. - * - */ - getScaffold: function (parentId, alias) { - - return umbRequestHelper.resourcePromise( + /** + * @ngdoc method + * @name umbraco.resources.mediaResource#getScaffold + * @methodOf umbraco.resources.mediaResource + * + * @description + * Returns a scaffold of an empty media item, given the id of the media item to place it underneath and the media type alias. + * + * - Parent Id must be provided so umbraco knows where to store the media + * - Media Type alias must be provided so umbraco knows which properties to put on the media scaffold + * + * The scaffold is used to build editors for media that has not yet been populated with data. + * + * ##usage + *
+        * mediaResource.getScaffold(1234, 'folder')
+        *    .then(function(scaffold) {
+        *        var myDoc = scaffold;
+        *        myDoc.name = "My new media item"; 
+        *
+        *        mediaResource.save(myDoc, true)
+        *            .then(function(media){
+        *                alert("Retrieved, updated and saved again");
+        *            });
+        *    });
+        * 
+ * + * @param {Int} parentId id of media item to return + * @param {String} alias mediatype alias to base the scaffold on + * @returns {Promise} resourcePromise object containing the media scaffold. + * + */ + getScaffold: function (parentId, alias) { + + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "mediaApiBaseUrl", - "GetEmpty", - [{ contentTypeAlias: alias }, { parentId: parentId }])), + umbRequestHelper.getApiUrl( + "mediaApiBaseUrl", + "GetEmpty", + [{ contentTypeAlias: alias }, { parentId: parentId }])), 'Failed to retrieve data for empty media item type ' + alias); - }, + }, - rootMedia: function () { - - return umbRequestHelper.resourcePromise( + rootMedia: function () { + + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "mediaApiBaseUrl", - "GetRootMedia")), + umbRequestHelper.getApiUrl( + "mediaApiBaseUrl", + "GetRootMedia")), 'Failed to retrieve data for root media'); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.mediaResource#getChildren - * @methodOf umbraco.resources.mediaResource - * - * @description - * Gets children of a media item with a given id - * - * ##usage - *
-         * mediaResource.getChildren(1234, {pageSize: 10, pageNumber: 2})
-         *    .then(function(contentArray) {
-         *        var children = contentArray; 
-         *        alert('they are here!');
-         *    });
-         * 
- * - * @param {Int} parentid id of content item to return children of - * @param {Object} options optional options object - * @param {Int} options.pageSize if paging data, number of nodes per page, default = 0 - * @param {Int} options.pageNumber if paging data, current page index, default = 0 - * @param {String} options.filter if provided, query will only return those with names matching the filter - * @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Ascending` - * @param {String} options.orderBy property to order items by, default: `SortOrder` - * @returns {Promise} resourcePromise object containing an array of content items. - * - */ - getChildren: function (parentId, options) { + /** + * @ngdoc method + * @name umbraco.resources.mediaResource#getChildren + * @methodOf umbraco.resources.mediaResource + * + * @description + * Gets children of a media item with a given id + * + * ##usage + *
+        * mediaResource.getChildren(1234, {pageSize: 10, pageNumber: 2})
+        *    .then(function(contentArray) {
+        *        var children = contentArray; 
+        *        alert('they are here!');
+        *    });
+        * 
+ * + * @param {Int} parentid id of content item to return children of + * @param {Object} options optional options object + * @param {Int} options.pageSize if paging data, number of nodes per page, default = 0 + * @param {Int} options.pageNumber if paging data, current page index, default = 0 + * @param {String} options.filter if provided, query will only return those with names matching the filter + * @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Ascending` + * @param {String} options.orderBy property to order items by, default: `SortOrder` + * @returns {Promise} resourcePromise object containing an array of content items. + * + */ + getChildren: function (parentId, options) { - var defaults = { - pageSize: 0, - pageNumber: 0, - filter: '', - orderDirection: "Ascending", - orderBy: "SortOrder" - }; - 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; - //change asc/desct - if (options.orderDirection === "asc") { - options.orderDirection = "Ascending"; - } - else if (options.orderDirection === "desc") { - options.orderDirection = "Descending"; - } + var defaults = { + pageSize: 0, + pageNumber: 0, + filter: '', + orderDirection: "Ascending", + orderBy: "SortOrder", + orderBySystemField: true + }; + 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; + //change asc/desct + if (options.orderDirection === "asc") { + options.orderDirection = "Ascending"; + } + else if (options.orderDirection === "desc") { + options.orderDirection = "Descending"; + } - return umbRequestHelper.resourcePromise( + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "mediaApiBaseUrl", - "GetChildren", - [ - { id: parentId }, - { pageNumber: options.pageNumber }, - { pageSize: options.pageSize }, - { orderBy: options.orderBy }, - { orderDirection: options.orderDirection }, - { filter: options.filter } - ])), + umbRequestHelper.getApiUrl( + "mediaApiBaseUrl", + "GetChildren", + [ + { id: parentId }, + { pageNumber: options.pageNumber }, + { pageSize: options.pageSize }, + { orderBy: options.orderBy }, + { orderDirection: options.orderDirection }, + { orderBySystemField: options.orderBySystemField }, + { filter: options.filter } + ])), 'Failed to retrieve children for media item ' + parentId); - }, - - /** - * @ngdoc method - * @name umbraco.resources.mediaResource#save - * @methodOf umbraco.resources.mediaResource - * - * @description - * Saves changes made to a media item, if the media item is new, the isNew paramater must be passed to force creation - * if the media item needs to have files attached, they must be provided as the files param and passed separately - * - * - * ##usage - *
-         * mediaResource.getById(1234)
-         *    .then(function(media) {
-         *          media.name = "I want a new name!";
-         *          mediaResource.save(media, false)
-         *            .then(function(media){
-         *                alert("Retrieved, updated and saved again");
-         *            });
-         *    });
-         * 
- * - * @param {Object} media The media item object with changes applied - * @param {Bool} isNew set to true to create a new item or to update an existing - * @param {Array} files collection of files for the media item - * @returns {Promise} resourcePromise object containing the saved media item. - * - */ - save: function (media, isNew, files) { - return saveMediaItem(media, "save" + (isNew ? "New" : ""), files); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.mediaResource#addFolder - * @methodOf umbraco.resources.mediaResource - * - * @description - * Shorthand for adding a media item of the type "Folder" under a given parent ID - * - * ##usage - *
-         * mediaResource.addFolder("My gallery", 1234)
-         *    .then(function(folder) {
-         *        alert('New folder');
-         *    });
-         * 
- * - * @param {string} name Name of the folder to create - * @param {int} parentId Id of the media item to create the folder underneath - * @returns {Promise} resourcePromise object. - * - */ - addFolder: function(name, parentId){ - return umbRequestHelper.resourcePromise( + /** + * @ngdoc method + * @name umbraco.resources.mediaResource#save + * @methodOf umbraco.resources.mediaResource + * + * @description + * Saves changes made to a media item, if the media item is new, the isNew paramater must be passed to force creation + * if the media item needs to have files attached, they must be provided as the files param and passed separately + * + * + * ##usage + *
+        * mediaResource.getById(1234)
+        *    .then(function(media) {
+        *          media.name = "I want a new name!";
+        *          mediaResource.save(media, false)
+        *            .then(function(media){
+        *                alert("Retrieved, updated and saved again");
+        *            });
+        *    });
+        * 
+ * + * @param {Object} media The media item object with changes applied + * @param {Bool} isNew set to true to create a new item or to update an existing + * @param {Array} files collection of files for the media item + * @returns {Promise} resourcePromise object containing the saved media item. + * + */ + save: function (media, isNew, files) { + return saveMediaItem(media, "save" + (isNew ? "New" : ""), files); + }, + + /** + * @ngdoc method + * @name umbraco.resources.mediaResource#addFolder + * @methodOf umbraco.resources.mediaResource + * + * @description + * Shorthand for adding a media item of the type "Folder" under a given parent ID + * + * ##usage + *
+        * mediaResource.addFolder("My gallery", 1234)
+        *    .then(function(folder) {
+        *        alert('New folder');
+        *    });
+        * 
+ * + * @param {string} name Name of the folder to create + * @param {int} parentId Id of the media item to create the folder underneath + * @returns {Promise} resourcePromise object. + * + */ + addFolder: function (name, parentId) { + return umbRequestHelper.resourcePromise( $http.post(umbRequestHelper - .getApiUrl("mediaApiBaseUrl", "PostAddFolder"), - { - name: name, - parentId: parentId - }), + .getApiUrl("mediaApiBaseUrl", "PostAddFolder"), + { + name: name, + parentId: parentId + }), 'Failed to add folder'); - }, - - /** - * @ngdoc method - * @name umbraco.resources.mediaResource#getChildFolders - * @methodOf umbraco.resources.mediaResource - * - * @description - * Retrieves all media children with types used as folders. - * Uses the convention of looking for media items with mediaTypes ending in - * *Folder so will match "Folder", "bannerFolder", "secureFolder" etc, - * - * ##usage - *
-         * mediaResource.getChildFolders(1234)
-         *    .then(function(data) {
-         *        alert('folders');
-         *    });
-         * 
- * - * @param {int} parentId Id of the media item to query for child folders - * @returns {Promise} resourcePromise object. - * - */ - getChildFolders: function(parentId){ - if(!parentId){ - parentId = -1; - } - - return umbRequestHelper.resourcePromise( + }, + + /** + * @ngdoc method + * @name umbraco.resources.mediaResource#getChildFolders + * @methodOf umbraco.resources.mediaResource + * + * @description + * Retrieves all media children with types used as folders. + * Uses the convention of looking for media items with mediaTypes ending in + * *Folder so will match "Folder", "bannerFolder", "secureFolder" etc, + * + * ##usage + *
+        * mediaResource.getChildFolders(1234)
+        *    .then(function(data) {
+        *        alert('folders');
+        *    });
+        * 
+ * + * @param {int} parentId Id of the media item to query for child folders + * @returns {Promise} resourcePromise object. + * + */ + getChildFolders: function (parentId) { + if (!parentId) { + parentId = -1; + } + + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "mediaApiBaseUrl", - "GetChildFolders", - [ - { id: parentId } - ])), + umbRequestHelper.getApiUrl( + "mediaApiBaseUrl", + "GetChildFolders", + [ + { id: parentId } + ])), 'Failed to retrieve child folders for media item ' + parentId); - }, - - /** - * @ngdoc method - * @name umbraco.resources.mediaResource#emptyRecycleBin - * @methodOf umbraco.resources.mediaResource - * - * @description - * Empties the media recycle bin - * - * ##usage - *
-         * mediaResource.emptyRecycleBin()
-         *    .then(function() {
-         *        alert('its empty!');
-         *    });
-         * 
- * - * @returns {Promise} resourcePromise object. - * - */ - emptyRecycleBin: function() { - return umbRequestHelper.resourcePromise( + }, + + /** + * @ngdoc method + * @name umbraco.resources.mediaResource#emptyRecycleBin + * @methodOf umbraco.resources.mediaResource + * + * @description + * Empties the media recycle bin + * + * ##usage + *
+        * mediaResource.emptyRecycleBin()
+        *    .then(function() {
+        *        alert('its empty!');
+        *    });
+        * 
+ * + * @returns {Promise} resourcePromise object. + * + */ + emptyRecycleBin: function () { + return umbRequestHelper.resourcePromise( $http.post( - umbRequestHelper.getApiUrl( - "mediaApiBaseUrl", - "EmptyRecycleBin")), + umbRequestHelper.getApiUrl( + "mediaApiBaseUrl", + "EmptyRecycleBin")), 'Failed to empty the recycle bin'); - } - }; + } + }; } angular.module('umbraco.resources').factory('mediaResource', mediaResource); diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/member.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/member.resource.js index 42db4f6366..3ec9258f98 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/member.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/member.resource.js @@ -4,230 +4,232 @@ * @description Loads in data for members **/ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) { - - /** internal method process the saving of data and post processing the result */ - function saveMember(content, action, files) { - - return umbRequestHelper.postSaveContent({ - restApiUrl: umbRequestHelper.getApiUrl( + + /** internal method process the saving of data and post processing the result */ + function saveMember(content, action, files) { + + return umbRequestHelper.postSaveContent({ + restApiUrl: umbRequestHelper.getApiUrl( "memberApiBaseUrl", "PostSave"), - content: content, - action: action, - files: files, - dataFormatter: function(c, a) { - return umbDataFormatter.formatMemberPostData(c, a); - } - }); - } + content: content, + action: action, + files: files, + dataFormatter: function (c, a) { + return umbDataFormatter.formatMemberPostData(c, a); + } + }); + } - return { - - getPagedResults: function (memberTypeAlias, options) { + return { - if (memberTypeAlias === 'all-members') { - memberTypeAlias = null; - } + getPagedResults: function (memberTypeAlias, options) { - var defaults = { - pageSize: 25, - pageNumber: 1, - filter: '', - orderDirection: "Ascending", - orderBy: "LoginName" - }; - 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; - //change asc/desct - if (options.orderDirection === "asc") { - options.orderDirection = "Ascending"; - } - else if (options.orderDirection === "desc") { - options.orderDirection = "Descending"; - } + if (memberTypeAlias === 'all-members') { + memberTypeAlias = null; + } - var params = [ + var defaults = { + pageSize: 25, + pageNumber: 1, + filter: '', + orderDirection: "Ascending", + orderBy: "LoginName", + orderBySystemField: true + }; + 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; + //change asc/desct + if (options.orderDirection === "asc") { + options.orderDirection = "Ascending"; + } + else if (options.orderDirection === "desc") { + options.orderDirection = "Descending"; + } + + var params = [ { pageNumber: options.pageNumber }, { pageSize: options.pageSize }, { orderBy: options.orderBy }, { orderDirection: options.orderDirection }, + { orderBySystemField: options.orderBySystemField }, { filter: options.filter } - ]; - if (memberTypeAlias != null) { - params.push({ memberTypeAlias: memberTypeAlias }); - } + ]; + if (memberTypeAlias != null) { + params.push({ memberTypeAlias: memberTypeAlias }); + } - return umbRequestHelper.resourcePromise( + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "memberApiBaseUrl", - "GetPagedResults", - params)), + umbRequestHelper.getApiUrl( + "memberApiBaseUrl", + "GetPagedResults", + params)), 'Failed to retrieve member paged result'); - }, - - getListNode: function (listName) { + }, - return umbRequestHelper.resourcePromise( + getListNode: function (listName) { + + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "memberApiBaseUrl", - "GetListNodeDisplay", - [{ listName: listName }])), + umbRequestHelper.getApiUrl( + "memberApiBaseUrl", + "GetListNodeDisplay", + [{ listName: listName }])), 'Failed to retrieve data for member list ' + listName); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.memberResource#getByKey - * @methodOf umbraco.resources.memberResource - * - * @description - * Gets a member item with a given key - * - * ##usage - *
-         * memberResource.getByKey("0000-0000-000-00000-000")
-         *    .then(function(member) {
-         *        var mymember = member; 
-         *        alert('its here!');
-         *    });
-         * 
- * - * @param {Guid} key key of member item to return - * @returns {Promise} resourcePromise object containing the member item. - * - */ - getByKey: function (key) { - - return umbRequestHelper.resourcePromise( + /** + * @ngdoc method + * @name umbraco.resources.memberResource#getByKey + * @methodOf umbraco.resources.memberResource + * + * @description + * Gets a member item with a given key + * + * ##usage + *
+        * memberResource.getByKey("0000-0000-000-00000-000")
+        *    .then(function(member) {
+        *        var mymember = member; 
+        *        alert('its here!');
+        *    });
+        * 
+ * + * @param {Guid} key key of member item to return + * @returns {Promise} resourcePromise object containing the member item. + * + */ + getByKey: function (key) { + + return umbRequestHelper.resourcePromise( $http.get( - umbRequestHelper.getApiUrl( - "memberApiBaseUrl", - "GetByKey", - [{ key: key }])), + umbRequestHelper.getApiUrl( + "memberApiBaseUrl", + "GetByKey", + [{ key: key }])), 'Failed to retrieve data for member id ' + key); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.memberResource#deleteByKey - * @methodOf umbraco.resources.memberResource - * - * @description - * Deletes a member item with a given key - * - * ##usage - *
-         * memberResource.deleteByKey("0000-0000-000-00000-000")
-         *    .then(function() {
-         *        alert('its gone!');
-         *    });
-         * 
- * - * @param {Guid} key id of member item to delete - * @returns {Promise} resourcePromise object. - * - */ - deleteByKey: function (key) { - return umbRequestHelper.resourcePromise( + /** + * @ngdoc method + * @name umbraco.resources.memberResource#deleteByKey + * @methodOf umbraco.resources.memberResource + * + * @description + * Deletes a member item with a given key + * + * ##usage + *
+        * memberResource.deleteByKey("0000-0000-000-00000-000")
+        *    .then(function() {
+        *        alert('its gone!');
+        *    });
+        * 
+ * + * @param {Guid} key id of member item to delete + * @returns {Promise} resourcePromise object. + * + */ + deleteByKey: function (key) { + return umbRequestHelper.resourcePromise( $http.post( - umbRequestHelper.getApiUrl( - "memberApiBaseUrl", - "DeleteByKey", - [{ key: key }])), + umbRequestHelper.getApiUrl( + "memberApiBaseUrl", + "DeleteByKey", + [{ key: key }])), 'Failed to delete item ' + key); - }, + }, - /** - * @ngdoc method - * @name umbraco.resources.memberResource#getScaffold - * @methodOf umbraco.resources.memberResource - * - * @description - * Returns a scaffold of an empty member item, given the id of the member item to place it underneath and the member type alias. - * - * - Member Type alias must be provided so umbraco knows which properties to put on the member scaffold - * - * The scaffold is used to build editors for member that has not yet been populated with data. - * - * ##usage - *
-         * memberResource.getScaffold('client')
-         *    .then(function(scaffold) {
-         *        var myDoc = scaffold;
-         *        myDoc.name = "My new member item"; 
-         *
-         *        memberResource.save(myDoc, true)
-         *            .then(function(member){
-         *                alert("Retrieved, updated and saved again");
-         *            });
-         *    });
-         * 
- * - * @param {String} alias membertype alias to base the scaffold on - * @returns {Promise} resourcePromise object containing the member scaffold. - * - */ - getScaffold: function (alias) { - - if (alias) { - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "memberApiBaseUrl", - "GetEmpty", - [{ contentTypeAlias: alias }])), - 'Failed to retrieve data for empty member item type ' + alias); - } - else { - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "memberApiBaseUrl", - "GetEmpty")), - 'Failed to retrieve data for empty member item type ' + alias); - } + /** + * @ngdoc method + * @name umbraco.resources.memberResource#getScaffold + * @methodOf umbraco.resources.memberResource + * + * @description + * Returns a scaffold of an empty member item, given the id of the member item to place it underneath and the member type alias. + * + * - Member Type alias must be provided so umbraco knows which properties to put on the member scaffold + * + * The scaffold is used to build editors for member that has not yet been populated with data. + * + * ##usage + *
+        * memberResource.getScaffold('client')
+        *    .then(function(scaffold) {
+        *        var myDoc = scaffold;
+        *        myDoc.name = "My new member item"; 
+        *
+        *        memberResource.save(myDoc, true)
+        *            .then(function(member){
+        *                alert("Retrieved, updated and saved again");
+        *            });
+        *    });
+        * 
+ * + * @param {String} alias membertype alias to base the scaffold on + * @returns {Promise} resourcePromise object containing the member scaffold. + * + */ + getScaffold: function (alias) { - }, - - /** - * @ngdoc method - * @name umbraco.resources.memberResource#save - * @methodOf umbraco.resources.memberResource - * - * @description - * Saves changes made to a member, if the member is new, the isNew paramater must be passed to force creation - * if the member needs to have files attached, they must be provided as the files param and passed separately - * - * - * ##usage - *
-         * memberResource.getBykey("23234-sd8djsd-3h8d3j-sdh8d")
-         *    .then(function(member) {
-         *          member.name = "Bob";
-         *          memberResource.save(member, false)
-         *            .then(function(member){
-         *                alert("Retrieved, updated and saved again");
-         *            });
-         *    });
-         * 
- * - * @param {Object} media The member item object with changes applied - * @param {Bool} isNew set to true to create a new item or to update an existing - * @param {Array} files collection of files for the media item - * @returns {Promise} resourcePromise object containing the saved media item. - * - */ - save: function (member, isNew, files) { - return saveMember(member, "save" + (isNew ? "New" : ""), files); - } - }; + if (alias) { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "memberApiBaseUrl", + "GetEmpty", + [{ contentTypeAlias: alias }])), + 'Failed to retrieve data for empty member item type ' + alias); + } + else { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "memberApiBaseUrl", + "GetEmpty")), + 'Failed to retrieve data for empty member item type ' + alias); + } + + }, + + /** + * @ngdoc method + * @name umbraco.resources.memberResource#save + * @methodOf umbraco.resources.memberResource + * + * @description + * Saves changes made to a member, if the member is new, the isNew paramater must be passed to force creation + * if the member needs to have files attached, they must be provided as the files param and passed separately + * + * + * ##usage + *
+        * memberResource.getBykey("23234-sd8djsd-3h8d3j-sdh8d")
+        *    .then(function(member) {
+        *          member.name = "Bob";
+        *          memberResource.save(member, false)
+        *            .then(function(member){
+        *                alert("Retrieved, updated and saved again");
+        *            });
+        *    });
+        * 
+ * + * @param {Object} media The member item object with changes applied + * @param {Bool} isNew set to true to create a new item or to update an existing + * @param {Array} files collection of files for the media item + * @returns {Promise} resourcePromise object containing the saved media item. + * + */ + save: function (member, isNew, files) { + return saveMember(member, "save" + (isNew ? "New" : ""), files); + } + }; } angular.module('umbraco.resources').factory('memberResource', memberResource); diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html index fdd7dd23c9..8d9b45e6be 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html @@ -1,76 +1,60 @@ -
- -
- - -
-
- -
- -
- - - - - -
-
- - -
-
- - -
- - -
- -
- - -
- -
- {{item[column.alias]}} -
- -
-
- -
- - - - There are no items show in the list. - - -
+
+
+ +
+
+
+ +
+ + +
+
+ +
+
+ +
+ + +
+
+ + +
+
+ {{item[column.alias]}} +
+
+
+
+ + + There are no items show in the list. + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/list/list.listviewlayout.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/list/list.listviewlayout.controller.js index 1d2d361f28..b396b66564 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/list/list.listviewlayout.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/list/list.listviewlayout.controller.js @@ -1,75 +1,76 @@ -(function() { - "use strict"; - - function ListViewListLayoutController($scope, listViewHelper, $location, mediaHelper) { - - var vm = this; - - vm.nodeId = $scope.contentId; - //vm.acceptedFileTypes = mediaHelper.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes); - //instead of passing in a whitelist, we pass in a blacklist by adding ! to the ext - vm.acceptedFileTypes = mediaHelper.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.disallowedUploadFiles).replace(/./g, "!."); - vm.maxFileSize = Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB"; - vm.activeDrag = false; - vm.isRecycleBin = $scope.contentId === '-21' || $scope.contentId === '-20'; - - vm.selectItem = selectItem; - vm.clickItem = clickItem; - vm.selectAll = selectAll; - vm.isSelectedAll = isSelectedAll; - vm.isSortDirection = isSortDirection; - vm.sort = sort; - vm.dragEnter = dragEnter; - vm.dragLeave = dragLeave; - vm.onFilesQueue = onFilesQueue; - vm.onUploadComplete = onUploadComplete; - - function selectAll($event) { - listViewHelper.selectAllItems($scope.items, $scope.selection, $event); - } - - function isSelectedAll() { - return listViewHelper.isSelectedAll($scope.items, $scope.selection); - } - - function selectItem(selectedItem, $index, $event) { - listViewHelper.selectHandler(selectedItem, $index, $scope.items, $scope.selection, $event); - } - - function clickItem(item) { - $location.path($scope.entityType + '/' + $scope.entityType + '/edit/' + item.id); - } - - function isSortDirection(col, direction) { - return listViewHelper.setSortingDirection(col, direction, $scope.options); - } - - function sort(field, allow) { - if (allow) { - listViewHelper.setSorting(field, allow, $scope.options); - $scope.getContent($scope.contentId); - } - } - - // Dropzone upload functions - function dragEnter(el, event) { - vm.activeDrag = true; - } - - function dragLeave(el, event) { - vm.activeDrag = false; - } - - function onFilesQueue() { - vm.activeDrag = false; - } - - function onUploadComplete() { - $scope.getContent($scope.contentId); - } - - } - - angular.module("umbraco").controller("Umbraco.PropertyEditors.ListView.ListLayoutController", ListViewListLayoutController); - -})(); +(function () { + "use strict"; + + function ListViewListLayoutController($scope, listViewHelper, $location, mediaHelper) { + + var vm = this; + + vm.nodeId = $scope.contentId; + //vm.acceptedFileTypes = mediaHelper.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes); + //instead of passing in a whitelist, we pass in a blacklist by adding ! to the ext + vm.acceptedFileTypes = mediaHelper.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.disallowedUploadFiles).replace(/./g, "!."); + vm.maxFileSize = Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB"; + vm.activeDrag = false; + vm.isRecycleBin = $scope.contentId === '-21' || $scope.contentId === '-20'; + + vm.selectItem = selectItem; + vm.clickItem = clickItem; + vm.selectAll = selectAll; + vm.isSelectedAll = isSelectedAll; + vm.isSortDirection = isSortDirection; + vm.sort = sort; + vm.dragEnter = dragEnter; + vm.dragLeave = dragLeave; + vm.onFilesQueue = onFilesQueue; + vm.onUploadComplete = onUploadComplete; + + function selectAll($event) { + listViewHelper.selectAllItems($scope.items, $scope.selection, $event); + } + + function isSelectedAll() { + return listViewHelper.isSelectedAll($scope.items, $scope.selection); + } + + function selectItem(selectedItem, $index, $event) { + listViewHelper.selectHandler(selectedItem, $index, $scope.items, $scope.selection, $event); + } + + function clickItem(item) { + $location.path($scope.entityType + '/' +$scope.entityType + '/edit/' +item.id); + } + + function isSortDirection(col, direction) { + return listViewHelper.setSortingDirection(col, direction, $scope.options); + } + + function sort(field, allow, isSystem) { + if (allow) { + $scope.options.orderBySystemField = isSystem; + listViewHelper.setSorting(field, allow, $scope.options); + $scope.getContent($scope.contentId); + } + } + + // Dropzone upload functions + function dragEnter(el, event) { + vm.activeDrag = true; + } + + function dragLeave(el, event) { + vm.activeDrag = false; + } + + function onFilesQueue() { + vm.activeDrag = false; + } + + function onUploadComplete() { + $scope.getContent($scope.contentId); + } + + } + +angular.module("umbraco").controller("Umbraco.PropertyEditors.ListView.ListLayoutController", ListViewListLayoutController); + +}) (); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index 59ea03aa91..0d5451274c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -1,382 +1,393 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookieStore, notificationsService, iconHelper, dialogService, editorState, localizationService, $location, appState, $timeout, $q, mediaResource, listViewHelper, userService) { - //this is a quick check to see if we're in create mode, if so just exit - we cannot show children for content - // that isn't created yet, if we continue this will use the parent id in the route params which isn't what - // we want. NOTE: This is just a safety check since when we scaffold an empty model on the server we remove - // the list view tab entirely when it's new. - if ($routeParams.create) { - $scope.isNew = true; - return; - } + //this is a quick check to see if we're in create mode, if so just exit - we cannot show children for content + // that isn't created yet, if we continue this will use the parent id in the route params which isn't what + // we want. NOTE: This is just a safety check since when we scaffold an empty model on the server we remove + // the list view tab entirely when it's new. + if ($routeParams.create) { + $scope.isNew = true; + return; + } - //Now we need to check if this is for media, members or content because that will depend on the resources we use - var contentResource, getContentTypesCallback, getListResultsCallback, deleteItemCallback, getIdCallback, createEditUrlCallback; + //Now we need to check if this is for media, members or content because that will depend on the resources we use + var contentResource, getContentTypesCallback, getListResultsCallback, deleteItemCallback, getIdCallback, createEditUrlCallback; - //check the config for the entity type, or the current section name (since the config is only set in c#, not in pre-vals) - if (($scope.model.config.entityType && $scope.model.config.entityType === "member") || (appState.getSectionState("currentSection") === "member")) { - $scope.entityType = "member"; - contentResource = $injector.get('memberResource'); - getContentTypesCallback = $injector.get('memberTypeResource').getTypes; - getListResultsCallback = contentResource.getPagedResults; - deleteItemCallback = contentResource.deleteByKey; - getIdCallback = function(selected) { - var selectedKey = getItemKey(selected.id); - return selectedKey; - }; - createEditUrlCallback = function(item) { - return "/" + $scope.entityType + "/" + $scope.entityType + "/edit/" + item.key + "?page=" + $scope.options.pageNumber + "&listName=" + $scope.contentId; - }; - } - else { - //check the config for the entity type, or the current section name (since the config is only set in c#, not in pre-vals) - if (($scope.model.config.entityType && $scope.model.config.entityType === "media") || (appState.getSectionState("currentSection") === "media")) { - $scope.entityType = "media"; - contentResource = $injector.get('mediaResource'); - getContentTypesCallback = $injector.get('mediaTypeResource').getAllowedTypes; - } - else { - $scope.entityType = "content"; - contentResource = $injector.get('contentResource'); - getContentTypesCallback = $injector.get('contentTypeResource').getAllowedTypes; - } - getListResultsCallback = contentResource.getChildren; - deleteItemCallback = contentResource.deleteById; - getIdCallback = function(selected) { - return selected.id; - }; - createEditUrlCallback = function(item) { - return "/" + $scope.entityType + "/" + $scope.entityType + "/edit/" + item.id + "?page=" + $scope.options.pageNumber; - }; - } + //check the config for the entity type, or the current section name (since the config is only set in c#, not in pre-vals) + if (($scope.model.config.entityType && $scope.model.config.entityType === "member") || (appState.getSectionState("currentSection") === "member")) { + $scope.entityType = "member"; + contentResource = $injector.get('memberResource'); + getContentTypesCallback = $injector.get('memberTypeResource').getTypes; + getListResultsCallback = contentResource.getPagedResults; + deleteItemCallback = contentResource.deleteByKey; + getIdCallback = function (selected) { + var selectedKey = getItemKey(selected.id); + return selectedKey; + }; + createEditUrlCallback = function (item) { + return "/" + $scope.entityType + "/" + $scope.entityType + "/edit/" + item.key + "?page=" + $scope.options.pageNumber + "&listName=" + $scope.contentId; + }; + } + else { + //check the config for the entity type, or the current section name (since the config is only set in c#, not in pre-vals) + if (($scope.model.config.entityType && $scope.model.config.entityType === "media") || (appState.getSectionState("currentSection") === "media")) { + $scope.entityType = "media"; + contentResource = $injector.get('mediaResource'); + getContentTypesCallback = $injector.get('mediaTypeResource').getAllowedTypes; + } + else { + $scope.entityType = "content"; + contentResource = $injector.get('contentResource'); + getContentTypesCallback = $injector.get('contentTypeResource').getAllowedTypes; + } + getListResultsCallback = contentResource.getChildren; + deleteItemCallback = contentResource.deleteById; + getIdCallback = function (selected) { + return selected.id; + }; + createEditUrlCallback = function (item) { + return "/" + $scope.entityType + "/" + $scope.entityType + "/edit/" + item.id + "?page=" + $scope.options.pageNumber; + }; + } - $scope.pagination = []; - $scope.isNew = false; - $scope.actionInProgress = false; - $scope.selection = []; - $scope.folders = []; - $scope.listViewResultSet = { - totalPages: 0, - items: [] - }; - - $scope.currentNodePermissions = {} + $scope.pagination = []; + $scope.isNew = false; + $scope.actionInProgress = false; + $scope.selection = []; + $scope.folders = []; + $scope.listViewResultSet = { + totalPages: 0, + items: [] + }; - //Just ensure we do have an editorState - if (editorState.current) { - //Fetch current node allowed actions for the current user - //This is the current node & not each individual child node in the list - var currentUserPermissions = editorState.current.allowedActions; + $scope.currentNodePermissions = {} - //Create a nicer model rather than the funky & hard to remember permissions strings - $scope.currentNodePermissions = { - "canCopy": _.contains(currentUserPermissions, 'O'), //Magic Char = O - "canCreate": _.contains(currentUserPermissions, 'C'), //Magic Char = C - "canDelete": _.contains(currentUserPermissions, 'D'), //Magic Char = D - "canMove": _.contains(currentUserPermissions, 'M'), //Magic Char = M - "canPublish": _.contains(currentUserPermissions, 'U'), //Magic Char = U - "canUnpublish": _.contains(currentUserPermissions, 'U'), //Magic Char = Z (however UI says it can't be set, so if we can publish 'U' we can unpublish) - }; - } + //Just ensure we do have an editorState + if (editorState.current) { + //Fetch current node allowed actions for the current user + //This is the current node & not each individual child node in the list + var currentUserPermissions = editorState.current.allowedActions; - //when this is null, we don't check permissions - $scope.buttonPermissions = null; + //Create a nicer model rather than the funky & hard to remember permissions strings + $scope.currentNodePermissions = { + "canCopy": _.contains(currentUserPermissions, 'O'), //Magic Char = O + "canCreate": _.contains(currentUserPermissions, 'C'), //Magic Char = C + "canDelete": _.contains(currentUserPermissions, 'D'), //Magic Char = D + "canMove": _.contains(currentUserPermissions, 'M'), //Magic Char = M + "canPublish": _.contains(currentUserPermissions, 'U'), //Magic Char = U + "canUnpublish": _.contains(currentUserPermissions, 'U'), //Magic Char = Z (however UI says it can't be set, so if we can publish 'U' we can unpublish) + }; + } - //When we are dealing with 'content', we need to deal with permissions on child nodes. - // Currently there is no real good way to - if ($scope.entityType === "content") { + //when this is null, we don't check permissions + $scope.buttonPermissions = null; - var idsWithPermissions = null; + //When we are dealing with 'content', we need to deal with permissions on child nodes. + // Currently there is no real good way to + if ($scope.entityType === "content") { - $scope.buttonPermissions = { - canCopy: true, - canCreate: true, - canDelete: true, - canMove: true, - canPublish: true, - canUnpublish: true - }; + var idsWithPermissions = null; - $scope.$watch(function() { - return $scope.selection.length; - }, function(newVal, oldVal) { + $scope.buttonPermissions = { + canCopy: true, + canCreate: true, + canDelete: true, + canMove: true, + canPublish: true, + canUnpublish: true + }; - if ((idsWithPermissions == null && newVal > 0) || (idsWithPermissions != null)) { - - //get all of the selected ids - var ids = _.map($scope.selection, function(i) { - return i.id.toString(); - }); + $scope.$watch(function () { + return $scope.selection.length; + }, function (newVal, oldVal) { - //remove the dictionary items that don't have matching ids - var filtered = {}; - _.each(idsWithPermissions, function (value, key, list) { - if (_.contains(ids, key)) { - filtered[key] = value; - } - }); - idsWithPermissions = filtered; + if ((idsWithPermissions == null && newVal > 0) || (idsWithPermissions != null)) { - //find all ids that we haven't looked up permissions for - var existingIds = _.keys(idsWithPermissions); - var missingLookup = _.map(_.difference(ids, existingIds), function (i) { - return Number(i); - }); - - if (missingLookup.length > 0) { - contentResource.getPermissions(missingLookup).then(function(p) { - $scope.buttonPermissions = listViewHelper.getButtonPermissions(p, idsWithPermissions); - }); - } - else { - $scope.buttonPermissions = listViewHelper.getButtonPermissions({}, idsWithPermissions); - } - } - }); - - } - - $scope.options = { - displayAtTabNumber: $scope.model.config.displayAtTabNumber ? $scope.model.config.displayAtTabNumber : 1, - pageSize: $scope.model.config.pageSize ? $scope.model.config.pageSize : 10, - pageNumber: ($routeParams.page && Number($routeParams.page) != NaN && Number($routeParams.page) > 0) ? $routeParams.page : 1, - filter: '', - orderBy: ($scope.model.config.orderBy ? $scope.model.config.orderBy : 'VersionDate').trim(), - orderDirection: $scope.model.config.orderDirection ? $scope.model.config.orderDirection.trim() : "desc", - includeProperties: $scope.model.config.includeProperties ? $scope.model.config.includeProperties : [ - { alias: 'updateDate', header: 'Last edited', isSystem: 1 }, - { alias: 'updater', header: 'Last edited by', isSystem: 1 } - ], - layout: { - layouts: $scope.model.config.layouts, - activeLayout: listViewHelper.getLayout($routeParams.id, $scope.model.config.layouts) - }, - allowBulkPublish: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkPublish, - allowBulkUnpublish: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkUnpublish, - allowBulkCopy: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkCopy, - allowBulkMove: $scope.model.config.bulkActionPermissions.allowBulkMove, - allowBulkDelete: $scope.model.config.bulkActionPermissions.allowBulkDelete - }; - - //update all of the system includeProperties to enable sorting - _.each($scope.options.includeProperties, function(e, i) { - - if (e.isSystem) { - - //NOTE: special case for contentTypeAlias, it's a system property that cannot be sorted - // to do that, we'd need to update the base query for content to include the content type alias column - // which requires another join and would be slower. BUT We are doing this for members so not sure it makes a diff? - if (e.alias != "contentTypeAlias") { - e.allowSorting = true; - } - - //localize the header - var key = getLocalizedKey(e.alias); - localizationService.localize(key).then(function (v) { - e.header = v; + //get all of the selected ids + var ids = _.map($scope.selection, function (i) { + return i.id.toString(); }); - } - }); - $scope.selectLayout = function(selectedLayout) { - $scope.options.layout.activeLayout = listViewHelper.setLayout($routeParams.id, selectedLayout, $scope.model.config.layouts); - }; + //remove the dictionary items that don't have matching ids + var filtered = {}; + _.each(idsWithPermissions, function (value, key, list) { + if (_.contains(ids, key)) { + filtered[key] = value; + } + }); + idsWithPermissions = filtered; - function showNotificationsAndReset(err, reload, successMsg) { + //find all ids that we haven't looked up permissions for + var existingIds = _.keys(idsWithPermissions); + var missingLookup = _.map(_.difference(ids, existingIds), function (i) { + return Number(i); + }); - //check if response is ysod - if(err.status && err.status >= 500) { - - // Open ysod overlay - $scope.ysodOverlay = { - view : "ysod", - error : err, - show : true - }; - } - - $timeout(function() { - $scope.bulkStatus = ""; - $scope.actionInProgress = false; - }, 500); - - if (reload === true) { - $scope.reloadView($scope.contentId); - } - - if (err.data && angular.isArray(err.data.notifications)) { - for (var i = 0; i < err.data.notifications.length; i++) { - notificationsService.showNotification(err.data.notifications[i]); + if (missingLookup.length > 0) { + contentResource.getPermissions(missingLookup).then(function (p) { + $scope.buttonPermissions = listViewHelper.getButtonPermissions(p, idsWithPermissions); + }); } - } - else if (successMsg) { - notificationsService.success("Done", successMsg); - } - } - - $scope.next = function(pageNumber) { - $scope.options.pageNumber = pageNumber; - $scope.reloadView($scope.contentId); - }; - - $scope.goToPage = function(pageNumber) { - $scope.options.pageNumber = pageNumber; - $scope.reloadView($scope.contentId); - }; - - $scope.prev = function(pageNumber) { - $scope.options.pageNumber = pageNumber; - $scope.reloadView($scope.contentId); - }; - - - /*Loads the search results, based on parameters set in prev,next,sort and so on*/ - /*Pagination is done by an array of objects, due angularJS's funky way of monitoring state - with simple values */ - - $scope.reloadView = function(id) { - - $scope.viewLoaded = false; - - listViewHelper.clearSelection($scope.listViewResultSet.items, $scope.folders, $scope.selection); - - getListResultsCallback(id, $scope.options).then(function(data) { - - $scope.actionInProgress = false; - $scope.listViewResultSet = data; - - //update all values for display - if ($scope.listViewResultSet.items) { - _.each($scope.listViewResultSet.items, function(e, index) { - setPropertyValues(e); - }); + else { + $scope.buttonPermissions = listViewHelper.getButtonPermissions({}, idsWithPermissions); } + } + }); - if ($scope.entityType === 'media') { + } - mediaResource.getChildFolders($scope.contentId) - .then(function(folders) { - $scope.folders = folders; - $scope.viewLoaded = true; + $scope.options = { + displayAtTabNumber: $scope.model.config.displayAtTabNumber ? $scope.model.config.displayAtTabNumber : 1, + pageSize: $scope.model.config.pageSize ? $scope.model.config.pageSize : 10, + pageNumber: ($routeParams.page && Number($routeParams.page) != NaN && Number($routeParams.page) > 0) ? $routeParams.page : 1, + filter: '', + orderBy: ($scope.model.config.orderBy ? $scope.model.config.orderBy : 'VersionDate').trim(), + orderDirection: $scope.model.config.orderDirection ? $scope.model.config.orderDirection.trim() : "desc", + orderBySystemField: true, + includeProperties: $scope.model.config.includeProperties ? $scope.model.config.includeProperties : [ + { alias: 'updateDate', header: 'Last edited', isSystem: 1 }, + { alias: 'updater', header: 'Last edited by', isSystem: 1 } + ], + layout: { + layouts: $scope.model.config.layouts, + activeLayout: listViewHelper.getLayout($routeParams.id, $scope.model.config.layouts) + }, + allowBulkPublish: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkPublish, + allowBulkUnpublish: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkUnpublish, + allowBulkCopy: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkCopy, + allowBulkMove: $scope.model.config.bulkActionPermissions.allowBulkMove, + allowBulkDelete: $scope.model.config.bulkActionPermissions.allowBulkDelete + }; + + //update all of the system includeProperties to enable sorting + _.each($scope.options.includeProperties, function (e, i) { + + + //NOTE: special case for contentTypeAlias, it's a system property that cannot be sorted + // to do that, we'd need to update the base query for content to include the content type alias column + // which requires another join and would be slower. BUT We are doing this for members so not sure it makes a diff? + if (e.alias != "contentTypeAlias") { + e.allowSorting = true; + } + + // Another special case for lasted edited data/update date for media, again this field isn't available on the base table so we can't sort by it + if (e.isSystem && $scope.entityType == "media") { + e.allowSorting = e.alias != 'updateDate'; + } + + // Another special case for members, only fields on the base table (cmsMember) can be used for sorting + if (e.isSystem && $scope.entityType == "member") { + e.allowSorting = e.alias == 'username' || e.alias == 'email'; + } + if (e.isSystem) { + + //localize the header + var key = getLocalizedKey(e.alias); + localizationService.localize(key).then(function (v) { + e.header = v; + }); + } + }); + + $scope.selectLayout = function (selectedLayout) { + $scope.options.layout.activeLayout = listViewHelper.setLayout($routeParams.id, selectedLayout, $scope.model.config.layouts); + }; + + function showNotificationsAndReset(err, reload, successMsg) { + + //check if response is ysod + if (err.status && err.status >= 500) { + + // Open ysod overlay + $scope.ysodOverlay = { + view: "ysod", + error: err, + show: true + }; + } + + $timeout(function () { + $scope.bulkStatus = ""; + $scope.actionInProgress = false; + }, 500); + + if (reload === true) { + $scope.reloadView($scope.contentId); + } + + if (err.data && angular.isArray(err.data.notifications)) { + for (var i = 0; i < err.data.notifications.length; i++) { + notificationsService.showNotification(err.data.notifications[i]); + } + } + else if (successMsg) { + notificationsService.success("Done", successMsg); + } + } + + $scope.next = function (pageNumber) { + $scope.options.pageNumber = pageNumber; + $scope.reloadView($scope.contentId); + }; + + $scope.goToPage = function (pageNumber) { + $scope.options.pageNumber = pageNumber; + $scope.reloadView($scope.contentId); + }; + + $scope.prev = function (pageNumber) { + $scope.options.pageNumber = pageNumber; + $scope.reloadView($scope.contentId); + }; + + + /*Loads the search results, based on parameters set in prev,next,sort and so on*/ + /*Pagination is done by an array of objects, due angularJS's funky way of monitoring state + with simple values */ + + $scope.reloadView = function (id) { + + $scope.viewLoaded = false; + + listViewHelper.clearSelection($scope.listViewResultSet.items, $scope.folders, $scope.selection); + + getListResultsCallback(id, $scope.options).then(function (data) { + + $scope.actionInProgress = false; + $scope.listViewResultSet = data; + + //update all values for display + if ($scope.listViewResultSet.items) { + _.each($scope.listViewResultSet.items, function (e, index) { + setPropertyValues(e); + }); + } + + if ($scope.entityType === 'media') { + + mediaResource.getChildFolders($scope.contentId) + .then(function (folders) { + $scope.folders = folders; + $scope.viewLoaded = true; }); - } else { - $scope.viewLoaded = true; - } + } else { + $scope.viewLoaded = true; + } - //NOTE: This might occur if we are requesting a higher page number than what is actually available, for example - // if you have more than one page and you delete all items on the last page. In this case, we need to reset to the last - // available page and then re-load again - if ($scope.options.pageNumber > $scope.listViewResultSet.totalPages) { - $scope.options.pageNumber = $scope.listViewResultSet.totalPages; + //NOTE: This might occur if we are requesting a higher page number than what is actually available, for example + // if you have more than one page and you delete all items on the last page. In this case, we need to reset to the last + // available page and then re-load again + if ($scope.options.pageNumber > $scope.listViewResultSet.totalPages) { + $scope.options.pageNumber = $scope.listViewResultSet.totalPages; - //reload! - $scope.reloadView(id); - } + //reload! + $scope.reloadView(id); + } - }); - }; + }); + }; - var searchListView = _.debounce(function(){ - $scope.$apply(function() { + var searchListView = _.debounce(function () { + $scope.$apply(function () { + makeSearch(); + }); + }, 500); + + $scope.forceSearch = function (ev) { + //13: enter + switch (ev.keyCode) { + case 13: makeSearch(); - }); - }, 500); + break; + } + }; - $scope.forceSearch = function (ev) { - //13: enter - switch (ev.keyCode) { - case 13: - makeSearch(); - break; - } - }; + $scope.enterSearch = function () { + $scope.viewLoaded = false; + searchListView(); + }; - $scope.enterSearch = function() { - $scope.viewLoaded = false; - searchListView(); - }; + function makeSearch() { + if ($scope.options.filter !== null && $scope.options.filter !== undefined) { + $scope.options.pageNumber = 1; + //$scope.actionInProgress = true; + $scope.reloadView($scope.contentId); + } + } - function makeSearch() { - if ($scope.options.filter !== null && $scope.options.filter !== undefined) { - $scope.options.pageNumber = 1; - //$scope.actionInProgress = true; - $scope.reloadView($scope.contentId); - } - } + $scope.isAnythingSelected = function () { + if ($scope.selection.length === 0) { + return false; + } else { + return true; + } + }; - $scope.isAnythingSelected = function() { - if ($scope.selection.length === 0) { - return false; - } else { - return true; - } - }; - - $scope.selectedItemsCount = function() { + $scope.selectedItemsCount = function () { return $scope.selection.length; - }; + }; - $scope.clearSelection = function() { + $scope.clearSelection = function () { listViewHelper.clearSelection($scope.listViewResultSet.items, $scope.folders, $scope.selection); - }; + }; - $scope.getIcon = function(entry) { - return iconHelper.convertFromLegacyIcon(entry.icon); - }; + $scope.getIcon = function (entry) { + return iconHelper.convertFromLegacyIcon(entry.icon); + }; - function serial(selected, fn, getStatusMsg, index) { - return fn(selected, index).then(function (content) { - index++; - $scope.bulkStatus = getStatusMsg(index, selected.length); - return index < selected.length ? serial(selected, fn, getStatusMsg, index) : content; - }, function (err) { - var reload = index > 0; - showNotificationsAndReset(err, reload); - return err; - }); - } + function serial(selected, fn, getStatusMsg, index) { + return fn(selected, index).then(function (content) { + index++; + $scope.bulkStatus = getStatusMsg(index, selected.length); + return index < selected.length ? serial(selected, fn, getStatusMsg, index) : content; + }, function (err) { + var reload = index > 0; + showNotificationsAndReset(err, reload); + return err; + }); + } - function applySelected(fn, getStatusMsg, getSuccessMsg, confirmMsg) { - var selected = $scope.selection; - if (selected.length === 0) - return; - if (confirmMsg && !confirm(confirmMsg)) - return; + function applySelected(fn, getStatusMsg, getSuccessMsg, confirmMsg) { + var selected = $scope.selection; + if (selected.length === 0) + return; + if (confirmMsg && !confirm(confirmMsg)) + return; - $scope.actionInProgress = true; - $scope.bulkStatus = getStatusMsg(0, selected.length); + $scope.actionInProgress = true; + $scope.bulkStatus = getStatusMsg(0, selected.length); - serial(selected, fn, getStatusMsg, 0).then(function (result) { - // executes once the whole selection has been processed - // in case of an error (caught by serial), result will be the error - if (!(result.data && angular.isArray(result.data.notifications))) - showNotificationsAndReset(result, true, getSuccessMsg(selected.length)); - }); - } + serial(selected, fn, getStatusMsg, 0).then(function (result) { + // executes once the whole selection has been processed + // in case of an error (caught by serial), result will be the error + if (!(result.data && angular.isArray(result.data.notifications))) + showNotificationsAndReset(result, true, getSuccessMsg(selected.length)); + }); + } - $scope.delete = function () { - applySelected( - function (selected, index) { return deleteItemCallback(getIdCallback(selected[index])); }, - function (count, total) { return "Deleted " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, - function (total) { return "Deleted " + total + " item" + (total > 1 ? "s" : ""); }, - "Sure you want to delete?"); - }; + $scope.delete = function () { + applySelected( + function (selected, index) { return deleteItemCallback(getIdCallback(selected[index])); }, + function (count, total) { return "Deleted " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, + function (total) { return "Deleted " + total + " item" + (total > 1 ? "s" : ""); }, + "Sure you want to delete?"); + }; - $scope.publish = function () { - applySelected( - function (selected, index) { return contentResource.publishById(getIdCallback(selected[index])); }, - function (count, total) { return "Published " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, - function (total) { return "Published " + total + " item" + (total > 1 ? "s" : ""); }); - }; + $scope.publish = function () { + applySelected( + function (selected, index) { return contentResource.publishById(getIdCallback(selected[index])); }, + function (count, total) { return "Published " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, + function (total) { return "Published " + total + " item" + (total > 1 ? "s" : ""); }); + }; - $scope.unpublish = function() { - applySelected( - function (selected, index) { return contentResource.unPublish(getIdCallback(selected[index])); }, - function (count, total) { return "Unpublished " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, - function (total) { return "Unpublished " + total + " item" + (total > 1 ? "s" : ""); }); - }; + $scope.unpublish = function () { + applySelected( + function (selected, index) { return contentResource.unPublish(getIdCallback(selected[index])); }, + function (count, total) { return "Unpublished " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, + function (total) { return "Unpublished " + total + " item" + (total > 1 ? "s" : ""); }); + }; - $scope.move = function() { + $scope.move = function () { $scope.moveDialog = {}; $scope.moveDialog.title = "Move"; $scope.moveDialog.section = $scope.entityType; @@ -384,9 +395,9 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie $scope.moveDialog.view = "move"; $scope.moveDialog.show = true; - $scope.moveDialog.submit = function(model) { + $scope.moveDialog.submit = function (model) { - if(model.target) { + if (model.target) { performMove(model.target); } @@ -394,22 +405,22 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie $scope.moveDialog = null; }; - $scope.moveDialog.close = function(oldModel) { + $scope.moveDialog.close = function (oldModel) { $scope.moveDialog.show = false; $scope.moveDialog = null; }; - }; + }; - function performMove(target) { + function performMove(target) { applySelected( - function(selected, index) {return contentResource.move({parentId: target.id, id: getIdCallback(selected[index])}); }, - function(count, total) {return "Moved " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, - function(total) {return "Moved " + total + " item" + (total > 1 ? "s" : ""); }); - } + function (selected, index) { return contentResource.move({ parentId: target.id, id: getIdCallback(selected[index]) }); }, + function (count, total) { return "Moved " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, + function (total) { return "Moved " + total + " item" + (total > 1 ? "s" : ""); }); + } - $scope.copy = function() { + $scope.copy = function () { $scope.copyDialog = {}; $scope.copyDialog.title = "Copy"; $scope.copyDialog.section = $scope.entityType; @@ -417,8 +428,8 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie $scope.copyDialog.view = "copy"; $scope.copyDialog.show = true; - $scope.copyDialog.submit = function(model) { - if(model.target) { + $scope.copyDialog.submit = function (model) { + if (model.target) { performCopy(model.target, model.relateToOriginal); } @@ -426,142 +437,142 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie $scope.copyDialog = null; }; - $scope.copyDialog.close = function(oldModel) { + $scope.copyDialog.close = function (oldModel) { $scope.copyDialog.show = false; $scope.copyDialog = null; }; - }; + }; - function performCopy(target, relateToOriginal) { + function performCopy(target, relateToOriginal) { applySelected( - function(selected, index) {return contentResource.copy({parentId: target.id, id: getIdCallback(selected[index]), relateToOriginal: relateToOriginal}); }, - function(count, total) {return "Copied " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, - function(total) {return "Copied " + total + " item" + (total > 1 ? "s" : ""); }); - } + function (selected, index) { return contentResource.copy({ parentId: target.id, id: getIdCallback(selected[index]), relateToOriginal: relateToOriginal }); }, + function (count, total) { return "Copied " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, + function (total) { return "Copied " + total + " item" + (total > 1 ? "s" : ""); }); + } - function getCustomPropertyValue(alias, properties) { - var value = ''; - var index = 0; - var foundAlias = false; - for (var i = 0; i < properties.length; i++) { - if (properties[i].alias == alias) { - foundAlias = true; - break; - } - index++; - } + function getCustomPropertyValue(alias, properties) { + var value = ''; + var index = 0; + var foundAlias = false; + for (var i = 0; i < properties.length; i++) { + if (properties[i].alias == alias) { + foundAlias = true; + break; + } + index++; + } - if (foundAlias) { - value = properties[index].value; - } + if (foundAlias) { + value = properties[index].value; + } - return value; - } + return value; + } - /** This ensures that the correct value is set for each item in a row, we don't want to call a function during interpolation or ng-bind as performance is really bad that way */ - function setPropertyValues(result) { + /** This ensures that the correct value is set for each item in a row, we don't want to call a function during interpolation or ng-bind as performance is really bad that way */ + function setPropertyValues(result) { - //set the edit url - result.editPath = createEditUrlCallback(result); + //set the edit url + result.editPath = createEditUrlCallback(result); - _.each($scope.options.includeProperties, function (e, i) { + _.each($scope.options.includeProperties, function (e, i) { - var alias = e.alias; + var alias = e.alias; - // First try to pull the value directly from the alias (e.g. updatedBy) - var value = result[alias]; + // First try to pull the value directly from the alias (e.g. updatedBy) + var value = result[alias]; - // If this returns an object, look for the name property of that (e.g. owner.name) - if (value === Object(value)) { - value = value['name']; - } + // If this returns an object, look for the name property of that (e.g. owner.name) + if (value === Object(value)) { + value = value['name']; + } - // If we've got nothing yet, look at a user defined property - if (typeof value === 'undefined') { - value = getCustomPropertyValue(alias, result.properties); - } + // If we've got nothing yet, look at a user defined property + if (typeof value === 'undefined') { + value = getCustomPropertyValue(alias, result.properties); + } - // If we have a date, format it - if (isDate(value)) { - value = value.substring(0, value.length - 3); - } + // If we have a date, format it + if (isDate(value)) { + value = value.substring(0, value.length - 3); + } - // set what we've got on the result - result[alias] = value; - }); + // set what we've got on the result + result[alias] = value; + }); - } + } - function isDate(val) { - if (angular.isString(val)) { - return val.match(/^(\d{4})\-(\d{2})\-(\d{2})\ (\d{2})\:(\d{2})\:(\d{2})$/); - } - return false; - } + function isDate(val) { + if (angular.isString(val)) { + return val.match(/^(\d{4})\-(\d{2})\-(\d{2})\ (\d{2})\:(\d{2})\:(\d{2})$/); + } + return false; + } - function initView() { - //default to root id if the id is undefined - var id = $routeParams.id; - if(id === undefined){ - id = -1; - } + function initView() { + //default to root id if the id is undefined + var id = $routeParams.id; + if (id === undefined) { + id = -1; + } - $scope.listViewAllowedTypes = getContentTypesCallback(id); + $scope.listViewAllowedTypes = getContentTypesCallback(id); - $scope.contentId = id; - $scope.isTrashed = id === "-20" || id === "-21"; + $scope.contentId = id; + $scope.isTrashed = id === "-20" || id === "-21"; - $scope.options.allowBulkPublish = $scope.options.allowBulkPublish && !$scope.isTrashed; - $scope.options.allowBulkUnpublish = $scope.options.allowBulkUnpublish && !$scope.isTrashed; + $scope.options.allowBulkPublish = $scope.options.allowBulkPublish && !$scope.isTrashed; + $scope.options.allowBulkUnpublish = $scope.options.allowBulkUnpublish && !$scope.isTrashed; - $scope.options.bulkActionsAllowed = $scope.options.allowBulkPublish || - $scope.options.allowBulkUnpublish || - $scope.options.allowBulkCopy || - $scope.options.allowBulkMove || - $scope.options.allowBulkDelete; + $scope.options.bulkActionsAllowed = $scope.options.allowBulkPublish || + $scope.options.allowBulkUnpublish || + $scope.options.allowBulkCopy || + $scope.options.allowBulkMove || + $scope.options.allowBulkDelete; - $scope.reloadView($scope.contentId); - } + $scope.reloadView($scope.contentId); + } - function getLocalizedKey(alias) { + function getLocalizedKey(alias) { - switch (alias) { - case "sortOrder": - return "general_sort"; - case "updateDate": - return "content_updateDate"; - case "updater": - return "content_updatedBy"; - case "createDate": - return "content_createDate"; - case "owner": - return "content_createBy"; - case "published": - return "content_isPublished"; - case "contentTypeAlias": - //TODO: Check for members - return $scope.entityType === "content" ? "content_documentType" : "content_mediatype"; - case "email": - return "general_email"; - case "username": - return "general_username"; - } - return alias; - } + switch (alias) { + case "sortOrder": + return "general_sort"; + case "updateDate": + return "content_updateDate"; + case "updater": + return "content_updatedBy"; + case "createDate": + return "content_createDate"; + case "owner": + return "content_createBy"; + case "published": + return "content_isPublished"; + case "contentTypeAlias": + //TODO: Check for members + return $scope.entityType === "content" ? "content_documentType" : "content_mediatype"; + case "email": + return "general_email"; + case "username": + return "general_username"; + } + return alias; + } - function getItemKey(itemId) { - for (var i = 0; i < $scope.listViewResultSet.items.length; i++) { - var item = $scope.listViewResultSet.items[i]; - if (item.id === itemId) { - return item.key; - } - } - } + function getItemKey(itemId) { + for (var i = 0; i < $scope.listViewResultSet.items.length; i++) { + var item = $scope.listViewResultSet.items[i]; + if (item.id === itemId) { + return item.key; + } + } + } - //GO! - initView(); + //GO! + initView(); } diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index a65821cfa0..580e1a018c 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -48,13 +48,13 @@ namespace Umbraco.Web.Editors [PluginController("UmbracoApi")] [UmbracoApplicationAuthorizeAttribute(Constants.Applications.Content)] public class ContentController : ContentControllerBase - { + { /// /// Constructor /// public ContentController() - : this(UmbracoContext.Current) - { + : this(UmbracoContext.Current) + { } /// @@ -62,8 +62,8 @@ namespace Umbraco.Web.Editors /// /// public ContentController(UmbracoContext umbracoContext) - : base(umbracoContext) - { + : base(umbracoContext) + { } /// @@ -110,15 +110,15 @@ namespace Umbraco.Web.Editors [EnsureUserPermissionForContent("id")] public ContentItemDisplay GetById(int id) { - var foundContent = GetObjectFromRequest(() => Services.ContentService.GetById(id)); + var foundContent = GetObjectFromRequest(() => Services.ContentService.GetById(id)); if (foundContent == null) { HandleContentNotFound(id); } - + var content = Mapper.Map(foundContent); return content; - } + } [EnsureUserPermissionForContent("id")] public ContentItemDisplay GetWithTreeDefinition(int id) @@ -156,7 +156,7 @@ namespace Umbraco.Web.Editors //remove this tab if it exists: umbContainerView var containerTab = mapped.Tabs.FirstOrDefault(x => x.Alias == Constants.Conventions.PropertyGroups.ListViewGroupName); - mapped.Tabs = mapped.Tabs.Except(new[] {containerTab}); + mapped.Tabs = mapped.Tabs.Except(new[] { containerTab }); return mapped; } @@ -169,7 +169,7 @@ namespace Umbraco.Web.Editors { var url = Umbraco.NiceUrl(id); var response = Request.CreateResponse(HttpStatusCode.OK); - response.Content = new StringContent(url, Encoding.UTF8, "application/json"); + response.Content = new StringContent(url, Encoding.UTF8, "application/json"); return response; } @@ -179,18 +179,22 @@ namespace Umbraco.Web.Editors /// [FilterAllowedOutgoingContent(typeof(IEnumerable>), "Items")] public PagedResult> GetChildren( - int id, - int pageNumber = 0, //TODO: This should be '1' as it's not the index - int pageSize = 0, - string orderBy = "SortOrder", - Direction orderDirection = Direction.Ascending, - string filter = "") + int id, + int pageNumber = 0, //TODO: This should be '1' as it's not the index + int pageSize = 0, + string orderBy = "SortOrder", + Direction orderDirection = Direction.Ascending, + int? orderBySystemField = 2, + string filter = "") { + var orderBySystemFieldBool = orderBySystemField == 1 || orderBySystemField == 2; long totalChildren; IContent[] children; if (pageNumber > 0 && pageSize > 0) { - children = Services.ContentService.GetPagedChildren(id, (pageNumber - 1), pageSize, out totalChildren, orderBy, orderDirection, filter).ToArray(); + children = Services.ContentService + .GetPagedChildren(id, (pageNumber - 1), pageSize, out totalChildren + , orderBy, orderDirection, orderBySystemFieldBool, filter).ToArray(); } else { @@ -205,7 +209,7 @@ namespace Umbraco.Web.Editors var pagedResult = new PagedResult>(totalChildren, pageNumber, pageSize); pagedResult.Items = children - .Select(Mapper.Map>); + .Select(Mapper.Map>); return pagedResult; } @@ -213,7 +217,7 @@ namespace Umbraco.Web.Editors [Obsolete("Dont use this, it is incorrectly named, use HasPermission instead")] public bool GetHasPermission(string permissionToCheck, int nodeId) { - return HasPermission(permissionToCheck, nodeId); + return HasPermission(permissionToCheck, nodeId); } /// @@ -225,8 +229,8 @@ namespace Umbraco.Web.Editors public Dictionary GetPermissions(int[] nodeIds) { return Services.UserService - .GetPermissions(Security.CurrentUser, nodeIds) - .ToDictionary(x => x.EntityId, x => x.AssignedPermissions); + .GetPermissions(Security.CurrentUser, nodeIds) + .ToDictionary(x => x.EntityId, x => x.AssignedPermissions); } [HttpGet] @@ -240,7 +244,7 @@ namespace Umbraco.Web.Editors return false; } - + /// /// Saves content /// @@ -248,16 +252,16 @@ namespace Umbraco.Web.Editors [FileUploadCleanupFilter] [ContentPostValidate] public ContentItemDisplay PostSave( - [ModelBinder(typeof(ContentItemBinder))] - ContentItemSave contentItem) - { + [ModelBinder(typeof(ContentItemBinder))] + ContentItemSave contentItem) + { //If we've reached here it means: // * Our model has been bound // * and validated // * any file attachments have been saved to their temporary location for us to use // * we have a reference to the DTO object and the persisted object // * Permissions are valid - + MapPropertyValues(contentItem); //We need to manually check the validation results here because: @@ -275,7 +279,7 @@ namespace Umbraco.Web.Editors var forDisplay = Mapper.Map(contentItem.PersistedContent); forDisplay.Errors = ModelState.ToErrorDictionary(); throw new HttpResponseException(Request.CreateValidationErrorResponse(forDisplay)); - + } //if the model state is not valid we cannot publish so change it to save @@ -292,7 +296,7 @@ namespace Umbraco.Web.Editors //initialize this to successful var publishStatus = Attempt.Succeed(); - var wasCancelled = false; + var wasCancelled = false; if (contentItem.Action == ContentSaveAction.Save || contentItem.Action == ContentSaveAction.SaveNew) { @@ -327,8 +331,8 @@ namespace Umbraco.Web.Editors if (wasCancelled == false) { display.AddSuccessNotification( - Services.TextService.Localize("speechBubbles/editContentSavedHeader"), - Services.TextService.Localize("speechBubbles/editContentSavedText")); + Services.TextService.Localize("speechBubbles/editContentSavedHeader"), + Services.TextService.Localize("speechBubbles/editContentSavedText")); } else { @@ -340,8 +344,8 @@ namespace Umbraco.Web.Editors if (wasCancelled == false) { display.AddSuccessNotification( - Services.TextService.Localize("speechBubbles/editContentSendToPublish"), - Services.TextService.Localize("speechBubbles/editContentSendToPublishText")); + Services.TextService.Localize("speechBubbles/editContentSendToPublish"), + Services.TextService.Localize("speechBubbles/editContentSendToPublishText")); } else { @@ -366,7 +370,7 @@ namespace Umbraco.Web.Editors return display; } - + /// /// Publishes a document with a given ID /// @@ -392,7 +396,7 @@ namespace Umbraco.Web.Editors { var notificationModel = new SimpleNotificationModel(); ShowMessageForPublishStatus(publishResult.Result, notificationModel); - return Request.CreateValidationErrorResponse(notificationModel); + return Request.CreateValidationErrorResponse(notificationModel); } //return ok @@ -440,7 +444,7 @@ namespace Umbraco.Web.Editors //returning an object of INotificationModel will ensure that any pending // notification messages are added to the response. return Request.CreateValidationErrorResponse(new SimpleNotificationModel()); - } + } } return Request.CreateResponse(HttpStatusCode.OK); @@ -457,7 +461,7 @@ namespace Umbraco.Web.Editors [HttpPost] [EnsureUserPermissionForContent(Constants.System.RecycleBinContent)] public HttpResponseMessage EmptyRecycleBin() - { + { Services.ContentService.EmptyRecycleBin(); return Request.CreateResponse(HttpStatusCode.OK); } @@ -516,7 +520,7 @@ namespace Umbraco.Web.Editors var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new StringContent(toMove.Path, Encoding.UTF8, "application/json"); - return response; + return response; } /// @@ -548,7 +552,7 @@ namespace Umbraco.Web.Editors if (foundContent == null) HandleContentNotFound(id); - + var unpublishResult = Services.ContentService.WithResult().UnPublish(foundContent, Security.CurrentUser.Id); var content = Mapper.Map(foundContent); @@ -559,7 +563,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(Request.CreateValidationErrorResponse(content)); } else - { + { content.AddSuccessNotification(Services.TextService.Localize("content/unPublish"), Services.TextService.Localize("speechBubbles/contentUnpublished")); return content; } @@ -597,8 +601,8 @@ namespace Umbraco.Web.Editors contentItem.PersistedContent.ReleaseDate = contentItem.ReleaseDate; //only set the template if it didn't change var templateChanged = (contentItem.PersistedContent.Template == null && contentItem.TemplateAlias.IsNullOrWhiteSpace() == false) - || (contentItem.PersistedContent.Template != null && contentItem.PersistedContent.Template.Alias != contentItem.TemplateAlias) - || (contentItem.PersistedContent.Template != null && contentItem.TemplateAlias.IsNullOrWhiteSpace()); + || (contentItem.PersistedContent.Template != null && contentItem.PersistedContent.Template.Alias != contentItem.TemplateAlias) + || (contentItem.PersistedContent.Template != null && contentItem.TemplateAlias.IsNullOrWhiteSpace()); if (templateChanged) { var template = Services.FileService.GetTemplate(contentItem.TemplateAlias); @@ -641,8 +645,8 @@ namespace Umbraco.Web.Editors if (toMove.ContentType.AllowedAsRoot == false) { throw new HttpResponseException( - Request.CreateNotificationValidationErrorResponse( - Services.TextService.Localize("moveOrCopy/notAllowedAtRoot"))); + Request.CreateNotificationValidationErrorResponse( + Services.TextService.Localize("moveOrCopy/notAllowedAtRoot"))); } } else @@ -655,19 +659,19 @@ namespace Umbraco.Web.Editors //check if the item is allowed under this one if (parent.ContentType.AllowedContentTypes.Select(x => x.Id).ToArray() - .Any(x => x.Value == toMove.ContentType.Id) == false) + .Any(x => x.Value == toMove.ContentType.Id) == false) { throw new HttpResponseException( - Request.CreateNotificationValidationErrorResponse( - Services.TextService.Localize("moveOrCopy/notAllowedByContentType"))); + Request.CreateNotificationValidationErrorResponse( + Services.TextService.Localize("moveOrCopy/notAllowedByContentType"))); } // Check on paths if ((string.Format(",{0},", parent.Path)).IndexOf(string.Format(",{0},", toMove.Id), StringComparison.Ordinal) > -1) - { + { throw new HttpResponseException( - Request.CreateNotificationValidationErrorResponse( - Services.TextService.Localize("moveOrCopy/notAllowedByPath"))); + Request.CreateNotificationValidationErrorResponse( + Services.TextService.Localize("moveOrCopy/notAllowedByPath"))); } } @@ -681,52 +685,52 @@ namespace Umbraco.Web.Editors case PublishStatusType.Success: case PublishStatusType.SuccessAlreadyPublished: display.AddSuccessNotification( - Services.TextService.Localize("speechBubbles/editContentPublishedHeader"), - Services.TextService.Localize("speechBubbles/editContentPublishedText")); + Services.TextService.Localize("speechBubbles/editContentPublishedHeader"), + Services.TextService.Localize("speechBubbles/editContentPublishedText")); break; case PublishStatusType.FailedPathNotPublished: display.AddWarningNotification( - Services.TextService.Localize("publish"), - Services.TextService.Localize("publish/contentPublishedFailedByParent", - new[] {string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id)}).Trim()); + Services.TextService.Localize("publish"), + Services.TextService.Localize("publish/contentPublishedFailedByParent", + new[] { string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id) }).Trim()); break; case PublishStatusType.FailedCancelledByEvent: AddCancelMessage(display, "publish", "speechBubbles/contentPublishedFailedByEvent"); - break; + break; case PublishStatusType.FailedAwaitingRelease: display.AddWarningNotification( - Services.TextService.Localize("publish"), - Services.TextService.Localize("publish/contentPublishedFailedAwaitingRelease", - new[] {string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id)}).Trim()); + Services.TextService.Localize("publish"), + Services.TextService.Localize("publish/contentPublishedFailedAwaitingRelease", + new[] { string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id) }).Trim()); break; case PublishStatusType.FailedHasExpired: display.AddWarningNotification( - Services.TextService.Localize("publish"), - Services.TextService.Localize("publish/contentPublishedFailedExpired", - new[] - { - string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id), - }).Trim()); + Services.TextService.Localize("publish"), + Services.TextService.Localize("publish/contentPublishedFailedExpired", + new[] + { + string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id), + }).Trim()); break; case PublishStatusType.FailedIsTrashed: //TODO: We should add proper error messaging for this! break; case PublishStatusType.FailedContentInvalid: display.AddWarningNotification( - Services.TextService.Localize("publish"), - Services.TextService.Localize("publish/contentPublishedFailedInvalid", - new[] - { - string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id), - string.Join(",", status.InvalidProperties.Select(x => x.Alias)) - }).Trim()); + Services.TextService.Localize("publish"), + Services.TextService.Localize("publish/contentPublishedFailedInvalid", + new[] + { + string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id), + string.Join(",", status.InvalidProperties.Select(x => x.Alias)) + }).Trim()); break; default: throw new IndexOutOfRangeException(); } } - + /// /// Performs a permissions check for the user to check if it has access to the node based on @@ -741,15 +745,15 @@ namespace Umbraco.Web.Editors /// Specifies the already resolved content item to check against /// internal static bool CheckPermissions( - IDictionary storage, - IUser user, - IUserService userService, - IContentService contentService, - int nodeId, - char[] permissionsToCheck = null, - IContent contentItem = null) + IDictionary storage, + IUser user, + IUserService userService, + IContentService contentService, + int nodeId, + char[] permissionsToCheck = null, + IContent contentItem = null) { - + if (contentItem == null && nodeId != Constants.System.Root && nodeId != Constants.System.RecycleBinContent) { contentItem = contentService.GetById(nodeId); @@ -764,16 +768,16 @@ namespace Umbraco.Web.Editors } var hasPathAccess = (nodeId == Constants.System.Root) - ? UserExtensions.HasPathAccess( - Constants.System.Root.ToInvariantString(), - user.StartContentId, - Constants.System.RecycleBinContent) - : (nodeId == Constants.System.RecycleBinContent) - ? UserExtensions.HasPathAccess( - Constants.System.RecycleBinContent.ToInvariantString(), - user.StartContentId, - Constants.System.RecycleBinContent) - : user.HasPathAccess(contentItem); + ? UserExtensions.HasPathAccess( + Constants.System.Root.ToInvariantString(), + user.StartContentId, + Constants.System.RecycleBinContent) + : (nodeId == Constants.System.RecycleBinContent) + ? UserExtensions.HasPathAccess( + Constants.System.RecycleBinContent.ToInvariantString(), + user.StartContentId, + Constants.System.RecycleBinContent) + : user.HasPathAccess(contentItem); if (hasPathAccess == false) { diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 66889e2206..060fb06750 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -52,7 +52,7 @@ namespace Umbraco.Web.Editors /// public MediaController() : this(UmbracoContext.Current) - { + { } /// @@ -156,7 +156,7 @@ namespace Umbraco.Web.Editors var folderTypes = Services.ContentTypeService.GetAllMediaTypes().ToArray().Where(x => x.Alias.EndsWith("Folder")).Select(x => x.Id); var children = (id < 0) ? Services.MediaService.GetRootMedia() : Services.MediaService.GetById(id).Children(); - return children.Where(x => folderTypes.Contains(x.ContentTypeId)).Select(Mapper.Map>); + return children.Where(x => folderTypes.Contains(x.ContentTypeId)).Select(Mapper.Map>); } /// @@ -180,13 +180,16 @@ namespace Umbraco.Web.Editors int pageSize = 0, string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, + bool orderBySystemField = true, string filter = "") { int totalChildren; IMedia[] children; if (pageNumber > 0 && pageSize > 0) { - children = Services.MediaService.GetPagedChildren(id, (pageNumber - 1), pageSize, out totalChildren, orderBy, orderDirection, filter).ToArray(); + children = Services.MediaService + .GetPagedChildren(id, (pageNumber - 1), pageSize, out totalChildren + , orderBy, orderDirection, orderBySystemField, filter).ToArray(); } else { @@ -261,7 +264,7 @@ namespace Umbraco.Web.Editors var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new StringContent(toMove.Path, Encoding.UTF8, "application/json"); - return response; + return response; } /// @@ -307,7 +310,7 @@ namespace Umbraco.Web.Editors //return the updated model var display = Mapper.Map(contentItem.PersistedContent); - + //lasty, if it is not valid, add the modelstate to the outgoing object and throw a 403 HandleInvalidModelState(display); @@ -334,8 +337,8 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(Request.CreateValidationErrorResponse(display)); } } - - break; + + break; } return display; @@ -364,7 +367,7 @@ namespace Umbraco.Web.Editors Services.MediaService.EmptyRecycleBin(); return Request.CreateResponse(HttpStatusCode.OK); } - + /// /// Change the sort order for media /// @@ -383,7 +386,7 @@ namespace Umbraco.Web.Editors { return Request.CreateResponse(HttpStatusCode.OK); } - + var mediaService = base.ApplicationContext.Services.MediaService; var sortedMedia = new List(); try @@ -405,7 +408,7 @@ namespace Umbraco.Web.Editors } } - [EnsureUserPermissionForMedia("folder.ParentId")] + [EnsureUserPermissionForMedia("folder.ParentId")] public MediaItemDisplay PostAddFolder(EntityBasic folder) { var mediaService = ApplicationContext.Services.MediaService; @@ -436,7 +439,7 @@ namespace Umbraco.Web.Editors var provider = new MultipartFormDataStreamProvider(root); var result = await Request.Content.ReadAsMultipartAsync(provider); - + //must have a file if (result.FileData.Count == 0) { @@ -449,10 +452,10 @@ namespace Umbraco.Web.Editors { return Request.CreateValidationErrorResponse("The request was not formatted correctly, the currentFolder is not an integer"); } - + //ensure the user has access to this folder by parent id! if (CheckPermissions( - new Dictionary(), + new Dictionary(), Security.CurrentUser, Services.MediaService, parentId) == false) { @@ -463,65 +466,65 @@ namespace Umbraco.Web.Editors Services.TextService.Localize("speechBubbles/invalidUserPermissionsText"), SpeechBubbleIcon.Warning))); } - + var tempFiles = new PostedFiles(); var mediaService = ApplicationContext.Services.MediaService; //in case we pass a path with a folder in it, we will create it and upload media to it. - if (result.FormData.ContainsKey("path")) - { + if (result.FormData.ContainsKey("path")) + { - var folders = result.FormData["path"].Split('/'); + var folders = result.FormData["path"].Split('/'); - for (int i = 0; i < folders.Length - 1; i++) - { - var folderName = folders[i]; - IMedia folderMediaItem; + for (int i = 0; i < folders.Length - 1; i++) + { + var folderName = folders[i]; + IMedia folderMediaItem; - //if uploading directly to media root and not a subfolder - if (parentId == -1) - { - //look for matching folder - folderMediaItem = - mediaService.GetRootMedia().FirstOrDefault(x => x.Name == folderName && x.ContentType.Alias == Constants.Conventions.MediaTypes.Folder); - if (folderMediaItem == null) - { - //if null, create a folder - folderMediaItem = mediaService.CreateMedia(folderName, -1, Constants.Conventions.MediaTypes.Folder); - mediaService.Save(folderMediaItem); - } - } - else - { - //get current parent - var mediaRoot = mediaService.GetById(parentId); + //if uploading directly to media root and not a subfolder + if (parentId == -1) + { + //look for matching folder + folderMediaItem = + mediaService.GetRootMedia().FirstOrDefault(x => x.Name == folderName && x.ContentType.Alias == Constants.Conventions.MediaTypes.Folder); + if (folderMediaItem == null) + { + //if null, create a folder + folderMediaItem = mediaService.CreateMedia(folderName, -1, Constants.Conventions.MediaTypes.Folder); + mediaService.Save(folderMediaItem); + } + } + else + { + //get current parent + var mediaRoot = mediaService.GetById(parentId); - //if the media root is null, something went wrong, we'll abort - if (mediaRoot == null) - return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, - "The folder: " + folderName + " could not be used for storing images, its ID: " + parentId + - " returned null"); + //if the media root is null, something went wrong, we'll abort + if (mediaRoot == null) + return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, + "The folder: " + folderName + " could not be used for storing images, its ID: " + parentId + + " returned null"); - //look for matching folder - folderMediaItem = mediaRoot.Children().FirstOrDefault(x => x.Name == folderName && x.ContentType.Alias == Constants.Conventions.MediaTypes.Folder); - if (folderMediaItem == null) - { - //if null, create a folder - folderMediaItem = mediaService.CreateMedia(folderName, mediaRoot, Constants.Conventions.MediaTypes.Folder); - mediaService.Save(folderMediaItem); - } - } - //set the media root to the folder id so uploaded files will end there. - parentId = folderMediaItem.Id; - } - } + //look for matching folder + folderMediaItem = mediaRoot.Children().FirstOrDefault(x => x.Name == folderName && x.ContentType.Alias == Constants.Conventions.MediaTypes.Folder); + if (folderMediaItem == null) + { + //if null, create a folder + folderMediaItem = mediaService.CreateMedia(folderName, mediaRoot, Constants.Conventions.MediaTypes.Folder); + mediaService.Save(folderMediaItem); + } + } + //set the media root to the folder id so uploaded files will end there. + parentId = folderMediaItem.Id; + } + } - //get the files + //get the files foreach (var file in result.FileData) { var fileName = file.Headers.ContentDisposition.FileName.Trim(new[] { '\"' }); - var ext = fileName.Substring(fileName.LastIndexOf('.')+1).ToLower(); + var ext = fileName.Substring(fileName.LastIndexOf('.') + 1).ToLower(); if (UmbracoConfig.For.UmbracoSettings().Content.DisallowedUploadFiles.Contains(ext) == false) { @@ -583,7 +586,7 @@ namespace Umbraco.Web.Editors if (origin.Value == "blueimp") { return Request.CreateResponse(HttpStatusCode.OK, - tempFiles, + tempFiles, //Don't output the angular xsrf stuff, blue imp doesn't like that new JsonMediaTypeFormatter()); } diff --git a/src/Umbraco.Web/Editors/MemberController.cs b/src/Umbraco.Web/Editors/MemberController.cs index 909189b7ad..2a3bb4399b 100644 --- a/src/Umbraco.Web/Editors/MemberController.cs +++ b/src/Umbraco.Web/Editors/MemberController.cs @@ -73,15 +73,16 @@ namespace Umbraco.Web.Editors get { return Services.MemberService.GetMembershipScenario(); } } - public PagedResult GetPagedResults( + public PagedResult GetPagedResults( int pageNumber = 1, int pageSize = 100, string orderBy = "Name", Direction orderDirection = Direction.Ascending, + bool orderBySystemField = true, string filter = "", string memberTypeAlias = null) { - + if (pageNumber <= 0 || pageSize <= 0) { throw new NotSupportedException("Both pageNumber and pageSize must be greater than zero"); @@ -90,7 +91,9 @@ namespace Umbraco.Web.Editors if (MembershipScenario == MembershipScenario.NativeUmbraco) { long totalRecords; - var members = Services.MemberService.GetAll((pageNumber - 1), pageSize, out totalRecords, orderBy, orderDirection, memberTypeAlias, filter).ToArray(); + var members = Services.MemberService + .GetAll((pageNumber - 1), pageSize, out totalRecords, orderBy, orderDirection, orderBySystemField + , memberTypeAlias, filter).ToArray(); if (totalRecords == 0) { return new PagedResult(0, 0, 0); @@ -114,7 +117,7 @@ namespace Umbraco.Web.Editors .Select(Mapper.Map); return pagedResult; } - + } /// @@ -162,23 +165,23 @@ namespace Umbraco.Web.Editors return Mapper.Map(foundMember); case MembershipScenario.CustomProviderWithUmbracoLink: - //TODO: Support editing custom properties for members with a custom membership provider here. + //TODO: Support editing custom properties for members with a custom membership provider here. - //foundMember = Services.MemberService.GetByKey(key); - //if (foundMember == null) - //{ - // HandleContentNotFound(key); - //} - //foundMembershipMember = Membership.GetUser(key, false); - //if (foundMembershipMember == null) - //{ - // HandleContentNotFound(key); - //} + //foundMember = Services.MemberService.GetByKey(key); + //if (foundMember == null) + //{ + // HandleContentNotFound(key); + //} + //foundMembershipMember = Membership.GetUser(key, false); + //if (foundMembershipMember == null) + //{ + // HandleContentNotFound(key); + //} - //display = Mapper.Map(foundMembershipMember); - ////map the name over - //display.Name = foundMember.Name; - //return display; + //display = Mapper.Map(foundMembershipMember); + ////map the name over + //display.Name = foundMember.Name; + //return display; case MembershipScenario.StandaloneCustomProvider: default: @@ -219,7 +222,7 @@ namespace Umbraco.Web.Editors emptyContent.AdditionalData["NewPassword"] = Membership.GeneratePassword(Membership.MinRequiredPasswordLength, Membership.MinRequiredNonAlphanumericCharacters); return Mapper.Map(emptyContent); case MembershipScenario.CustomProviderWithUmbracoLink: - //TODO: Support editing custom properties for members with a custom membership provider here. + //TODO: Support editing custom properties for members with a custom membership provider here. case MembershipScenario.StandaloneCustomProvider: default: @@ -275,7 +278,7 @@ namespace Umbraco.Web.Editors { throw new NotSupportedException("Currently the member editor does not support providers that have RequiresQuestionAndAnswer specified"); } - + //We're gonna look up the current roles now because the below code can cause // events to be raised and developers could be manually adding roles to members in // their handlers. If we don't look this up now there's a chance we'll just end up @@ -324,7 +327,7 @@ namespace Umbraco.Web.Editors //create/save the IMember Services.MemberService.Save(contentItem.PersistedContent); } - + //Now let's do the role provider stuff - now that we've saved the content item (that is important since // if we are changing the username, it must be persisted before looking up the member roles). if (rolesToRemove.Any()) @@ -504,7 +507,7 @@ namespace Umbraco.Web.Editors private void RefetchMemberData(MemberSave contentItem, LookupType lookup) { var currProps = contentItem.PersistedContent.Properties.ToArray(); - + switch (MembershipScenario) { case MembershipScenario.NativeUmbraco: @@ -512,11 +515,11 @@ namespace Umbraco.Web.Editors { case LookupType.ByKey: //Go and re-fetch the persisted item - contentItem.PersistedContent = Services.MemberService.GetByKey(contentItem.Key); + contentItem.PersistedContent = Services.MemberService.GetByKey(contentItem.Key); break; case LookupType.ByUserName: contentItem.PersistedContent = Services.MemberService.GetByUsername(contentItem.Username.Trim()); - break; + break; } break; case MembershipScenario.CustomProviderWithUmbracoLink: @@ -524,14 +527,14 @@ namespace Umbraco.Web.Editors default: var membershipUser = _provider.GetUser(contentItem.Key, false); //Go and re-fetch the persisted item - contentItem.PersistedContent = Mapper.Map(membershipUser); + contentItem.PersistedContent = Mapper.Map(membershipUser); break; } UpdateName(contentItem); //re-assign the mapped values that are not part of the membership provider properties. - var builtInAliases = Constants.Conventions.Member.GetStandardPropertyTypeStubs().Select(x => x.Key).ToArray(); + var builtInAliases = Constants.Conventions.Member.GetStandardPropertyTypeStubs().Select(x => x.Key).ToArray(); foreach (var p in contentItem.PersistedContent.Properties) { var valueMapped = currProps.SingleOrDefault(x => x.Alias == p.Alias); @@ -542,7 +545,7 @@ namespace Umbraco.Web.Editors p.TagSupport.Enable = valueMapped.TagSupport.Enable; p.TagSupport.Tags = valueMapped.TagSupport.Tags; } - } + } } /// @@ -595,7 +598,7 @@ namespace Umbraco.Web.Editors contentItem.IsApproved, Guid.NewGuid(), //since it's the umbraco provider, the user key here doesn't make any difference out status); - + break; case MembershipScenario.CustomProviderWithUmbracoLink: //We are using a custom membership provider, we'll create an empty IMember first to get the unique id to use @@ -618,7 +621,7 @@ namespace Umbraco.Web.Editors case MembershipScenario.StandaloneCustomProvider: // we don't have a member type to use so we will just create the basic membership user with the provider with no // link back to the umbraco data - + var newKey = Guid.NewGuid(); //TODO: We are not supporting q/a - passing in empty here membershipUser = _provider.CreateUser( @@ -628,9 +631,9 @@ namespace Umbraco.Web.Editors "TEMP", //some membership provider's require something here even if q/a is disabled! "TEMP", //some membership provider's require something here even if q/a is disabled! contentItem.IsApproved, - newKey, + newKey, out status); - + break; default: throw new ArgumentOutOfRangeException(); @@ -685,12 +688,12 @@ namespace Umbraco.Web.Editors break; case MembershipCreateStatus.InvalidProviderUserKey: ModelState.AddPropertyError( - //specify 'default' just so that it shows up as a notification - is not assigned to a property + //specify 'default' just so that it shows up as a notification - is not assigned to a property new ValidationResult("Invalid provider user key"), "default"); break; case MembershipCreateStatus.DuplicateProviderUserKey: ModelState.AddPropertyError( - //specify 'default' just so that it shows up as a notification - is not assigned to a property + //specify 'default' just so that it shows up as a notification - is not assigned to a property new ValidationResult("Duplicate provider user key"), "default"); break; case MembershipCreateStatus.ProviderError: diff --git a/src/Umbraco.Web/WebApi/Filters/DisableBrowserCacheAttribute.cs b/src/Umbraco.Web/WebApi/Filters/DisableBrowserCacheAttribute.cs index e1890326fb..edd1792e0e 100644 --- a/src/Umbraco.Web/WebApi/Filters/DisableBrowserCacheAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/DisableBrowserCacheAttribute.cs @@ -1,50 +1,54 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Web; -using System.Web.Http.Controllers; -using System.Web.Http.Filters; -using Umbraco.Core; - -namespace Umbraco.Web.WebApi.Filters -{ - /// - /// Ensures that the request is not cached by the browser - /// - public class DisableBrowserCacheAttribute : ActionFilterAttribute - { - public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) - { - //See: http://stackoverflow.com/questions/17755239/how-to-stop-chrome-from-caching-rest-response-from-webapi - - base.OnActionExecuted(actionExecutedContext); - - //NOTE: Until we upgraded to WebApi 2, this didn't work correctly and we had to revert to using - // HttpContext.Current responses. I've changed this back to what it should be now since it works - // and now with WebApi2, the HttpContext.Current responses dont! Anyways, all good now. - actionExecutedContext.Response.Headers.CacheControl = new CacheControlHeaderValue() - { - NoCache = true, - NoStore = true, - MaxAge = new TimeSpan(0), - MustRevalidate = true - }; - - actionExecutedContext.Response.Headers.Pragma.Add(new NameValueHeaderValue("no-cache")); - if (actionExecutedContext.Response.Content != null) - { - actionExecutedContext.Response.Content.Headers.Expires = - //Mon, 01 Jan 1990 00:00:00 GMT - new DateTimeOffset(1990, 1, 1, 0, 0, 0, TimeSpan.Zero); - } - - - - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +using System.Web.Http.Controllers; +using System.Web.Http.Filters; +using Umbraco.Core; + +namespace Umbraco.Web.WebApi.Filters +{ + /// + /// Ensures that the request is not cached by the browser + /// + public class DisableBrowserCacheAttribute : ActionFilterAttribute + { + public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) + { + //See: http://stackoverflow.com/questions/17755239/how-to-stop-chrome-from-caching-rest-response-from-webapi + + base.OnActionExecuted(actionExecutedContext); + if (actionExecutedContext == null || actionExecutedContext.Response == null || + actionExecutedContext.Response.Headers == null) + { + return; + } + //NOTE: Until we upgraded to WebApi 2, this didn't work correctly and we had to revert to using + // HttpContext.Current responses. I've changed this back to what it should be now since it works + // and now with WebApi2, the HttpContext.Current responses dont! Anyways, all good now. + actionExecutedContext.Response.Headers.CacheControl = new CacheControlHeaderValue() + { + NoCache = true, + NoStore = true, + MaxAge = new TimeSpan(0), + MustRevalidate = true + }; + + actionExecutedContext.Response.Headers.Pragma.Add(new NameValueHeaderValue("no-cache")); + if (actionExecutedContext.Response.Content != null) + { + actionExecutedContext.Response.Content.Headers.Expires = + //Mon, 01 Jan 1990 00:00:00 GMT + new DateTimeOffset(1990, 1, 1, 0, 0, 0, TimeSpan.Zero); + } + + + + } + } +} diff --git a/src/UmbracoExamine/UmbracoMemberIndexer.cs b/src/UmbracoExamine/UmbracoMemberIndexer.cs index 873391da50..4a460e0f38 100644 --- a/src/UmbracoExamine/UmbracoMemberIndexer.cs +++ b/src/UmbracoExamine/UmbracoMemberIndexer.cs @@ -16,8 +16,8 @@ using Lucene.Net.Analysis; namespace UmbracoExamine { - - /// + + /// /// Custom indexer for members /// public class UmbracoMemberIndexer : UmbracoContentIndexer @@ -26,29 +26,29 @@ namespace UmbracoExamine private readonly IMemberService _memberService; private readonly IDataTypeService _dataTypeService; - /// - /// Default constructor - /// - public UmbracoMemberIndexer() : base() - { + /// + /// Default constructor + /// + public UmbracoMemberIndexer() : base() + { _dataTypeService = ApplicationContext.Current.Services.DataTypeService; _memberService = ApplicationContext.Current.Services.MemberService; - } + } - /// - /// Constructor to allow for creating an indexer at runtime - /// - /// - /// - /// - /// - [Obsolete("Use the overload that specifies the Umbraco services")] - public UmbracoMemberIndexer(IIndexCriteria indexerData, DirectoryInfo indexPath, IDataService dataService, Analyzer analyzer, bool async) - : base(indexerData, indexPath, dataService, analyzer, async) - { + /// + /// Constructor to allow for creating an indexer at runtime + /// + /// + /// + /// + /// + [Obsolete("Use the overload that specifies the Umbraco services")] + public UmbracoMemberIndexer(IIndexCriteria indexerData, DirectoryInfo indexPath, IDataService dataService, Analyzer analyzer, bool async) + : base(indexerData, indexPath, dataService, analyzer, async) + { _dataTypeService = ApplicationContext.Current.Services.DataTypeService; _memberService = ApplicationContext.Current.Services.MemberService; - } + } /// /// Constructor to allow for creating an indexer at runtime @@ -60,19 +60,19 @@ namespace UmbracoExamine /// /// /// - public UmbracoMemberIndexer(IIndexCriteria indexerData, DirectoryInfo indexPath, IDataService dataService, - IDataTypeService dataTypeService, - IMemberService memberService, - Analyzer analyzer, bool async) - : base(indexerData, indexPath, dataService, analyzer, async) - { + public UmbracoMemberIndexer(IIndexCriteria indexerData, DirectoryInfo indexPath, IDataService dataService, + IDataTypeService dataTypeService, + IMemberService memberService, + Analyzer analyzer, bool async) + : base(indexerData, indexPath, dataService, analyzer, async) + { _dataTypeService = dataTypeService; _memberService = memberService; - } + } - - /// + + /// /// Ensures that the'_searchEmail' is added to the user fields so that it is indexed - without having to modify the config /// /// @@ -87,7 +87,7 @@ namespace UmbracoExamine if (indexerData.UserFields.Any(x => x.Name == "_searchEmail") == false) { - var field = new IndexField {Name = "_searchEmail"}; + var field = new IndexField { Name = "_searchEmail" }; var policy = IndexFieldPolicies.FirstOrDefault(x => x.Name == "_searchEmail"); if (policy != null) { @@ -97,7 +97,7 @@ namespace UmbracoExamine return new IndexCriteria( indexerData.StandardFields, - indexerData.UserFields.Concat(new[] {field}), + indexerData.UserFields.Concat(new[] { field }), indexerData.IncludeNodeTypes, indexerData.ExcludeNodeTypes, indexerData.ParentNodeId @@ -105,10 +105,10 @@ namespace UmbracoExamine } } - return indexerData; + return indexerData; } - /// + /// /// The supported types for this indexer /// protected override IEnumerable SupportedTypes @@ -119,39 +119,40 @@ namespace UmbracoExamine } } - /// - /// Reindex all members - /// - /// - protected override void PerformIndexAll(string type) - { + /// + /// Reindex all members + /// + /// + protected override void PerformIndexAll(string type) + { //This only supports members if (SupportedTypes.Contains(type) == false) return; - + const int pageSize = 1000; var pageIndex = 0; IMember[] members; if (IndexerData.IncludeNodeTypes.Any()) - { + { //if there are specific node types then just index those foreach (var nodeType in IndexerData.IncludeNodeTypes) - { + { do { long total; - members = _memberService.GetAll(pageIndex, pageSize, out total, "LoginName", Direction.Ascending, nodeType).ToArray(); + members = _memberService.GetAll(pageIndex, pageSize, out total, "LoginName" + , Direction.Ascending, true, nodeType).ToArray(); AddNodesToIndex(GetSerializedMembers(members), type); pageIndex++; } while (members.Length == pageSize); - } - } - else - { + } + } + else + { //no node types specified, do all members do { @@ -162,8 +163,8 @@ namespace UmbracoExamine pageIndex++; } while (members.Length == pageSize); - } - } + } + } private IEnumerable GetSerializedMembers(IEnumerable members) { @@ -171,18 +172,18 @@ namespace UmbracoExamine return members.Select(member => serializer.Serialize(_dataTypeService, member)); } - protected override XDocument GetXDocument(string xPath, string type) - { - throw new NotSupportedException(); - } - + protected override XDocument GetXDocument(string xPath, string type) + { + throw new NotSupportedException(); + } + protected override Dictionary GetSpecialFieldsToIndex(Dictionary allValuesForIndexing) { var fields = base.GetSpecialFieldsToIndex(allValuesForIndexing); //adds the special path property to the index fields.Add("__key", allValuesForIndexing["__key"]); - + return fields; } @@ -207,14 +208,14 @@ namespace UmbracoExamine if (e.Fields.ContainsKey("_searchEmail") == false) e.Fields.Add("_searchEmail", e.Node.Attribute("email").Value.Replace(".", " ").Replace("@", " ")); } - + if (e.Fields.ContainsKey(IconFieldName) == false) e.Fields.Add(IconFieldName, (string)e.Node.Attribute("icon")); } private static XElement GetMemberItem(int nodeId) { - //TODO: Change this so that it is not using the LegacyLibrary, just serialize manually! + //TODO: Change this so that it is not using the LegacyLibrary, just serialize manually! var nodes = LegacyLibrary.GetMember(nodeId); return XElement.Parse(nodes.Current.OuterXml); }