Skip to content

Commit

Permalink
Merge pull request #2230 from robertmuehsig/432-cancelemaichange
Browse files Browse the repository at this point in the history
432: Cancel Email Address Change
  • Loading branch information
jeffhandley committed Jun 26, 2014
2 parents 8354eee + 9035c0c commit cd57b3d
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/NuGetGallery.Core/Auditing/UserAuditRecord.cs
Expand Up @@ -81,6 +81,7 @@ public enum UserAuditAction
RemovedCredential, RemovedCredential,
RequestedPasswordReset, RequestedPasswordReset,
ChangeEmail, ChangeEmail,
CancelChangeEmail,
ConfirmEmail, ConfirmEmail,
} }
} }
6 changes: 6 additions & 0 deletions src/NuGetGallery.Core/Entities/User.cs
Expand Up @@ -69,6 +69,12 @@ public void ConfirmEmailAddress()
UnconfirmedEmailAddress = null; UnconfirmedEmailAddress = null;
} }


public void CancelChangeEmailAddress()
{
EmailConfirmationToken = null;
UnconfirmedEmailAddress = null;
}

public void UpdateEmailAddress(string newEmailAddress, Func<string> generateToken) public void UpdateEmailAddress(string newEmailAddress, Func<string> generateToken)
{ {
if (!String.IsNullOrEmpty(UnconfirmedEmailAddress)) if (!String.IsNullOrEmpty(UnconfirmedEmailAddress))
Expand Down
24 changes: 19 additions & 5 deletions src/NuGetGallery/Controllers/UsersController.cs
Expand Up @@ -333,6 +333,25 @@ public virtual async Task<ActionResult> ChangeEmail(AccountViewModel model)
return RedirectToAction(actionName: "Account", controllerName: "Users"); return RedirectToAction(actionName: "Account", controllerName: "Users");
} }


[HttpPost]
[Authorize]
public virtual async Task<ActionResult> CancelChangeEmail(AccountViewModel model)
{
var user = GetCurrentUser();

if(string.IsNullOrWhiteSpace(user.UnconfirmedEmailAddress))
{
return RedirectToAction(actionName: "Account", controllerName: "Users");
}

await UserService.CancelChangeEmailAddress(user);

TempData["Message"] = Strings.CancelEmailAddress;

return RedirectToAction(actionName: "Account", controllerName: "Users");
}


[HttpPost] [HttpPost]
[Authorize] [Authorize]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
Expand Down Expand Up @@ -433,11 +452,6 @@ private async Task<ActionResult> RemoveCredential(User user, Credential cred, st
return RedirectToAction("Account"); return RedirectToAction("Account");
} }


private ActionResult EditProfileView()
{
return AccountView(new AccountViewModel());
}

private ActionResult AccountView(AccountViewModel model) private ActionResult AccountView(AccountViewModel model)
{ {
// Load Credential info // Load Credential info
Expand Down
2 changes: 2 additions & 0 deletions src/NuGetGallery/Services/IUserService.cs
Expand Up @@ -19,5 +19,7 @@ public interface IUserService
Task<bool> ConfirmEmailAddress(User user, string token); Task<bool> ConfirmEmailAddress(User user, string token);


Task ChangeEmailAddress(User user, string newEmailAddress); Task ChangeEmailAddress(User user, string newEmailAddress);

Task CancelChangeEmailAddress(User user);
} }
} }
8 changes: 8 additions & 0 deletions src/NuGetGallery/Services/UserService.cs
Expand Up @@ -98,6 +98,14 @@ public async Task ChangeEmailAddress(User user, string newEmailAddress)
UserRepository.CommitChanges(); UserRepository.CommitChanges();
} }


public async Task CancelChangeEmailAddress(User user)
{
await Auditing.SaveAuditRecord(new UserAuditRecord(user, UserAuditAction.CancelChangeEmail, user.UnconfirmedEmailAddress));

user.CancelChangeEmailAddress();
UserRepository.CommitChanges();
}

public async Task<bool> ConfirmEmailAddress(User user, string token) public async Task<bool> ConfirmEmailAddress(User user, string token)
{ {
if (user == null) if (user == null)
Expand Down
9 changes: 9 additions & 0 deletions src/NuGetGallery/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/NuGetGallery/Strings.resx
Expand Up @@ -302,4 +302,7 @@ The {2} Team</value>
<data name="DefaultUserSafeExceptionMessage" xml:space="preserve"> <data name="DefaultUserSafeExceptionMessage" xml:space="preserve">
<value>An unexpected error occurred. Contact support for assistance.</value> <value>An unexpected error occurred. Contact support for assistance.</value>
</data> </data>
<data name="CancelEmailAddress" xml:space="preserve">
<value>You canceled your email address change request.</value>
</data>
</root> </root>
14 changes: 13 additions & 1 deletion src/NuGetGallery/Views/Users/Account.cshtml
Expand Up @@ -163,7 +163,19 @@
subtitle: currentEmailAddress, subtitle: currentEmailAddress,
enabled: String.IsNullOrEmpty(CurrentUser.UnconfirmedEmailAddress), enabled: String.IsNullOrEmpty(CurrentUser.UnconfirmedEmailAddress),
formModelStatePrefix: "ChangeEmail", formModelStatePrefix: "ChangeEmail",
actions: @<text>@item.ExpandButton("Change", "Cancel")</text>, actions: @<text>@item.ExpandButton("Change", "Cancel")
@if (!String.IsNullOrEmpty(CurrentUser.EmailAddress) && !String.IsNullOrEmpty(CurrentUser.UnconfirmedEmailAddress))
{
using (Html.BeginForm("CancelChangeEmail", "Users", FormMethod.Post, new { @class = "form-inline" }))
{
<fieldset class="form">
<legend>Reset to Confirmed Email Address</legend>
@Html.AntiForgeryToken()
<button class="btn btn-inline" type="submit">Reset to Confirmed Email Address</button>
</fieldset>
}
}
</text>,
content: @<text> content: @<text>
@using (Html.BeginForm("ChangeEmail", "Users", FormMethod.Post, new { @class = "form-inline" })) @using (Html.BeginForm("ChangeEmail", "Users", FormMethod.Post, new { @class = "form-inline" }))
{ {
Expand Down
56 changes: 56 additions & 0 deletions tests/NuGetGallery.Facts/Services/UserServiceFacts.cs
Expand Up @@ -302,6 +302,62 @@ public async Task WritesAuditRecord()
} }
} }


public class TheCancelChangeEmailAddressMethod
{
[Fact]
public async Task ClearsUnconfirmedEmail()
{
var user = new User { Username = "Bob", UnconfirmedEmailAddress = "unconfirmedEmail@example.org", EmailAddress = "confirmedEmail@example.org" };
var service = new TestableUserServiceWithDBFaking
{
Users = new[] { user }
};

await service.CancelChangeEmailAddress(user);

Assert.Equal("confirmedEmail@example.org", user.EmailAddress);
Assert.Null(user.UnconfirmedEmailAddress);
service.FakeEntitiesContext.VerifyCommitChanges();
}

[Fact]
public async Task ClearsEmailConfirmationToken()
{
var user = new User { Username = "Bob", EmailConfirmationToken = Guid.NewGuid().ToString() ,UnconfirmedEmailAddress = "unconfirmedEmail@example.org", EmailAddress = "confirmedEmail@example.org" };
var service = new TestableUserServiceWithDBFaking
{
Users = new[] { user }
};

await service.CancelChangeEmailAddress(user);

Assert.Equal("confirmedEmail@example.org", user.EmailAddress);
Assert.Null(user.EmailConfirmationToken);
service.FakeEntitiesContext.VerifyCommitChanges();
}

[Fact]
public async Task WritesAuditRecord()
{
// Arrange
var user = new User { Username = "Bob", EmailConfirmationToken = Guid.NewGuid().ToString(), UnconfirmedEmailAddress = "unconfirmedEmail@example.org", EmailAddress = "confirmedEmail@example.org" };
var service = new TestableUserServiceWithDBFaking
{
Users = new[] { user }
};

// Act
await service.CancelChangeEmailAddress(user);

// Assert
Assert.True(service.Auditing.WroteRecord<UserAuditRecord>(ar =>
ar.Action == UserAuditAction.CancelChangeEmail &&
ar.AffectedEmailAddress == "unconfirmedEmail@example.org" &&
ar.EmailAddress == "confirmedEmail@example.org"));
}
}


public class TheUpdateProfileMethod public class TheUpdateProfileMethod
{ {
[Fact] [Fact]
Expand Down

0 comments on commit cd57b3d

Please sign in to comment.