Re-send of invitation from user profile.

Allow delete of users that haven't logged in from user profile.
Prevent disable/enable and change password options from user profile for invited users.
This commit is contained in:
AndyButland
2018-04-09 08:52:54 +02:00
parent 8499c01eac
commit 78121dd0f2
6 changed files with 154 additions and 5 deletions

View File

@@ -280,7 +280,7 @@
* });
* </pre>
*
* @param {Array} id user id.
* @param {Int} userId user id.
* @returns {Promise} resourcePromise object containing the user.
*
*/
@@ -406,6 +406,36 @@
"Failed to save user");
}
/**
* @ngdoc method
* @name umbraco.resources.usersResource#deleteNonLoggedInUser
* @methodOf umbraco.resources.usersResource
*
* @description
* Deletes a user that hasn't already logged in (and hence we know has made no content updates that would create related records)
*
* ##usage
* <pre>
* usersResource.deleteNonLoggedInUser(1)
* .then(function() {
* alert("user was deleted");
* });
* </pre>
*
* @param {Int} userId user id.
* @returns {Promise} resourcePromise object.
*
*/
function deleteNonLoggedInUser(userId) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"userApiBaseUrl",
"PostDeleteNonLoggedInUser", { id: userId })),
'Failed to delete the user ' + userId);
}
var resource = {
disableUsers: disableUsers,
@@ -417,6 +447,7 @@
createUser: createUser,
inviteUser: inviteUser,
saveUser: saveUser,
deleteNonLoggedInUser: deleteNonLoggedInUser,
clearAvatar: clearAvatar
};

View File

@@ -31,6 +31,8 @@
vm.disableUser = disableUser;
vm.enableUser = enableUser;
vm.unlockUser = unlockUser;
vm.resendInvite = resendInvite;
vm.deleteNonLoggedInUser = deleteNonLoggedInUser;
vm.changeAvatar = changeAvatar;
vm.clearAvatar = clearAvatar;
vm.save = save;
@@ -49,7 +51,9 @@
"sections_users",
"content_contentRoot",
"media_mediaRoot",
"user_noStartNodes"
"user_noStartNodes",
"user_defaultInvitationMessage",
"user_deleteUserConfirmation"
];
localizationService.localizeMany(labelKeys).then(function (values) {
@@ -61,6 +65,8 @@
vm.labels.contentRoot = values[5];
vm.labels.mediaRoot = values[6];
vm.labels.noStartNodes = values[7];
vm.labels.defaultInvitationMessage = values[8];
vm.labels.deleteUserConfirmation = values[9];
});
// get user
@@ -350,6 +356,44 @@
});
}
function resendInvite() {
vm.resendInviteButtonState = "busy";
if (vm.resendInviteMessage) {
vm.user.message = vm.resendInviteMessage;
}
else {
vm.user.message = vm.labels.defaultInvitationMessage;
}
usersResource.inviteUser(vm.user).then(function (data) {
vm.resendInviteButtonState = "success";
vm.resendInviteMessage = "";
formHelper.showNotifications(data);
}, function (error) {
vm.resendInviteButtonState = "error";
formHelper.showNotifications(error.data);
});
}
function deleteNonLoggedInUser() {
vm.deleteNotLoggedInUserButtonState = "busy";
var confirmationMessage = vm.labels.deleteUserConfirmation;
if (!confirm(confirmationMessage)) {
vm.deleteNotLoggedInUserButtonState = "danger";
return;
}
usersResource.deleteNonLoggedInUser(vm.user.id).then(function (data) {
formHelper.showNotifications(data);
goToPage(vm.breadcrumbs[0]);
}, function (error) {
vm.deleteNotLoggedInUserButtonState = "error";
formHelper.showNotifications(error.data);
});
}
function clearAvatar() {
// get user
usersResource.clearAvatar(vm.user.id).then(function (data) {

View File

@@ -239,7 +239,7 @@
</div>
<div style="margin-bottom: 10px;">
<umb-button ng-if="model.user.userDisplayState.key !== 'Disabled' && !model.user.isCurrentUser"
<umb-button ng-if="model.user.userDisplayState.key !== 'Disabled' && model.user.userDisplayState.key !== 'Invited' && !model.user.isCurrentUser"
type="button"
button-style="[info,block]"
action="model.disableUser()"
@@ -250,7 +250,7 @@
</umb-button>
</div>
<umb-button type="button"
<umb-button type="button" ng-if="model.user.userDisplayState.key !== 'Invited'"
button-style="[info,block]"
action="model.toggleChangePassword()"
label="Change password"
@@ -260,6 +260,15 @@
size="s">
</umb-button>
<umb-button type="button" ng-if="!model.user.lastLoginDate"
button-style="[danger,block]"
action="model.deleteNonLoggedInUser()"
label="Delete"
label-key="user_deleteUser"
state="deleteNotLoggedInUserButtonState"
size="s">
</umb-button>
<ng-form ng-if="model.changePasswordModel.isChanging" name="passwordForm" class="block-form" val-form-manager>
<change-password password-values="model.user.changePassword"
@@ -293,6 +302,25 @@
</div>
</div>
<div style="margin-bottom: 10px;" ng-if="model.user.userDisplayState.key === 'Invited' && !model.user.isCurrentUser">
<textarea name="resendInviteMessage"
type="text"
class="input-block-level"
localize="placeholder"
placeholder="@placeholders_enterMessage"
ng-model="model.resendInviteMessage"
rows="4">
</textarea>
<umb-button type="button"
button-style="[info,block]"
action="model.resendInvite()"
state="model.resendInviteButtonState"
label="Resend Invite"
label-key="actions_resendInvite"
size="s">
</umb-button>
</div>
<div class="umb-package-details__information-item">
<div class="umb-package-details__information-item-label">
<localize key="user_lastLogin">Last login</localize>:
@@ -358,4 +386,4 @@
</div>
</div>
</div>

View File

@@ -46,6 +46,7 @@
<key alias="setPermissions">Set permissions</key>
<key alias="unlock">Unlock</key>
<key alias="createblueprint">Create Content Template</key>
<key alias="resendInvite">Resend Invitation</key>
</area>
<area alias="actionCategories">
<key alias="content">Content</key>
@@ -1419,6 +1420,9 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="unlockUserError">An error occurred while unlocking the user</key>
<key alias="memberExportedSuccess">Member was exported to file</key>
<key alias="memberExportedError">An error occurred while exporting the member</key>
<key alias="deleteUserSuccess">User %0% was deleted</key>
<key alias="resendInviteHeader">Invite user</key>
<key alias="resendInviteSuccess">Invitation has been re-sent to %0%</key>
</area>
<area alias="stylesheet">
<key alias="aliasHelp">Uses CSS syntax ex: h1, .redHeader, .blueTex</key>
@@ -1996,6 +2000,9 @@ To manage your website, simply open the Umbraco back office and start adding con
</html>]]>
</key>
<key alias="invite">Invite</key>
<key alias="defaultInvitationMessage">Resending invitation...</key>
<key alias="deleteUser">Delete User</key>
<key alias="deleteUserConfirmation">Are you sure you wish to delete this user account?</key>
</area>
<area alias="validation">

View File

@@ -46,6 +46,7 @@
<key alias="setPermissions">Set permissions</key>
<key alias="unlock">Unlock</key>
<key alias="createblueprint">Create Content Template</key>
<key alias="resendInvite">Resend Invitation</key>
</area>
<area alias="actionCategories">
<key alias="content">Content</key>
@@ -1416,6 +1417,9 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="unlockUserError">An error occurred while unlocking the user</key>
<key alias="memberExportedSuccess">Member was exported to file</key>
<key alias="memberExportedError">An error occurred while exporting the member</key>
<key alias="deleteUserSuccess">User %0% was deleted</key>
<key alias="resendInviteHeader">Invite user</key>
<key alias="resendInviteSuccess">Invitation has been re-sent to %0%</key>
</area>
<area alias="stylesheet">
<key alias="aliasHelp">Uses CSS syntax ex: h1, .redHeader, .blueTex</key>
@@ -1988,6 +1992,9 @@ To manage your website, simply open the Umbraco back office and start adding con
</html>]]>
</key>
<key alias="invite">Invite</key>
<key alias="defaultInvitationMessage">Resending invitation...</key>
<key alias="deleteUser">Delete User</key>
<key alias="deleteUserConfirmation">Are you sure you wish to delete this user account?</key>
</area>
<area alias="validation">
<key alias="validation">Validation</key>

View File

@@ -412,6 +412,8 @@ namespace Umbraco.Web.Editors
await SendUserInviteEmailAsync(display, Security.CurrentUser.Name, Security.CurrentUser.Email, user, userSave.Message);
display.AddSuccessNotification(Services.TextService.Localize("speechBubbles/resendInviteHeader"), Services.TextService.Localize("speechBubbles/resendInviteSuccess", new[] { user.Name }));
return display;
}
@@ -699,6 +701,36 @@ namespace Umbraco.Web.Editors
Services.TextService.Localize("speechBubbles/setUserGroupOnUsersSuccess"));
}
/// <summary>
/// Deletes the non-logged in user provided id
/// </summary>
/// <param name="id">User Id</param>
/// <remarks>
/// Limited to users that haven't logged in to avoid issues with related records constrained
/// with a foreign key on the user Id
/// </remarks>
public async Task<HttpResponseMessage> PostDeleteNonLoggedInUser(int id)
{
var user = Services.UserService.GetUserById(id);
if (user == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
// Check user hasn't logged in. If they have they may have made content changes which will mean
// the Id is associated with audit trails, versions etc. and can't be removed.
if (user.LastLoginDate != default(DateTime))
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
var userName = user.Name;
Services.UserService.Delete(user, true);
return Request.CreateNotificationSuccessResponse(
Services.TextService.Localize("speechBubbles/deleteUserSuccess", new[] { userName }));
}
public class PagedUserResult : PagedResult<UserBasic>
{
public PagedUserResult(long totalItems, long pageNumber, long pageSize) : base(totalItems, pageNumber, pageSize)