diff --git a/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs index bdc0ddeac0..d6c97b6df2 100644 --- a/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs @@ -79,15 +79,16 @@ namespace Umbraco.Core.Persistence.Repositories public IDictionary GetUserStates() { - var sql = @"SELECT 'CountOfAll' AS name, COUNT(id) AS num FROM umbracoUser + var sql = @"SELECT '1CountOfAll' AS colName, COUNT(id) AS num FROM umbracoUser UNION -SELECT 'CountOfActive' AS name, COUNT(id) AS num FROM umbracoUser WHERE userDisabled = 0 AND userNoConsole = 0 AND lastLoginDate IS NOT NULL +SELECT '2CountOfActive' AS colName, COUNT(id) AS num FROM umbracoUser WHERE userDisabled = 0 AND userNoConsole = 0 AND lastLoginDate IS NOT NULL UNION -SELECT 'CountOfDisabled' AS name, COUNT(id) AS num FROM umbracoUser WHERE userDisabled = 1 +SELECT '3CountOfDisabled' AS colName, COUNT(id) AS num FROM umbracoUser WHERE userDisabled = 1 UNION -SELECT 'CountOfLockedOut' AS name, COUNT(id) AS num FROM umbracoUser WHERE userNoConsole = 1 +SELECT '4CountOfLockedOut' AS colName, COUNT(id) AS num FROM umbracoUser WHERE userNoConsole = 1 UNION -SELECT 'CountOfInvited' AS name, COUNT(id) AS num FROM umbracoUser WHERE lastLoginDate IS NULL AND userDisabled = 1 AND invitedDate IS NOT NULL"; +SELECT '5CountOfInvited' AS colName, COUNT(id) AS num FROM umbracoUser WHERE lastLoginDate IS NULL AND userDisabled = 1 AND invitedDate IS NOT NULL +ORDER BY colName"; var result = Database.Fetch(sql); @@ -513,7 +514,7 @@ SELECT 'CountOfInvited' AS name, COUNT(id) AS num FROM umbracoUser WHERE lastLog Sql filterSql = null; - if (filter != null || (userGroups != null && userGroups.Length > 0)) + if (filter != null || (userGroups != null && userGroups.Length > 0) || (userState != null && userState.Length > 0 && userState.Contains(UserState.All) == false)) filterSql = new Sql(); if (filter != null) @@ -531,10 +532,33 @@ SELECT 'CountOfInvited' AS name, COUNT(id) AS num FROM umbracoUser WHERE lastLog INNER JOIN umbracoUserGroup ON umbracoUserGroup.id = umbracoUser2UserGroup.userGroupId WHERE umbracoUserGroup.userGroupAlias IN (@userGroups)))"; filterSql.Append(subQuery, new {userGroups= userGroups}); + } + if (userState != null && userState.Length > 0) + { + //the "ALL" state doesn't require any filtering so we ignore that, if it exists in the list we don't do any filtering + if (userState.Contains(UserState.All) == false) + { + if (userState.Contains(UserState.Active)) + { + filterSql.Append("AND (userDisabled = 0 AND userNoConsole = 0 AND lastLoginDate IS NOT NULL)"); + } + if (userState.Contains(UserState.Disabled)) + { + filterSql.Append("AND (userDisabled = 1)"); + } + if (userState.Contains(UserState.LockedOut)) + { + filterSql.Append("AND (userNoConsole = 1)"); + } + if (userState.Contains(UserState.Invited)) + { + filterSql.Append("AND (lastLoginDate IS NULL AND userDisabled = 1 AND invitedDate IS NOT NULL)"); + } + } } - - // Get base query for returning IDs - var sqlBaseIds = GetBaseQuery("id"); + + // Get base query for returning IDs + var sqlBaseIds = GetBaseQuery("id"); if (query == null) query = new Query(); var translatorIds = new SqlTranslator(sqlBaseIds, query); diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/users.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/users.resource.js index 7631fda31f..706142dd18 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/users.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/users.resource.js @@ -7,179 +7,184 @@ * Used by the users section to get users and send requests to create, invite, delete, etc. users. */ (function () { - 'use strict'; + 'use strict'; - function usersResource($http, umbRequestHelper, $q, umbDataFormatter) { + function usersResource($http, umbRequestHelper, $q, umbDataFormatter) { - function clearAvatar(userId) { + function clearAvatar(userId) { - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "PostClearAvatar", - { id: userId })), - 'Failed to clear the user avatar ' + userId); - } + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "userApiBaseUrl", + "PostClearAvatar", + { id: userId })), + 'Failed to clear the user avatar ' + userId); + } - function disableUsers(userIds) { - if (!userIds) { - throw "userIds not specified"; - } + function disableUsers(userIds) { + if (!userIds) { + throw "userIds not specified"; + } - //we need to create a custom query string for the usergroup array, so create it now and we can append the user groups if needed - var qry = "userIds=" + userIds.join("&userIds="); + //we need to create a custom query string for the usergroup array, so create it now and we can append the user groups if needed + var qry = "userIds=" + userIds.join("&userIds="); - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "PostDisableUsers", qry)), - 'Failed to disable the users ' + userIds.join(",")); + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "userApiBaseUrl", + "PostDisableUsers", qry)), + 'Failed to disable the users ' + userIds.join(",")); + } + + function enableUsers(userIds) { + if (!userIds) { + throw "userIds not specified"; + } + + //we need to create a custom query string for the usergroup array, so create it now and we can append the user groups if needed + var qry = "userIds=" + userIds.join("&userIds="); + + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "userApiBaseUrl", + "PostEnableUsers", qry)), + 'Failed to enable the users ' + userIds.join(",")); + } + + function getPagedResults(options) { + var defaults = { + pageSize: 25, + pageNumber: 1, + filter: '', + orderDirection: "Ascending", + orderBy: "Username", + userGroups: [], + userStates: [] + }; + 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 + }; + //we need to create a custom query string for the usergroup array, so create it now and we can append the user groups if needed + var qry = umbRequestHelper.dictionaryToQueryString(params); + if (options.userGroups.length > 0) { + //we need to create a custom query string for an array + qry += "&userGroups=" + options.userGroups.join("&userGroups="); + } + if (options.userStates.length > 0) { + //we need to create a custom query string for an array + qry += "&userStates=" + options.userStates.join("&userStates="); + } + + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "userApiBaseUrl", + "GetPagedUsers", + qry)), + 'Failed to retrieve users paged result'); + } + + function getUser(userId) { + + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "userApiBaseUrl", + "GetById", + { id: userId })), + "Failed to retrieve data for user " + userId); + } + + function createUser(user) { + if (!user) { + throw "user not specified"; + } + + //need to convert the user data into the correctly formatted save data - it is *not* the same and we don't want to over-post + var formattedSaveData = umbDataFormatter.formatUserPostData(user); + + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "userApiBaseUrl", + "PostCreateUser"), + formattedSaveData), + "Failed to save user"); + } + + function inviteUser(user) { + if (!user) { + throw "user not specified"; + } + + //need to convert the user data into the correctly formatted save data - it is *not* the same and we don't want to over-post + var formattedSaveData = umbDataFormatter.formatUserPostData(user); + + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "userApiBaseUrl", + "PostInviteUser"), + formattedSaveData), + "Failed to invite user"); + } + + function saveUser(user) { + if (!user) { + throw "user not specified"; + } + + //need to convert the user data into the correctly formatted save data - it is *not* the same and we don't want to over-post + var formattedSaveData = umbDataFormatter.formatUserPostData(user); + + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "userApiBaseUrl", + "PostSaveUser"), + formattedSaveData), + "Failed to save user"); + } + + + var resource = { + disableUsers: disableUsers, + enableUsers: enableUsers, + getPagedResults: getPagedResults, + getUser: getUser, + createUser: createUser, + inviteUser: inviteUser, + saveUser: saveUser, + clearAvatar: clearAvatar + }; + + return resource; + } - function enableUsers(userIds) { - if (!userIds) { - throw "userIds not specified"; - } - - //we need to create a custom query string for the usergroup array, so create it now and we can append the user groups if needed - var qry = "userIds=" + userIds.join("&userIds="); - - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "PostEnableUsers", qry)), - 'Failed to enable the users ' + userIds.join(",")); - } - - function getPagedResults(options) { - var defaults = { - pageSize: 25, - pageNumber: 1, - filter: '', - orderDirection: "Ascending", - orderBy: "Username", - userGroups: [] - }; - 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 - }; - //we need to create a custom query string for the usergroup array, so create it now and we can append the user groups if needed - var qry = umbRequestHelper.dictionaryToQueryString(params); - if (options.userGroups.length > 0) { - //we need to create a custom query string for an array - qry += "&userGroups=" + options.userGroups.join("&userGroups="); - } - - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "GetPagedUsers", - qry)), - 'Failed to retrieve users paged result'); - } - - function getUser(userId) { - - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "GetById", - { id: userId })), - "Failed to retrieve data for user " + userId); - } - - function createUser(user) { - if (!user) { - throw "user not specified"; - } - - //need to convert the user data into the correctly formatted save data - it is *not* the same and we don't want to over-post - var formattedSaveData = umbDataFormatter.formatUserPostData(user); - - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "PostCreateUser"), - formattedSaveData), - "Failed to save user"); - } - - function inviteUser(user) { - if (!user) { - throw "user not specified"; - } - - //need to convert the user data into the correctly formatted save data - it is *not* the same and we don't want to over-post - var formattedSaveData = umbDataFormatter.formatUserPostData(user); - - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "PostInviteUser"), - formattedSaveData), - "Failed to invite user"); - } - - function saveUser(user) { - if (!user) { - throw "user not specified"; - } - - //need to convert the user data into the correctly formatted save data - it is *not* the same and we don't want to over-post - var formattedSaveData = umbDataFormatter.formatUserPostData(user); - - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "PostSaveUser"), - formattedSaveData), - "Failed to save user"); - } - - - var resource = { - disableUsers: disableUsers, - enableUsers: enableUsers, - getPagedResults: getPagedResults, - getUser: getUser, - createUser: createUser, - inviteUser: inviteUser, - saveUser: saveUser, - clearAvatar: clearAvatar - }; - - return resource; - - } - - angular.module('umbraco.resources').factory('usersResource', usersResource); + angular.module('umbraco.resources').factory('usersResource', usersResource); })(); diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js index ece0fe0fa5..67b4faf236 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js @@ -313,7 +313,42 @@ return name; } - function setUserStatesFilter(value) { + function setUserStatesFilter(userState) { + + if (!vm.usersOptions.userStates) { + vm.usersOptions.userStates = []; + } + + //If the selection is "ALL" then we need to unselect everything else since this is an 'odd' filter + if (userState.key === "All") { + angular.forEach(vm.userStatesFilter, function(i) { + i.selected = false; + }); + //we can't unselect All + userState.selected = true; + //reset the selection passed to the server + vm.usersOptions.userStates = []; + } + else { + angular.forEach(vm.userStatesFilter, function (i) { + if (i.key === "All") { + i.selected = false; + } + }); + var indexOfAll = vm.usersOptions.userStates.indexOf("All"); + if (indexOfAll >= 0) { + vm.usersOptions.userStates.splice(indexOfAll, 1); + } + } + + if (userState.selected) { + vm.usersOptions.userStates.push(userState.key); + } + else { + var index = vm.usersOptions.userStates.indexOf(userState.key); + vm.usersOptions.userStates.splice(index, 1); + } + getUsers(); } diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html index 581dad0c24..9e4b18034a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html @@ -111,7 +111,7 @@