Repository: pypi/warehouse

Issue:
Change delete file modal confirmation process
**From user testing:**

Currently, to delete a file, you must confirm the entire file name:

![screenshot from 2018-03-07 20-44-40](https://user-images.githubusercontent.com/3323703/37118147-2977e46e-224b-11e8-8d85-c379284e6cc2.png)

This is a little bit painful for some users, because the file name can get pretty long.

Instead, we should change this modal so that we require the `project name` for confirmation.

---

**Good First Issue**: This issue is good for first time contributors. If you've already contributed to Warehouse, please work on [another issue without this label](https://github.com/pypa/warehouse/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+-label%3A%22good+first+issue%22) instead. If there is not a corresponding pull request for this issue, it is up for grabs. For directions for getting set up, see our [Getting Started Guide](https://warehouse.pypa.io/development/getting-started/). If you are working on this issue and have questions, please feel free to ask them here, [`#pypa-dev` on Freenode](https://webchat.freenode.net/?channels=%23pypa-dev), or the [pypa-dev mailing list](https://groups.google.com/forum/#!forum/pypa-dev).



Discussion:
@aalmazan could I ask for you to help with this?
@brainwane Sure, however, I can't seem to find a good way to test uploading packages. Are there some docs you can point me to? Or at least a high-level of how I can create a test package? 

Would I need to follow [the packaging guide](https://packaging.python.org/tutorials/distributing-packages/) while having pypi.org point to localhost?
@aalmazan As a first step, if you haven't uploaded a package to PyPI before, I suggest you follow [the packaging guide](https://packaging.python.org/tutorials/distributing-packages/) and then [upload your package to Test PyPI](https://packaging.python.org/guides/using-testpypi/), just to see how the whole process works. [Here's a toy project I have set up reasonably well](https://gitlab.com/brainwane/form990s) in case you want to clone and use that (you'll have to modify the package name in `setup.py` so Test PyPI will let you upload it).

I am realizing now that [our Getting Started guide](https://warehouse.readthedocs.io/development/getting-started/) lacks information on uploading packages locally. @waseem18 and @lgh2 I think you've dealt with this -- how did you manage it? Whatever you advise, we should write it up and add it to the docs!
@aalmazan Sorry for this oversight! 
@aalmazan What you can do is - Find a user from local database who has one or more packages then reset the user's password and login with the same user. You can then use the user's packages to reproduce any issues.

@brainwane I'll add this information to the `Getting Started` guide sometime today.
Hi everyone, we actually already have documentation for how to login locally here: https://warehouse.readthedocs.io/development/getting-started/#logging-in-to-warehouse
@brainwane Our guide already has some details about uploading packages locally, but it's not in the "Getting Started" section: https://warehouse.pypa.io/development/reviewing-patches/?highlight=twine#testing-with-twine
I just spoke with Nicole and we agreed that this can wait till after we shut down legacy PyPI.
@aalmazan do you have what you need to proceed on this? Please do go ahead and work on it -- if we can merge your fix before shutting down legacy, all the better!
Below is a screenshot of what I currently have for the modal copy. Let me know if this should change. I think with how the `confirm_modal` macro is now, I'm not able to add more detail about what's deleted unless I add in some sort of `extra_details=[html_strings]` to the macro? Maybe we can add in the filename in the modal title if we're fine with having the title wrap to two lines? (i.e. "Delete File (filename.tar.gz) From pypusu?")

![selection_022](https://user-images.githubusercontent.com/800948/37752402-3d576882-2d55-11e8-8a22-4aaab2264e94.png)

----

Additionally, there seems to be a bug with the delete modal not clearing the delete button's previous state on close (see gif below). I don't think I see this reported in issues either -- has it been reported yet? I can fix the bug as well as I work on this issue.

![peek 2018-03-21 22-03](https://user-images.githubusercontent.com/800948/37752532-cd5e62dc-2d55-11e8-8a86-0a7036c44c4d.gif)

Hi @aalmazan - thanks for your work on this!  I think just "delete file from <project name>" for the title is fine (we had feedback during user tests that the file name itself could be really really long).

I agree that it would be nice to make another argument in the macro - but maybe for an additional line of information in the modal.  For example:

![screenshot from 2018-03-22 06-41-28](https://user-images.githubusercontent.com/3323703/37755126-13b0068c-2d9c-11e8-9640-ee017c96a8ff.png)

This would allow us to be more flexible with the main macro content in the future.  What do you think?

---------------------

Thanks for finding the button bug as well, I'll open a new issue for this :)



Resolving patch:
diff --git a/warehouse/manage/views.py b/warehouse/manage/views.py
--- a/warehouse/manage/views.py
+++ b/warehouse/manage/views.py
@@ -473,7 +473,7 @@ def delete_project_release(self):
 
     @view_config(
         request_method="POST",
-        request_param=["confirm_filename", "file_id"]
+        request_param=["confirm_project_name", "file_id"]
     )
     def delete_project_release_file(self):
 
@@ -487,9 +487,9 @@ def _error(message):
                 )
             )
 
-        filename = self.request.POST.get('confirm_filename')
+        project_name = self.request.POST.get('confirm_project_name')
 
-        if not filename:
+        if not project_name:
             return _error("Must confirm the request.")
 
         try:
@@ -504,10 +504,11 @@ def _error(message):
         except NoResultFound:
             return _error('Could not find file.')
 
-        if filename != release_file.filename:
+        if project_name != self.release.project.name:
             return _error(
                 "Could not delete file - " +
-                f"{filename!r} is not the same as {release_file.filename!r}",
+                f"{project_name!r} is not the same as "
+                f"{self.release.project.name!r}",
             )
 
         self.request.db.add(


Test patch:
diff --git a/tests/unit/manage/test_views.py b/tests/unit/manage/test_views.py
--- a/tests/unit/manage/test_views.py
+++ b/tests/unit/manage/test_views.py
@@ -1096,7 +1096,7 @@ def test_delete_project_release_file(self, monkeypatch):
         )
         request = pretend.stub(
             POST={
-                'confirm_filename': release_file.filename,
+                'confirm_project_name': release.project.name,
                 'file_id': release_file.id,
             },
             method="POST",
@@ -1156,7 +1156,7 @@ def test_delete_project_release_file_no_confirm(self):
             project=pretend.stub(name='foobar'),
         )
         request = pretend.stub(
-            POST={'confirm_filename': ''},
+            POST={'confirm_project_name': ''},
             method="POST",
             db=pretend.stub(delete=pretend.call_recorder(lambda a: None)),
             route_path=pretend.call_recorder(lambda *a, **kw: '/the-redirect'),
@@ -1195,7 +1195,7 @@ def no_result_found():
             raise NoResultFound
 
         request = pretend.stub(
-            POST={'confirm_filename': 'whatever'},
+            POST={'confirm_project_name': 'whatever'},
             method="POST",
             db=pretend.stub(
                 delete=pretend.call_recorder(lambda a: None),
@@ -1239,7 +1239,7 @@ def test_delete_project_release_file_bad_confirm(self):
             project=pretend.stub(name='foobar'),
         )
         request = pretend.stub(
-            POST={'confirm_filename': 'invalid'},
+            POST={'confirm_project_name': 'invalid'},
             method="POST",
             db=pretend.stub(
                 delete=pretend.call_recorder(lambda a: None),
@@ -1263,7 +1263,7 @@ def test_delete_project_release_file_bad_confirm(self):
         assert request.session.flash.calls == [
             pretend.call(
                 "Could not delete file - " +
-                f"'invalid' is not the same as {release_file.filename!r}",
+                f"'invalid' is not the same as {release.project.name!r}",
                 queue="error",
             )
         ]