Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial support for user deletion request #5007

Merged
merged 1 commit into from
Nov 16, 2017
Merged

Add initial support for user deletion request #5007

merged 1 commit into from
Nov 16, 2017

Conversation

joelverhagen
Copy link
Member

Progress on https://github.com/NuGet/Engineering/issues/921.

The changes were getting big so I stopped and made a PR. Hopefully easier to review.

This PR:

  1. Update the "report my package" form to support a new hidden drop-down (delete decision) and confirmation checkbox.
  2. Add new notification message so that all owners know a version was deleted.
  3. Add method to IPackageDeleteService to determine if a package can be deleted. It always returns false right now.
  4. Add logic to soft delete the package and auto-close the support request.

TODO:

  1. Implement "can I delete this?" logic.
  2. Introduce configuration for the aforementioned logic.
  3. Functional test (hopefully)

Without these TODOs, the new code paths introduced by this PR will not be available yet.

if (!allowDelete
&& reportForm.DeleteDecision == PackageDeleteDecision.DeletePackage)
{
reportForm.DeleteDecision = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that lack of permissions is going to result in the same UI validation error for when a delete decision wasn't provided?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, the UI will behave as if the delete decision UI was hidden. Really, the user should never get into this case because the UI doesn't allow it. The missing delete decision validation error only occurs if allowDelete is true (which is not the case here).

{
// Swallow exceptions that occur during the delete process. If this happens, we'll just
// send out the support request as usual and handle it manually.
QuietLog.LogHandledException(e);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the user receive a message that the support request was sent?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deleted will still be false so we will show the "support request sent" message as usual.

@@ -291,6 +291,19 @@ public static HtmlString ShowCheckboxFor<TModel>(this HtmlHelper<TModel> html, E
public static MvcHtmlString ShowEnumDropDownListFor<TModel, TEnum>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, TEnum?>> expression,
string emptyItemText)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also a HtmlExtensions class. Maybe we should move these HtmlHelper extensions there?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, good point. I'll take a look at that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this is a big mess already. I will create an issue to clean this up.
#5015

@skofman1
Copy link
Contributor

can you attach screenshots?

@joelverhagen
Copy link
Member Author

Select a reason

image

After choosing a delete reason

image

After choosing the delete decision

image

After choosing the contact support decision

image

After deleted

image

}

// Enforce the auto-delete rules.
var allowDelete = await _packageDeleteService.CanPackageBeDeletedByUserAsync(package);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to evaluate CanPackageBeDeletedByUserAsync is DeleteDecision is not DeletePackage? If the user just wants to contact support we are doing unnecessary work here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point, no we don't.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

{
return HttpNotFound();
reportForm.CopySender = false;
reportForm.Message = "This support request is intended for automatic deletion.";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

automatic package deletion

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Good point.

user,
package);

if (supportRequest != null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when will AddNewSupportRequestAsync return null?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the commit to the support request DB fails. This is existing logic in the support request service.

"change to propagate through our system.";

return Redirect(Url.Package(id, version));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method is to big. Can you split it to smaller methods?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.


TempData["Message"] =
"We're performing the package delete right now. It may take a while for this " +
"change to propagate through our system.";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this controller doesn't do much use of Strings, but perhaps it time to start?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

return HttpNotFound();
}

if (!PermissionsService.IsActionAllowed(package, User, PackageActions.ReportMyPackage))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the permissions required for reporting a package are the same as for deleting a package? Do we need a special check for the later?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same permissions. The keyword here is "My" in "ReportMyPackage".

Copy link
Contributor

@skofman1 skofman1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕐

Copy link
Contributor

@skofman1 skofman1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

A subsequent commit will complete the work and fully enable this feature.
Progress on NuGet/Engineering#921
@joelverhagen joelverhagen merged commit a0e9cfa into NuGet:dev Nov 16, 2017
@joelverhagen joelverhagen deleted the auto-delete branch November 16, 2017 23:30
Copy link
Contributor

@scottbommarito scottbommarito left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

woops, looks like i missed the bell

@@ -35,6 +36,29 @@ namespace NuGetGallery
public partial class PackagesController
: AppController
{
private static readonly IReadOnlyList<ReportPackageReason> ReportAbuseReasons = new[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add some comments on what these are for.

/// <summary>
/// Reasons that users can select when reporting abuse by a package they do not own.
/// </summary>
private static readonly IReadOnlyList<ReportPackageReason> ReportAbuseReasons = new[] { ... }

/// <summary>
/// Reasons that users can select when reporting their own package.
/// </summary>
private static readonly IReadOnlyList<ReportPackageReason> ReportMyPackageReasons = new[] { ... }

/// <summary>
/// Subset of <see cref="ReportMyPackageReasons"/> that suggests a user would like to delete a package.
/// </summary>
private static readonly IReadOnlyList<ReportPackageReason> DeleteReasons = new[] { ... }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good idea. Thanks for doing the work for me 😉


var modelIsValid = ModelState.IsValid;
if (reportForm.Reason == ReportPackageReason.ViolatesALicenseIOwn)
reportForm.Message = HttpUtility.HtmlEncode(reportForm.Message);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this isn't related to this PR, but shouldn't MVC do this encoding for us?

If it's needed, we should have a comment describing why.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope of this PR. I think we are encoding it since it makes its way into the email system.

modelIsValid = modelIsValid && !string.IsNullOrEmpty(reportForm.Signature);
ModelState.AddModelError(
nameof(ReportAbuseViewModel.Signature),
"The signature is required.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 - This should be in Strings.resx
2 - We should be more verbose here: for example, "A signature is required when submitting a copyright violation request."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that should be in Strings.

The context of the UI negates the need for verbosity. If the message field is visible, it is required.

return RedirectToAction(nameof(ReportAbuse), new { id = package.PackageRegistration.Id, version = package.NormalizedVersion });
}

reportForm.Message = HttpUtility.HtmlEncode(reportForm.Message);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above: shouldn't MVC do the encoding for us?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

allowDelete = await _packageDeleteService.CanPackageBeDeletedByUserAsync(package);
if (!allowDelete)
{
reportForm.DeleteDecision = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems really odd to me that we are changing the form here. It also made the logic more confusing for me.

If someone specifies they would like to delete their package, shouldn't we either
1 - return an error message that says they package does not meet the criteria
2 - keep the deletion state so that the on-call can see it in the support request

Regardless, there should be a comment on this line describing what we are doing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 - return an error message that says they package does not meet the criteria

Why show an error message? The only way this can happen is if someone is fiddling with the request or if they get the form while the package can be deleted and only submit it after the package can't be deleted. We shouldn't put extra effort into these cases.

2 - keep the deletion state so that the on-call can see it in the support request

The deletion state shouldn't even be persisted in this case. It's a bad request which should be rejected early on.

Regardless, there should be a comment on this line describing what we are doing.

Sounds good.

package.PackageRegistration.Id,
package.NormalizedVersion);
var reason = EnumHelper.GetDescription(reportForm.Reason.Value);
var supportRequest = await _supportRequestService.AddNewSupportRequestAsync(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the user attempts to the delete the package, why are we creating a support request?

Seems unnecessary. We should just delete it and if it fails, then create the request. Probably makes this code simpler because we don't need to pass around this support request object.

Also, it's very odd to be creating support requests we don't get emails for.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to track the auto-delete in a way the PMs asked for.

@@ -61,6 +61,13 @@ public class PackageDeleteService
_auditingService = auditingService;
}

public Task<bool> CanPackageBeDeletedByUserAsync(Package package)
{
// For now, don't allow user's to delete their packages.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: user's -> users

@Html.ShowCheckboxFor(m => m.DeleteConfirmation)
I understand that this action cannot be undone. This will permanently delete the package
@Model.PackageId @Model.PackageVersion and make it unavailable for download and package restore.
This does not allow uploading a new package with the same version.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep the same phrasing, this I will not be able to upload a new package with the same version. or something similar might be better.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I like that better too.

_viewModel);

// Assert
Assert.Contains(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can consolidate this into a helper message to be used in a number of these other tests

private void AssertContainsMessage(PackagesController controller, string message)
{
    Assert.Contains(message, _controller.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage));
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

}

[Theory]
[InlineData(ReportPackageReason.ContainsMaliciousCode)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two thoughts:

1 - we should make this run on all members of PackagesController.DeleteReasons
2 - if we are concerned about the members of PackageController.DeleteReasons changing, then there should be tests for that

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kind of out of scope, as there was no pre-existing validation on which reasons were being sent, but I'll add tests for it.

@joelverhagen
Copy link
Member Author

@scottbommarito, I will address these comments in a follow-up PR.

@shishirx34 shishirx34 mentioned this pull request Nov 17, 2017
10 tasks
scottbommarito pushed a commit that referenced this pull request Jul 22, 2019
A subsequent commit will complete the work and fully enable this feature.
Progress on NuGet/Engineering#921
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants