diff --git a/src/Umbraco.Core/Constants-Conventions.cs b/src/Umbraco.Core/Constants-Conventions.cs index da08bd631a..11255af8e2 100644 --- a/src/Umbraco.Core/Constants-Conventions.cs +++ b/src/Umbraco.Core/Constants-Conventions.cs @@ -11,6 +11,11 @@ namespace Umbraco.Core /// public static class Conventions { + public static class DataTypes + { + public const string ListViewPrefix = "List View - "; + } + public static class PropertyGroups { public const string ListViewGroupName = "umbContainerView"; diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs index 13f47cf85b..8debd76056 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs @@ -112,9 +112,9 @@ namespace Umbraco.Core.Persistence.Migrations.Initial _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -38, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-38", SortOrder = 2, UniqueId = new Guid("fd9f1447-6c61-4a7c-9595-5aa39147d318"), Text = "Folder Browser", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -37, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-37", SortOrder = 2, UniqueId = new Guid("0225af17-b302-49cb-9176-b9f35cab9c17"), Text = "Approved Color", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -36, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-36", SortOrder = 2, UniqueId = new Guid("e4d66c0f-b935-4200-81f0-025f7256b89a"), Text = "Date Picker with time", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); - _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultContentListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-95", SortOrder = 2, UniqueId = new Guid("C0808DD3-8133-4E4B-8CE8-E2BEA84A96A4"), Text = "List View - Content", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); - _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultMediaListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-96", SortOrder = 2, UniqueId = new Guid("3A0156C4-3B8C-4803-BDC1-6871FAA83FFF"), Text = "List View - Media", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); - _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultMembersListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-97", SortOrder = 2, UniqueId = new Guid("AA2C52A0-CE87-4E65-A47C-7DF09358585D"), Text = "List View - Members", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); + _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultContentListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-95", SortOrder = 2, UniqueId = new Guid("C0808DD3-8133-4E4B-8CE8-E2BEA84A96A4"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Content", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); + _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultMediaListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-96", SortOrder = 2, UniqueId = new Guid("3A0156C4-3B8C-4803-BDC1-6871FAA83FFF"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Media", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); + _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultMembersListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-97", SortOrder = 2, UniqueId = new Guid("AA2C52A0-CE87-4E65-A47C-7DF09358585D"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Members", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1031, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1031", SortOrder = 2, UniqueId = new Guid("f38bd2d7-65d0-48e6-95dc-87ce06ec2d3d"), Text = Constants.Conventions.MediaTypes.Folder, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1032, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1032", SortOrder = 2, UniqueId = new Guid("cc07b313-0843-4aa8-bbda-871c8da728c8"), Text = Constants.Conventions.MediaTypes.Image, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1033, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1033", SortOrder = 2, UniqueId = new Guid("4c52d8ab-54e6-40cd-999c-7a5f24903e4d"), Text = Constants.Conventions.MediaTypes.File, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now }); diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs index 2c43a90773..d65b04b9e0 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs @@ -72,11 +72,6 @@ namespace Umbraco.Core.Persistence.Repositories return content; - //var dtos = - // Database.Fetch( - // new PropertyDataRelator().Map, sql); - - //return BuildFromDto(dtos, sql); } protected override IEnumerable PerformGetAll(params int[] ids) @@ -88,20 +83,7 @@ namespace Umbraco.Core.Persistence.Repositories } return ProcessQuery(sql); - - //var sql = GetBaseQuery(false); - //if (ids.Any()) - //{ - // var statement = string.Join(" OR ", ids.Select(x => string.Format("umbracoNode.id='{0}'", x))); - // sql.Where(statement); - //} - //sql.OrderByDescending(x => x.VersionDate); - - //var dtos = - // Database.Fetch( - // new PropertyDataRelator().Map, sql); - - //return BuildFromDtos(dtos, sql); + } protected override IEnumerable PerformGetByQuery(IQuery query) @@ -112,6 +94,7 @@ namespace Umbraco.Core.Persistence.Repositories var query1 = query as Query; if (query1 == null) throw new Exception("Query cannot be null"); + var wheres = query1.WhereClauses(); //this is a pretty rudimentary check but wil work, we just need to know if this query requires property // level queries @@ -135,21 +118,6 @@ namespace Umbraco.Core.Persistence.Repositories return ProcessQuery(sql); } - - - //var sqlSubquery = GetSubquery(); - //var translator = new SqlTranslator(sqlSubquery, query); - //var subquery = translator.Translate(); - //var sql = GetBaseQuery(false) - // .Append(new Sql("WHERE umbracoNode.id IN (" + subquery.SQL + ")", subquery.Arguments)) - // .OrderByDescending(x => x.VersionDate) - // .OrderBy(x => x.SortOrder); - - //var dtos = - // Database.Fetch( - // new PropertyDataRelator().Map, sql); - - //return BuildFromDtos(dtos, sql); } #endregion @@ -164,45 +132,16 @@ namespace Umbraco.Core.Persistence.Repositories .InnerJoin() .On(left => left.NodeId, right => right.NodeId) .InnerJoin() - .On(left => left.NodeId, right => right.NodeId) + .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? + // the execution plan says it doesn't so we'll go with that and in that case, it might be worth joining the content + // types by default on the document and media repo's so we can query by content type there too. + .InnerJoin().On(left => left.NodeId, right => right.ContentTypeId) .InnerJoin() .On(left => left.NodeId, right => right.NodeId) .Where(x => x.NodeObjectType == NodeObjectTypeId); return sql; - //var sql = new Sql(); - - //if (isCount) - //{ - // sql.Select("COUNT(*)") - // .From() - // .InnerJoin().On(left => left.NodeId, right => right.NodeId) - // .InnerJoin().On(left => left.NodeId, right => right.ContentTypeId) - // .InnerJoin().On(left => left.NodeId, right => right.NodeId) - // .InnerJoin().On(left => left.NodeId, right => right.NodeId) - // .Where(x => x.NodeObjectType == NodeObjectTypeId); - // return sql; - //} - - //sql.Select("umbracoNode.*", "cmsContent.contentType", "cmsContentType.alias AS ContentTypeAlias", "cmsContentVersion.VersionId", - // "cmsContentVersion.VersionDate", "cmsContentVersion.LanguageLocale", "cmsMember.Email", - // "cmsMember.LoginName", "cmsMember.Password", "cmsPropertyData.id AS PropertyDataId", "cmsPropertyData.propertytypeid", - // "cmsPropertyData.dataDate", "cmsPropertyData.dataInt", "cmsPropertyData.dataNtext", "cmsPropertyData.dataNvarchar", - // "cmsPropertyType.id", "cmsPropertyType.Alias", "cmsPropertyType.Description", - // "cmsPropertyType.Name", "cmsPropertyType.mandatory", "cmsPropertyType.validationRegExp", - // "cmsPropertyType.helpText", "cmsPropertyType.sortOrder AS PropertyTypeSortOrder", "cmsPropertyType.propertyTypeGroupId", - // "cmsPropertyType.dataTypeId", "cmsDataType.propertyEditorAlias", "cmsDataType.dbType") - // .From() - // .InnerJoin().On(left => left.NodeId, right => right.NodeId) - // .InnerJoin().On(left => left.NodeId, right => right.ContentTypeId) - // .InnerJoin().On(left => left.NodeId, right => right.NodeId) - // .InnerJoin().On(left => left.NodeId, right => right.NodeId) - // .LeftJoin().On(left => left.ContentTypeId, right => right.ContentTypeId) - // .LeftJoin().On(left => left.DataTypeId, right => right.DataTypeId) - // .LeftJoin().On(left => left.PropertyTypeId, right => right.Id) - // .Append("AND cmsPropertyData.versionId = cmsContentVersion.VersionId") - // .Where(x => x.NodeObjectType == NodeObjectTypeId); - //return sql; } protected override string GetBaseWhereClause() @@ -506,15 +445,6 @@ namespace Umbraco.Core.Persistence.Repositories ((Entity)media).ResetDirtyProperties(false); return media; - //var sql = GetBaseQuery(false); - //sql.Where(x => x.VersionId == versionId); - //sql.OrderByDescending(x => x.VersionDate); - - //var dtos = - // Database.Fetch( - // new PropertyDataRelator().Map, sql); - - //return BuildFromDto(dtos, sql); } protected override void PerformDeleteVersion(int id, Guid versionId) @@ -591,18 +521,14 @@ namespace Umbraco.Core.Persistence.Repositories var subQuery = new Sql().Select("Member").From().Where(dto => dto.MemberGroup == memberGroup.Id); var sql = GetBaseQuery(false) - //TODO: This is NOT great!, do an inner join! + //TODO: An inner join would be better, though I've read that the query optimizer will always turn a + // subquery with an IN clause into an inner join anyways. .Append(new Sql("WHERE umbracoNode.id IN (" + subQuery.SQL + ")", subQuery.Arguments)) .OrderByDescending(x => x.VersionDate) .OrderBy(x => x.SortOrder); return ProcessQuery(sql); - //var dtos = - // Database.Fetch( - // new PropertyDataRelator().Map, sql); - - //return BuildFromDtos(dtos, sql); } public bool Exists(string username) @@ -653,7 +579,8 @@ namespace Umbraco.Core.Persistence.Repositories ProcessQuery, orderBy, orderDirection, filter.IsNullOrWhiteSpace() ? (Func) null - : () => "AND (cmsMember.LoginName LIKE '%" + filter + "%')"); + : () => "AND ((umbracoNode. " + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + " LIKE '%" + filter + "%') " + + "OR (cmsMember.LoginName LIKE '%" + filter + "%'))"); } public void AddOrUpdateContentXml(IMember content, Func xml) @@ -733,7 +660,7 @@ namespace Umbraco.Core.Persistence.Repositories /// /// Private method to create a member object from a MemberDto /// - /// + /// /// /// /// @@ -755,7 +682,7 @@ namespace Umbraco.Core.Persistence.Repositories /// /// Private method to create a member object from a MemberDto /// - /// + /// /// /// /// diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index 3cfd97d32e..8408a61296 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -117,10 +117,10 @@ namespace Umbraco.Core.Services /// Page size /// Total records query would return without paging /// Field to order by - /// Direction to order by + /// Direction to order by /// Search text filter /// An Enumerable list of objects - IEnumerable GetPagedChildren(int id, int pageIndex, int pageSize, out int totalChildren, + IEnumerable GetPagedChildren(int id, int pageIndex, int pageSize, out int totalRecords, string orderBy, Direction orderDirection, string filter = ""); /// diff --git a/src/Umbraco.Core/Services/IMediaService.cs b/src/Umbraco.Core/Services/IMediaService.cs index aa7d5c49e6..bfef76b1ec 100644 --- a/src/Umbraco.Core/Services/IMediaService.cs +++ b/src/Umbraco.Core/Services/IMediaService.cs @@ -70,10 +70,10 @@ namespace Umbraco.Core.Services /// Page size /// Total records query would return without paging /// Field to order by - /// Direction to order by + /// Direction to order by /// Search text filter /// An Enumerable list of objects - IEnumerable GetPagedChildren(int id, int pageIndex, int pageSize, out int totalChildren, + IEnumerable GetPagedChildren(int id, int pageIndex, int pageSize, out int totalRecords, string orderBy, Direction orderDirection, string filter = ""); /// diff --git a/src/Umbraco.Core/Services/IMemberService.cs b/src/Umbraco.Core/Services/IMemberService.cs index 82c21dd2fc..49a3612f30 100644 --- a/src/Umbraco.Core/Services/IMemberService.cs +++ b/src/Umbraco.Core/Services/IMemberService.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using Umbraco.Core.Models; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Querying; namespace Umbraco.Core.Services @@ -10,6 +12,21 @@ namespace Umbraco.Core.Services /// public interface IMemberService : IMembershipMemberService { + /// + /// Gets a list of paged objects + /// + /// An can be of type + /// Current page index + /// Size of the page + /// Total number of records found (out) + /// + /// + /// + /// + /// + IEnumerable GetAll(int pageIndex, int pageSize, out int totalRecords, + string orderBy, Direction orderDirection, string memberTypeAlias = null, string filter = ""); + /// /// Creates an object without persisting it /// diff --git a/src/Umbraco.Core/Services/MemberService.cs b/src/Umbraco.Core/Services/MemberService.cs index 6002086189..5322bb667e 100644 --- a/src/Umbraco.Core/Services/MemberService.cs +++ b/src/Umbraco.Core/Services/MemberService.cs @@ -659,6 +659,21 @@ namespace Umbraco.Core.Services } } + public IEnumerable GetAll(int pageIndex, int pageSize, out int totalRecords, + string orderBy, Direction orderDirection, 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); + } + var query = new Query().Where(x => x.ContentTypeAlias == memberTypeAlias); + return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filter); + } + } + /// /// Gets the count of Members by an optional MemberType alias /// diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/editors/umbcontentname.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/editors/umbcontentname.directive.js index fb1daabea3..02f78d8611 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/editors/umbcontentname.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/editors/umbcontentname.directive.js @@ -15,7 +15,8 @@ angular.module("umbraco.directives") templateUrl: 'views/directives/umb-content-name.html', scope: { placeholder: '@placeholder', - model: '=ngModel' + model: '=ngModel', + ngDisabled: '=' }, link: function(scope, element, attrs, ngModel) { 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 65a53d233d..381019fb5b 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 @@ -23,7 +23,65 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) { return { + getPagedResults: function (memberTypeAlias, options) { + + if (memberTypeAlias === 'all-members') { + memberTypeAlias = null; + } + + 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"; + } + + var params = [ + { pageNumber: options.pageNumber }, + { pageSize: options.pageSize }, + { orderBy: options.orderBy }, + { orderDirection: options.orderDirection }, + { filter: options.filter } + ]; + if (memberTypeAlias != null) { + params.push({ memberTypeAlias: memberTypeAlias }); + } + + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "memberApiBaseUrl", + "GetPagedResults", + params)), + 'Failed to retrieve member paged result'); + }, + getListNode: function (listName) { + + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "memberApiBaseUrl", + "GetListNodeDisplay", + [{ listName: listName }])), + 'Failed to retrieve data for member list ' + listName); + }, + /** * @ngdoc method * @name umbraco.resources.memberResource#getByKey diff --git a/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js index f4f71c19d0..709bcd7fce 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js @@ -10,8 +10,7 @@ function ContentEditController($scope, $rootScope, $routeParams, $q, $timeout, $ //setup scope vars $scope.defaultButton = null; - $scope.subButtons = []; - $scope.nav = navigationService; + $scope.subButtons = []; $scope.currentSection = appState.getSectionState("currentSection"); $scope.currentNode = null; //the editors affiliated node diff --git a/src/Umbraco.Web.UI.Client/src/views/datatype/datatype.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/datatype/datatype.edit.controller.js index 7f713c0322..9731e6a63f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/datatype/datatype.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/datatype/datatype.edit.controller.js @@ -8,8 +8,7 @@ */ function DataTypeEditController($scope, $routeParams, $location, appState, navigationService, treeService, dataTypeResource, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, formHelper, editorState) { - //setup scope vars - $scope.nav = navigationService; + //setup scope vars $scope.currentSection = appState.getSectionState("currentSection"); $scope.currentNode = null; //the editors affiliated node diff --git a/src/Umbraco.Web.UI.Client/src/views/datatype/edit.html b/src/Umbraco.Web.UI.Client/src/views/datatype/edit.html index b27d326088..4d365174fb 100644 --- a/src/Umbraco.Web.UI.Client/src/views/datatype/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/datatype/edit.html @@ -7,8 +7,9 @@ -
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/directives/umb-content-name.html b/src/Umbraco.Web.UI.Client/src/views/directives/umb-content-name.html index 314015f91b..85929d1e1b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/directives/umb-content-name.html +++ b/src/Umbraco.Web.UI.Client/src/views/directives/umb-content-name.html @@ -2,6 +2,7 @@
+ + + +
+

{{content.name}}

+
+ +
+ + + +
+ + + + + +
+
+ +
+
+ \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/member/member.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/member/member.edit.controller.js index bafa29bfd9..d610441b9c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/member/member.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/member/member.edit.controller.js @@ -9,7 +9,6 @@ function MemberEditController($scope, $routeParams, $location, $q, $window, appState, memberResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, formHelper, umbModelMapper, editorState) { //setup scope vars - $scope.nav = navigationService; $scope.currentSection = appState.getSectionState("currentSection"); $scope.currentNode = null; //the editors affiliated node diff --git a/src/Umbraco.Web.UI.Client/src/views/member/member.list.controller.js b/src/Umbraco.Web.UI.Client/src/views/member/member.list.controller.js new file mode 100644 index 0000000000..7b4d30bae6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/member/member.list.controller.js @@ -0,0 +1,43 @@ +/** + * @ngdoc controller + * @name Umbraco.Editors.Member.ListController + * @function + * + * @description + * The controller for the member list view + */ +function MemberListController($scope, $routeParams, $location, $q, $window, appState, memberResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, formHelper, umbModelMapper, editorState) { + + //setup scope vars + $scope.currentSection = appState.getSectionState("currentSection"); + $scope.currentNode = null; //the editors affiliated node + + //build a path to sync the tree with + function buildTreePath(data) { + var path = data.name[0].toLowerCase() + "," + data.key; + return path; + } + + //we are editing so get the content item from the server + memberResource.getListNode($routeParams.id) + .then(function (data) { + $scope.loaded = true; + $scope.content = data; + + editorState.set($scope.content); + + var path = buildTreePath(data); + + navigationService.syncTree({ tree: "member", path: path.split(",") }).then(function (syncArgs) { + $scope.currentNode = syncArgs.node; + }); + + //in one particular special case, after we've created a new item we redirect back to the edit + // route but there might be server validation errors in the collection which we need to display + // after the redirect, so we will bind all subscriptions which will show the server validation errors + // if there are any and then clear them so the collection no longer persists them. + serverValidationManager.executeAndClearAllSubscriptions(); + }); +} + +angular.module("umbraco").controller("Umbraco.Editors.Member.ListController", MemberListController); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/includeproperties.prevalues.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/includeproperties.prevalues.controller.js index 48f443b660..a9863e28ab 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/includeproperties.prevalues.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/includeproperties.prevalues.controller.js @@ -42,7 +42,7 @@ function includePropsPreValsController($rootScope, $scope, localizationService, $scope.removeField = function(e) { $scope.model.value = _.reject($scope.model.value, function (x) { return x.alias === e.alias; - }); + }); } //now we'll localize these strings, for some reason the directive doesn't work inside of the select group with an ng-model declared @@ -50,6 +50,16 @@ function includePropsPreValsController($rootScope, $scope, localizationService, var key = $scope.getLocalizedKey(e.value); localizationService.localize(key).then(function (v) { e.name = v; + + switch (e.value) { + case "updater": + e.name += " (Content only)"; + break; + case "published": + e.name += " (Content only)"; + break; + } + }); }); 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 5c68ad5b03..cd41745613 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 @@ -9,19 +9,35 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific return; } - //Now we need to check if this is for media or content because that will depend on the resources we use - //TODO: Check for members!! - var contentResource, contentTypeResource; + //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; - if ($scope.model.config.entityType && $scope.model.config.entityType === "media") { - contentResource = $injector.get('mediaResource'); - contentTypeResource = $injector.get('mediaTypeResource'); - $scope.entityType = "media"; + if ($scope.model.config.entityType && $scope.model.config.entityType === "member") { + contentResource = $injector.get('memberResource'); + getContentTypesCallback = $injector.get('memberTypeResource').getTypes; + getListResultsCallback = contentResource.getPagedResults; + deleteItemCallback = contentResource.deleteByKey; + getIdCallback = function(selected) { + return selected.key; + } + $scope.entityType = "member"; } else { - contentResource = $injector.get('contentResource'); - contentTypeResource = $injector.get('contentTypeResource'); - $scope.entityType = "content"; + if ($scope.model.config.entityType && $scope.model.config.entityType === "media") { + contentResource = $injector.get('mediaResource'); + getContentTypesCallback = $injector.get('mediaTypeResource').getAllowedTypes; + $scope.entityType = "media"; + } + else { + contentResource = $injector.get('contentResource'); + getContentTypesCallback = $injector.get('contentTypeResource').getAllowedTypes; + $scope.entityType = "content"; + } + getListResultsCallback = contentResource.getChildren; + deleteItemCallback = contentResource.deleteById; + getIdCallback = function (selected) { + return selected.id; + } } $scope.isNew = false; @@ -116,7 +132,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific with simple values */ $scope.reloadView = function(id) { - contentResource.getChildren(id, $scope.options).then(function(data) { + getListResultsCallback(id, $scope.options).then(function (data) { $scope.listViewResultSet = data; //update all values for display @@ -196,7 +212,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific for (var i = 0; i < selected.length; i++) { $scope.bulkStatus = "Deleted doc " + current + " out of " + total + " documents"; - contentResource.deleteById(selected[i].id).then(function(data) { + deleteItemCallback(getIdCallback(selected[i])).then(function (data) { if (current === total) { notificationsService.success("Bulk action", "Deleted " + total + "documents"); $scope.bulkStatus = ""; @@ -226,7 +242,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific for (var i = 0; i < selected.length; i++) { $scope.bulkStatus = "Publishing " + current + " out of " + total + " documents"; - contentResource.publishById(selected[i].id) + contentResource.publishById(getIdCallback(selected[i])) .then(function(content) { if (current == total) { notificationsService.success("Bulk action", "Published " + total + "documents"); @@ -269,7 +285,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific for (var i = 0; i < selected.length; i++) { $scope.bulkStatus = "Unpublishing " + current + " out of " + total + " documents"; - contentResource.unPublish(selected[i].id) + contentResource.unPublish(getIdCallback(selected[i])) .then(function(content) { if (current == total) { @@ -356,7 +372,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific function initView() { if ($routeParams.id) { $scope.pagination = new Array(10); - $scope.listViewAllowedTypes = contentTypeResource.getAllowedTypes($routeParams.id); + $scope.listViewAllowedTypes = getContentTypesCallback($routeParams.id); $scope.contentId = $routeParams.id; $scope.isTrashed = $routeParams.id === "-20" || $routeParams.id === "-21"; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/sortby.prevalues.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/sortby.prevalues.controller.js index b79dd62256..08e0c95376 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/sortby.prevalues.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/sortby.prevalues.controller.js @@ -15,6 +15,15 @@ function sortByPreValsController($rootScope, $scope, localizationService) { _.each($scope.sortByFields, function (e, i) { localizationService.localize(e.key).then(function (v) { e.name = v; + + switch (e.value) { + case "Updater": + e.name += " (Content only)"; + break; + case "Published": + e.name += " (Content only)"; + break; + } }); }); diff --git a/src/Umbraco.Web/Editors/MemberController.cs b/src/Umbraco.Web/Editors/MemberController.cs index 1c9486c67d..8c8768f37d 100644 --- a/src/Umbraco.Web/Editors/MemberController.cs +++ b/src/Umbraco.Web/Editors/MemberController.cs @@ -18,8 +18,10 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Security; using Umbraco.Core.Services; +using Umbraco.Web.Models.Mapping; using Umbraco.Web.WebApi; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; @@ -70,6 +72,60 @@ namespace Umbraco.Web.Editors get { return Services.MemberService.GetMembershipScenario(); } } + public PagedResult> GetPagedResults( + int pageNumber = 1, + int pageSize = 100, + string orderBy = "Name", + Direction orderDirection = Direction.Ascending, + string filter = "", + string memberTypeAlias = null) + { + int totalChildren; + IMember[] children; + if (pageNumber > 0 && pageSize > 0) + { + children = Services.MemberService.GetAll((pageNumber - 1), pageSize, out totalChildren, orderBy, orderDirection, memberTypeAlias, filter).ToArray(); + } + else + { + throw new NotSupportedException("Both pageNumber and pageSize must be greater than zero"); + } + + if (totalChildren == 0) + { + return new PagedResult>(0, 0, 0); + } + + var pagedResult = new PagedResult>(totalChildren, pageNumber, pageSize); + pagedResult.Items = children + .Select(Mapper.Map>); + + return pagedResult; + } + + /// + /// Returns a display node with a list view to render members + /// + /// + /// + public MemberListDisplay GetListNodeDisplay(string listName) + { + var display = new MemberListDisplay + { + ContentTypeAlias = listName, + ContentTypeName = listName, + Id = listName, + IsContainer = true, + Name = listName, + Path = "-1," + listName, + ParentId = -1 + }; + + TabsAndPropertiesResolver.AddListView(display, "member", Services.DataTypeService); + + return display; + } + /// /// Gets the content json for the member /// diff --git a/src/Umbraco.Web/Models/ContentEditing/DataTypeDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/DataTypeDisplay.cs index 2c7e3d1c17..b58773a621 100644 --- a/src/Umbraco.Web/Models/ContentEditing/DataTypeDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/DataTypeDisplay.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; @@ -34,5 +35,12 @@ namespace Umbraco.Web.Models.ContentEditing ///
[DataMember(Name = "notifications")] public List Notifications { get; private set; } + + /// + /// Whether or not this is a system data type, in which case it cannot be deleted + /// + [DataMember(Name = "isSystem")] + [ReadOnly(true)] + public bool IsSystemDataType { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/ContentEditing/MemberDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/MemberDisplay.cs index a295e7718f..e98191fc7e 100644 --- a/src/Umbraco.Web/Models/ContentEditing/MemberDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/MemberDisplay.cs @@ -6,6 +6,14 @@ using Umbraco.Core.Models.Membership; namespace Umbraco.Web.Models.ContentEditing { + /// + /// A model representing a member list to be displayed in the back office + /// + [DataContract(Name = "content", Namespace = "")] + public class MemberListDisplay : ContentItemDisplayBase + { + } + /// /// A model representing a member to be displayed in the back office /// diff --git a/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs b/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs index e1f5cc4508..2ec97b6b3b 100644 --- a/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs @@ -27,6 +27,13 @@ namespace Umbraco.Web.Models.Mapping config.CreateMap() .ForMember(x => x.Value, expression => expression.Ignore()); + var systemIds = new[] + { + Constants.System.DefaultContentListViewDataTypeId, + Constants.System.DefaultMediaListViewDataTypeId, + Constants.System.DefaultMembersListViewDataTypeId + }; + config.CreateMap() .ForMember(display => display.AvailableEditors, expression => expression.ResolveUsing()) .ForMember(display => display.PreValues, expression => expression.ResolveUsing( @@ -35,7 +42,8 @@ namespace Umbraco.Web.Models.Mapping definition => definition.PropertyEditorAlias.IsNullOrWhiteSpace() ? null : definition.PropertyEditorAlias)) .ForMember(x => x.Notifications, expression => expression.Ignore()) .ForMember(x => x.Icon, expression => expression.Ignore()) - .ForMember(x => x.Alias, expression => expression.Ignore()); + .ForMember(x => x.Alias, expression => expression.Ignore()) + .ForMember(x => x.IsSystemDataType, expression => expression.MapFrom(definition => systemIds.Contains(definition.Id))); //gets a list of PreValueFieldDisplay objects from the data type definition config.CreateMap>() diff --git a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs index a354718ffb..62e7bc58e4 100644 --- a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs @@ -130,7 +130,7 @@ namespace Umbraco.Web.Models.Mapping case "media": dtdId = Constants.System.DefaultMediaListViewDataTypeId; break; - case "members": + case "member": dtdId = Constants.System.DefaultMembersListViewDataTypeId; break; default: diff --git a/src/Umbraco.Web/PropertyEditors/ListViewPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/ListViewPropertyEditor.cs index fb179435db..09dfacc94f 100644 --- a/src/Umbraco.Web/PropertyEditors/ListViewPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ListViewPropertyEditor.cs @@ -44,13 +44,15 @@ namespace Umbraco.Web.PropertyEditors [PreValueField("pageSize", "Page Size", "number", Description = "Number of items per page")] public int PageSize { get; set; } - [PreValueField("orderBy", "Order By", "views/propertyeditors/listview/sortby.prevalues.html")] + [PreValueField("orderBy", "Order By", "views/propertyeditors/listview/sortby.prevalues.html", + Description = "The default sort order for the list")] public int OrderBy { get; set; } [PreValueField("orderDirection", "Order Direction", "views/propertyeditors/listview/orderdirection.prevalues.html")] public int OrderDirection { get; set; } - [PreValueField("includeProperties", "Include Properties", "views/propertyeditors/listview/includeproperties.prevalues.html")] + [PreValueField("includeProperties", "Columns Displayed", "views/propertyeditors/listview/includeproperties.prevalues.html", + Description = "The properties that will be displayed for each column")] public object IncludeProperties { get; set; } } diff --git a/src/Umbraco.Web/Strategies/Migrations/EnsureListViewDataTypeIsCreated.cs b/src/Umbraco.Web/Strategies/Migrations/EnsureListViewDataTypeIsCreated.cs index fd79462a81..09d636d153 100644 --- a/src/Umbraco.Web/Strategies/Migrations/EnsureListViewDataTypeIsCreated.cs +++ b/src/Umbraco.Web/Strategies/Migrations/EnsureListViewDataTypeIsCreated.cs @@ -65,9 +65,9 @@ namespace Umbraco.Web.Strategies.Migrations if (SqlSyntaxContext.SqlSyntaxProvider.SupportsIdentityInsert()) e.MigrationContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("umbracoNode")))); - e.MigrationContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultContentListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-95", SortOrder = 2, UniqueId = new Guid("C0808DD3-8133-4E4B-8CE8-E2BEA84A96A4"), Text = "List View - Content", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); - e.MigrationContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultMediaListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-96", SortOrder = 2, UniqueId = new Guid("3A0156C4-3B8C-4803-BDC1-6871FAA83FFF"), Text = "List View - Media", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); - e.MigrationContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultMembersListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-97", SortOrder = 2, UniqueId = new Guid("AA2C52A0-CE87-4E65-A47C-7DF09358585D"), Text = "List View - Members", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); + e.MigrationContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultContentListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-95", SortOrder = 2, UniqueId = new Guid("C0808DD3-8133-4E4B-8CE8-E2BEA84A96A4"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Content", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); + e.MigrationContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultMediaListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-96", SortOrder = 2, UniqueId = new Guid("3A0156C4-3B8C-4803-BDC1-6871FAA83FFF"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Media", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); + e.MigrationContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultMembersListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-97", SortOrder = 2, UniqueId = new Guid("AA2C52A0-CE87-4E65-A47C-7DF09358585D"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Members", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); //Turn off identity insert if db provider is not mysql if (SqlSyntaxContext.SqlSyntaxProvider.SupportsIdentityInsert()) diff --git a/src/Umbraco.Web/Trees/MemberTreeController.cs b/src/Umbraco.Web/Trees/MemberTreeController.cs index 8e4bed8d7f..a0c126bc25 100644 --- a/src/Umbraco.Web/Trees/MemberTreeController.cs +++ b/src/Umbraco.Web/Trees/MemberTreeController.cs @@ -11,13 +11,10 @@ using Umbraco.Web.Mvc; using Umbraco.Web.WebApi.Filters; using umbraco; using umbraco.BusinessLogic.Actions; -using umbraco.cms.businesslogic.member; using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Trees { - //TODO: Upgrade thsi to use the new Member Service! - //We will not allow the tree to render unless the user has access to any of the sections that the tree gets rendered // this is not ideal but until we change permissions to be tree based (not section) there's not much else we can do here. [UmbracoApplicationAuthorize( @@ -33,9 +30,11 @@ namespace Umbraco.Web.Trees public MemberTreeController() { _provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider(); + _isUmbracoProvider = _provider.IsUmbracoMembershipProvider(); } - private MembershipProvider _provider; + private readonly MembershipProvider _provider; + private readonly bool _isUmbracoProvider; protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) { @@ -43,55 +42,16 @@ namespace Umbraco.Web.Trees if (id == Constants.System.Root.ToInvariantString()) { - //list out all the letters - for (var i = 97; i < 123; i++) - { - var charString = ((char) i).ToString(CultureInfo.InvariantCulture); - var folder = CreateTreeNode(charString, id, queryStrings, charString, "icon-folder-close", true); - folder.NodeType = "member-folder"; - nodes.Add(folder); - } - //list out 'Others' if the membership provider is umbraco - if (_provider.IsUmbracoMembershipProvider()) - { - var folder = CreateTreeNode("others", id, queryStrings, "Others", "icon-folder-close", true); - folder.NodeType = "member-folder"; - nodes.Add(folder); - } - } - else - { - //if it is a letter - if (id.Length == 1 && char.IsLower(id, 0)) - { - if (_provider.IsUmbracoMembershipProvider()) - { - int totalRecs; - var foundMembers = Services.MemberService.FindMembersByDisplayName( - id.ToCharArray()[0].ToString(CultureInfo.InvariantCulture), 0, int.MaxValue, out totalRecs, StringPropertyMatchType.StartsWith) - .ToArray(); + nodes.Add( + CreateTreeNode("all-members", id, queryStrings, "All Members", "icon-users", false, + queryStrings.GetValue("application") + TreeAlias.EnsureStartsWith('/') + "/list/all-members")); - //get the members from our member data layer - nodes.AddRange( - foundMembers - .Select(m => CreateTreeNode(m.Key.ToString("N"), id, queryStrings, m.Name, "icon-user"))); - } - else - { - //get the members from the provider - int total; - nodes.AddRange( - FindUsersByName(char.Parse(id)).Cast() - .Select(m => CreateTreeNode(GetNodeIdForCustomProvider(m.ProviderUserKey), id, queryStrings, m.UserName, "icon-user"))); - } - } - else if (id == "others") + if (_isUmbracoProvider) { - //others will only show up when in umbraco membership mode - //TODO: We don't have a new API for this because we want to get rid of how this is displayed - nodes.AddRange( - Member.getAllOtherMembers() - .Select(m => CreateTreeNode(m.UniqueId.ToString("N"), id, queryStrings, m.Text, "icon-user"))); + nodes.AddRange(Services.MemberTypeService.GetAll() + .Select(memberType => + CreateTreeNode(memberType.Alias, id, queryStrings, memberType.Name, "icon-users", false, + queryStrings.GetValue("application") + TreeAlias.EnsureStartsWith('/') + "/list/" + memberType.Alias))); } } return nodes; @@ -115,10 +75,10 @@ namespace Umbraco.Web.Trees } else { - //the AD provider - and potentiall all other providers will use the asterisk syntax. + //the AD provider - and potentially all other providers will use the asterisk syntax. return _provider.FindUsersByName(letter + "*", 0, 9999, out total); } - + } /// @@ -155,7 +115,7 @@ namespace Umbraco.Web.Trees else { //Create a custom create action - this does not launch a dialog, it just navigates to the create screen - // we'll create it baesd on the ActionNew so it maintains the same icon properties, name, etc... + // we'll create it based on the ActionNew so it maintains the same icon properties, name, etc... var createMenuItem = new MenuItem(ActionNew.Instance); //we want to go to this route: /member/member/edit/-1?create=true createMenuItem.NavigateToRoute("/member/member/edit/-1?create=true"); @@ -166,15 +126,8 @@ namespace Umbraco.Web.Trees return menu; } - Guid guid; - if (Guid.TryParse(id, out guid)) - { - menu.Items.Add(ui.Text("actions", ActionDelete.Instance.Alias)); - } - else - { - menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), false); - } + menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), false); + return menu; } }