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

Handle FileNotFoundError on download of messages #5573

Conversation

DrGFreeman
Copy link
Contributor

@DrGFreeman DrGFreeman commented Oct 10, 2020

Status

Ready for review.

Description of Changes

Fixes #4787

Changes proposed in this pull request:

Handle the FileNotFoundError on download of message in the JI where the corresponding file is missing on the filesystem.

  • Display a flash message to the journalist.
  • Add a log entry reporting the error.
  • Redirect to the page from which the download was attempted.

Also added functional test for flash message and redirect and tests for logging of the error.

Testing

How should the reviewer test this PR?
Write out any special testing steps here.

Setup

  1. Run make dev.
  2. Log in the Source Interface and submit two messages.
  3. Log in the app server Docker container with docker exec -it securedrop-dev-0 bash and delete the first message (filename 1-something_something-msg.gpg) from the source's directory in /var/lib/securedrop/store.

Scenario 1 - Download via "n unread" button on /

  1. Log in the Journalist Interface.
  2. Click the "2 unread" button of the first source.
    • Verify that a flash error message is displayed
    • Verify that the page remains unchanged (journalist homepage)
    • Verify that the source's number of unread message is unchanged (2)

Scenario 2 - Download via "Download Unread" button on /

  1. Log in the Journalist Interface.
  2. Check the first source's checkbox.
  3. Click the "Download Unread" button.
    • Verify that a flash error message is displayed
    • Verify that the page remains unchanged (journalist homepage)
    • Verify that the source's number of unread message is unchanged (2)

Scenario 3 - Download via "Download" button on /

  1. Log in the Journalist Interface.
  2. Check the first source's checkbox.
  3. Click the "Download" button.
    • Verify that a flash error message is displayed
    • Verify that the page remains unchanged (journalist homepage)
    • Verify that the source's number of unread message is unchanged (2)

Scenario 4 - Download via "Download Selected" button on /col/<filesystem_id>

  1. Log in the Journalist Interface.
  2. Click the first source's code name.
  3. Click the "Select All" button
  4. Click the "Download Selected" button.
    • Verify that a flash error message is displayed
    • Verify that the page remains unchanged (source collection page)
    • Verify that the first message remains unread

Scenario 5 - Direct message download from /col/<filesystem_id>

  1. Log in the Journalist Interface.
  2. Click the first source's code name.
  3. Click first message.
    • Verify that a flash error message is displayed
    • Verify that the page remains unchanged (source collection page)
    • Verify that the first message remains unread

Deployment

Any special considerations for deployment? Consider both:

  1. Upgrading existing production instances.
  2. New installs.

Checklist

If you made changes to the server application code:

  • Linting (make lint) and tests (make test) pass in the development container

If you made changes to securedrop-admin:

  • Linting and tests (make -C admin test) pass in the admin development container

If you made changes to the system configuration:

If you made non-trivial code changes:

  • I have written a test plan and validated it for this PR
    Test plan above + added unit/functional tests.

If you made changes to documentation:

  • Doc linting (make docs-lint) passed locally

If you added or updated a code dependency:

Choose one of the following:

  • I have performed a diff review and pasted the contents to the packaging wiki
  • I would like someone else to do the diff review

@eloquence
Copy link
Member

Thanks for picking this up @DrGFreeman. Don't hesitate to comment if you're looking for feedback even while it's still in draft stage.

@eloquence eloquence changed the title Handle FileNotFoudError on download of messages Handle FileNotFoundError on download of messages Oct 13, 2020
@DrGFreeman
Copy link
Contributor Author

Thanks for the follow-up @eloquence. I was having difficulty setting up the missing file for the functional tests but figured out a way today (ref 995eed0).

I'm not yet done with the PR as I also want to check for proper logging of the error. UX feedback would however be welcome when you or someone has time. I added testing steps to the PR.

@DrGFreeman DrGFreeman marked this pull request as ready for review October 15, 2020 04:07
@DrGFreeman
Copy link
Contributor Author

As discussed in #4787 (comment), I used a catch-all flash message for now. I'm open for modifications of the message as well as the error message being logged. Thx.

@eloquence
Copy link
Member

Kicked the error message around a bit with @creviera and @ninavizz.

Currently:

"An unexpected error occurred! Please inform your admin."

(Also used in other contexts.)

Proposed option A replacement:

"An unexpected error has occurred. Your admin can find more information in the system logs."

Proposed option B replacement:

"An unexpected error has occurred. More information has been recorded in the system logs."

Rationale:

  • Exclamation mark can be anxiety-provoking
  • Present perfect tense connects the error more clearly with the user's action
  • Pointing to logs (if it is true, which judging by the code changes is the case here) gives more actionable information

Thoughts @DrGFreeman, others?

@DrGFreeman
Copy link
Contributor Author

@eloquence, thanks for the feedback.

Proposed option A replacement:

"An unexpected error has occurred. Your admin can find more information in the system logs."

Proposed option B replacement:

"An unexpected error has occurred. More information has been recorded in the system logs."

I would personally go with option A as it refers the user to their admin while hinting at the additional information in the logs. With option B, as a journalist I may not know how to access the system logs and/or think about contacting the admin.

Rationale:

* Exclamation mark can be anxiety-provoking

* Present perfect tense connects the error more clearly with the user's action

I fully agree.

Side note: Instead of creating a new message, I used one that was already in the codebase:

flash(gettext(
"An unexpected error occurred! Please "
"inform your admin."), "error")

flash(gettext(
"An unexpected error occurred! Please "
"inform your admin."), "error")

flash(gettext(
"An unexpected error occurred! "
"Please inform your admin."), "error")

Maybe we should consider improving these messages as well? I could include this as an additional change in this PR.

@eloquence
Copy link
Member

Thanks @DrGFreeman. Yes, I noticed that, and think we should standardize the message where it is used, assuming of course that errors are indeed logged in all those cases. I suggest we wait another day or so, in case other folks want to weigh in before we do that.

Copy link
Contributor

@sssoleileraaa sssoleileraaa left a comment

Choose a reason for hiding this comment

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

lgtm: we no longer display a FileNotFoundError with traceback; instead a more user-friendly error is shown on the same page. one improvement would be to keep the checkboxes checked after an error rather than clearing the selection. this will help the user remember which files they tried to download. i think it's fine to create a follow-up issue if this takes too much time, especially since we might want to catch the missing files early on and handle it differently in the future. sounds like we're going to let this pr sit a bit longer to discuss error messaging, which gives you time to address my comment about logging and leaving the checkboxes checked (but again more than happy to open some follow-up issues for this just like i did for the bug found while testing your pr: freedomofpress/securedrop-client#1173)

securedrop/journalist_app/utils.py Show resolved Hide resolved
securedrop/journalist_app/col.py Outdated Show resolved Hide resolved
@sssoleileraaa
Copy link
Contributor

Forgot to share this lovely test plan:

Scenario 1 - Download via "n unread" button on /

  1. Log in the Journalist Interface.
  2. Click the "2 unread" button of the first source.
    ✔️ Verify that a flash error message is displayed
    ✔️ Verify that the page remains unchanged (journalist homepage)
    ✔️ Verify that the source's number of unread message is unchanged (2)

Scenario 2 - Download via "Download Unread" button on /

  1. Log in the Journalist Interface.
  2. Check the first source's checkbox.
  3. Click the "Download Unread" button.
    ✔️ Verify that a flash error message is displayed
    ✔️ Verify that the page remains unchanged (journalist homepage)
    ✔️ Verify that the source's number of unread message is unchanged (2)

Scenario 3 - Download via "Download" button on /

  1. Log in the Journalist Interface.
  2. Check the first source's checkbox.
  3. Click the "Download" button.
    ✔️ Verify that a flash error message is displayed
    ✔️ Verify that the page remains unchanged (journalist homepage)
    ✔️ Verify that the source's number of unread message is unchanged (2)

Scenario 4 - Download via "Download Selected" button on /col/<filesystem_id>

  1. Log in the Journalist Interface.
  2. Click the first source's code name.
  3. Click the "Select All" button
  4. Click the "Download Selected" button.
    ✔️ Verify that a flash error message is displayed
    ✔️ Verify that the page remains unchanged (source collection page)
    ✔️ Verify that the first message remains unread

Scenario 5 - Direct message download from /col/<filesystem_id>

  1. Log in the Journalist Interface.
  2. Click the first source's code name.
  3. Click first message.
    ✔️ Verify that a flash error message is displayed
    ✔️ Verify that the page remains unchanged (source collection page)
    ✔️ Verify that the first message remains unread

@sssoleileraaa
Copy link
Contributor

sssoleileraaa commented Oct 28, 2020

re proposed error message replacement options - couple of suggestions:

  • i think "please contact an administrator" instead of saying "your administrator" sounds better - people might not think of people with securedrop admin privileges as their admins

  • the error is that a file is missing, so we could be better about catching that error specifically and communicating about it specifically

  • overall, all language suggestions seem fine to me so far, especially since a) this is such an edge case and b) it would probably be better to focus on creating clear logs of which files are missing and not show database entries without files as options for download (also might be better to alert an admin ahead of time rather than waiting until user action)

@DrGFreeman
Copy link
Contributor Author

@creviera, thanks for the feedback!

I'll look into updating the error messages per your suggestions over the weekend and see how I can proceed to leave the messages selected in the case where the user used "Download Selected" (test scenario 4).

@DrGFreeman DrGFreeman force-pushed the 4787-error-on-download-deleted-files branch from 581e91f to ee18a23 Compare November 2, 2020 05:16
Copy link
Contributor

@sssoleileraaa sssoleileraaa left a comment

Choose a reason for hiding this comment

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

this looks great! tests pass and there are clear logs of which files are missing. left one review comment.

securedrop/journalist_app/col.py Outdated Show resolved Hide resolved
os.path.basename(filename)
))
return zip_file
missing_files = True
Copy link
Contributor

Choose a reason for hiding this comment

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

I might be missing something but why not raise FileNotFoundError here directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To allow logging all the missing files if more than one are missing (see commit message ee18a23)

@DrGFreeman
Copy link
Contributor Author

@creviera, message updated as per your proposal in 38b0aa4.

Looks like the type linting failure in CI is related to #5616 so I suppose it will be resolved when #5616 is merged.

@DrGFreeman
Copy link
Contributor Author

@creviera & @eloquence, returning on this discussion:

Thanks @DrGFreeman. Yes, I noticed that, and think we should standardize the message where it is used, assuming of course that errors are indeed logged in all those cases. I suggest we wait another day or so, in case other folks want to weigh in before we do that.

Initially we were to use a single generic message for all these errors. Now that the message is specific to missing files, I did not update the other instances. I could update these other messages in this PR but I'd have to review their context and propose appropriate messages.

Or would you prefer to raise a follow-up issue for these other messages?

Please advise.

@eloquence
Copy link
Member

eloquence commented Nov 5, 2020

Now that the message is specific to missing files, I did not update the other instances.

I think that's the best course of action here, we can revisit that at a later time if warranted. You are a bit behind develop, so I think next step is to rebase and ensure we no longer see the type annotation related linting issues.

Handle the FileNotFoundError on download of message in the JI where the
corresponding file is missing on the filesystem.
- Display a flash message to the journalist.
- Add a log entry reporting the error.
- Redirect to the page from which the download was attempted.
Implement functional tests for the case where a message file is missing
in the store. One test for each of the five ways to download a message
from the journalist interface. Each test implements the following:
 -Creates a message from the source interface
 -Delete the message file from the store
 -Attempts to download the message from the journalist interface
 -Check that a flash message is displayed in the journalist interface
 -Check that the journalist remains on the page from which they
  attempted to download the message
Check error logging for bulk download via /bulk and single message
download via /col/<filesystem_id>/<fn>.
- If more than one file is missing in bulk download, add a log entry for
  each missing file before returning the FileNotFound exception.
- Update unit test to verify logging of multiple missing files.

- Improve flashed error message.

- Rename tests, fixture and journalist navigation steps to align with
  changes.

- Rename file_ variable to file.
Change the return type to the more generic werkzeug.Response which
represents both the return types of flask.redirect (werkzeug.Response)
and flask.send_file (flask.Response which is derived from
wekrzeuf.Response).
Improve flash message text based on feedback from PR review process.
@DrGFreeman DrGFreeman force-pushed the 4787-error-on-download-deleted-files branch from 38b0aa4 to 592410f Compare November 6, 2020 01:33
@DrGFreeman
Copy link
Contributor Author

I think next step is to rebase and ensure we no longer see the type annotation related linting issues.

@eloquence & @creviera, here you go, rebased and all tests passing!

Copy link
Contributor

@sssoleileraaa sssoleileraaa left a comment

Choose a reason for hiding this comment

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

ran through the test plan again and lgtm

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.

unhandled FileNotFoundError when files have been manually deleted from disk
4 participants