Refactor e-mail generation and previewing

Review Request #8885 — Created April 6, 2017 and submitted

Information

Review Board
release-3.0.x

Reviewers

Previously e-mail generation and previewing used duplicated logic. The
preview_{foo}_email views would duplicate the logic used to generate
the template context that the mail_{foo} methods (that actually built
& sent the e-mails out).

Now, we have utilities for building e-mail messages
(prepare_{foo}_mail) that generate an EMailMessage but do not send
it and a generic e-mail sending & error-handling utility in
send_email. The logic for catching failed e-mails was present in each
method that sent an e-mail and it is now unified in a single place.

Additionally, we have a decorator that generates e-mail preview views
from functions that can generate the necessary arguments to provide to a
prepare_{foo}_email. This way the view only needs to compute the state
necessary, which has resulted in a large amount of deduplication.

Unit tests have been updated to reference the new methods.

Ran unit tests.

Description From Last Updated

email/decorators.py should be in this diff.

brenniebrennie

I don't think you meant to add reviewboard/notifications/original_cbs.py ?

daviddavid

'reviewboard.notifications.email.decorators.preview_email' imported but unused

reviewbotreviewbot

'reviewboard.notifications.email.message.prepare_password_changed_mail' imported but unused

reviewbotreviewbot

Might be slightly more intuitive as: if not (siteconfig.get('mail_send_review_close_mail') and review_request.public):

daviddavid

While here, can you remove the blank line and fix the ordering?

chipx86chipx86

"djblets"

chipx86chipx86

Let's reverse this check. It's quicker to check a boolean.

chipx86chipx86

No ending paren.

chipx86chipx86

No ending paren.

chipx86chipx86

Let's check trivial first.

chipx86chipx86

I think we have a :http: you can use for HTTP codes.

chipx86chipx86

This is :django:setting:

chipx86chipx86

raise

chipx86chipx86

Let's use .update here.

chipx86chipx86

We can use build_server_url().

chipx86chipx86

If .target_groups is already fetched, this is fine. If not, we should use .values_list(). (If the former, we should document …

chipx86chipx86

This won't work. It's missing a second argument. Good indication that we're missing a test condition or tests aren't passing.

chipx86chipx86

Can this not be imported higher up?

chipx86chipx86

This could be combined.

chipx86chipx86

Reads kinda weird. Maybe just "Whether the review should only be sent to the submitter of the review request."

chipx86chipx86

Can be inline above in extra_context.

chipx86chipx86

Can now use Python 2.7 set syntax.

chipx86chipx86

Wrapped weird.

chipx86chipx86

Wrapping and paragraph break issues.

chipx86chipx86

Let's use .update({...})

chipx86chipx86

No need for the parens after for.

chipx86chipx86

This can probably be one statement.

chipx86chipx86

"updated"

chipx86chipx86

Capitalize the beginning of each.

chipx86chipx86

Let's put one per line. Helps a little with readability here, given the statement below.

chipx86chipx86

I doubt you want these. We should have a unit test covering this case.

chipx86chipx86

2 blank lines.

chipx86chipx86

Blank line should remain.

chipx86chipx86

Trailing comma.

chipx86chipx86

local variable 'e' is assigned to but never used

reviewbotreviewbot

Missing period.

chipx86chipx86

E501 line too long (81 > 79 characters)

reviewbotreviewbot

E501 line too long (81 > 79 characters)

reviewbotreviewbot

E501 line too long (81 > 79 characters)

reviewbotreviewbot

E501 line too long (81 > 79 characters)

reviewbotreviewbot

E501 line too long (81 > 79 characters)

reviewbotreviewbot

E501 line too long (80 > 79 characters)

reviewbotreviewbot
brennie
brennie
brennie
brennie
brennie
brennie
Review request changed
Change Summary:

Refactored many changes out of this one.

Checks run (1 failed, 1 succeeded, 1 failed with error)

JSHint passed.
PEP8 Style Checker internal error.
Pyflakes failed.

Pyflakes

brennie
brennie
  1. 
      
  2. Show all issues

    email/decorators.py should be in this diff.

  3. 
      
brennie
brennie
david
  1. 
      
  2. Show all issues

    I don't think you meant to add reviewboard/notifications/original_cbs.py ?

  3. Show all issues

    Might be slightly more intuitive as:

    if not (siteconfig.get('mail_send_review_close_mail') and
            review_request.public):
    
  4. 
      
brennie
david
  1. Ship It!
  2. 
      
brennie
chipx86
  1. Loving the e-mail changes :) Fantastic cleanup.

  2. reviewboard/notifications/email/__init__.py (Diff revision 8)
     
     
     
     
    Show all issues

    While here, can you remove the blank line and fix the ordering?

    1. I think this was already fixed but didnt show up in the diff? :/ Its not in my local copy.

  3. Show all issues

    "djblets"

  4. Show all issues

    Let's reverse this check. It's quicker to check a boolean.

  5. Show all issues

    No ending paren.

  6. Show all issues

    No ending paren.

  7. Show all issues

    Let's check trivial first.

  8. Show all issues

    I think we have a :http: you can use for HTTP codes.

  9. Show all issues

    This is :django:setting:

  10. Show all issues

    raise

  11. reviewboard/notifications/email/message.py (Diff revision 8)
     
     
     
     
    Show all issues

    Let's use .update here.

  12. reviewboard/notifications/email/message.py (Diff revision 8)
     
     
     
    Show all issues

    We can use build_server_url().

  13. reviewboard/notifications/email/message.py (Diff revision 8)
     
     
     
     
     
    Show all issues

    If .target_groups is already fetched, this is fine. If not, we should use .values_list().

    (If the former, we should document that.)

  14. Show all issues

    This won't work. It's missing a second argument.

    Good indication that we're missing a test condition or tests aren't passing.

  15. Show all issues

    Can this not be imported higher up?

    1. Nope, ciruclar import. reviewboard.reviews.views imports email.messages.prepare_{} funcs.

  16. reviewboard/notifications/email/message.py (Diff revision 8)
     
     
     
     
    Show all issues

    This could be combined.

    1. No they cannot. This requires extra_context.

  17. Show all issues

    Reads kinda weird. Maybe just "Whether the review should only be sent to the submitter of the review request."

  18. reviewboard/notifications/email/message.py (Diff revision 8)
     
     
     
     
    Show all issues

    Can be inline above in extra_context.

    1. Nope. Requires extra_context to build it.

  19. Show all issues

    Can now use Python 2.7 set syntax.

  20. reviewboard/notifications/email/message.py (Diff revision 8)
     
     
     
    Show all issues

    Wrapped weird.

  21. reviewboard/notifications/email/message.py (Diff revision 8)
     
     
     
     
     
     
     
     
     
     
    Show all issues

    Wrapping and paragraph break issues.

    1. Reads fine to me, I don't know what you're talking about :P

  22. reviewboard/notifications/email/message.py (Diff revision 8)
     
     
     
     
    Show all issues

    Let's use .update({...})

  23. Show all issues

    No need for the parens after for.

  24. reviewboard/notifications/email/message.py (Diff revision 8)
     
     
     
     
    Show all issues

    This can probably be one statement.

  25. Show all issues

    "updated"

  26. reviewboard/notifications/email/utils.py (Diff revision 8)
     
     
     
    Show all issues

    Capitalize the beginning of each.

  27. Show all issues

    Let's put one per line. Helps a little with readability here, given the statement below.

  28. reviewboard/notifications/email/utils.py (Diff revision 8)
     
     
     
    Show all issues

    I doubt you want these. We should have a unit test covering this case.

  29. reviewboard/reviews/views.py (Diff revision 8)
     
     
     
     
     
    Show all issues

    2 blank lines.

  30. reviewboard/reviews/views.py (Diff revision 8)
     
     
     
     
    Show all issues

    Blank line should remain.

  31. reviewboard/reviews/views.py (Diff revision 8)
     
     
    Show all issues

    Trailing comma.

  32. 
      
brennie
Review request changed
Change Summary:

Addressed Christian's issues.

Checks run (1 failed, 1 succeeded, 1 failed with error)

JSHint passed.
PEP8 Style Checker internal error.
Pyflakes failed.

Pyflakes

brennie
david
  1. Ship It!
  2. 
      
chipx86
  1. Great cleanup :)

  2. Show all issues

    Missing period.

  3. 
      
brennie
Review request changed

Checks run (1 failed, 1 succeeded)

flake8 failed.
JSHint passed.

flake8

brennie
Review request changed
Status:
Completed
Change Summary:
Pushed to release-3.0.x (4b6a38f)