Cleanup and refactor the e-mail module
Review Request #7560 — Created July 30, 2015 and submitted
The recipient building portion of
send_review_mail
has been
refactored out into two methods:build_recipients
, which returns sets
ofUser
s andGroup
s that should receive the e-mail, as well as
recipients_to_addresses
, which builds sets of addresses with fewer
queries than before.The logic of determing the recipients of an e-mail has been moved out
ofsend_review_mail
and the signature of the function has changed to
accept theTO
andCC
fields as sets or lists ofUser
s and
Group
s. The logic has also been corrected to no longer send e-mails
to the following:
- users who have starred a review request but are no longer in the
review request's local site; - users in the
limit_recipients_to
list who are inactive; and - users in the
limit_recipients_to
list who are no longer part of
the review request's local site.
All methods that call into send_review_mail
to send e-mail now must
calculate the addresses they will be sending to. This is to allow for
a future change to allow extensions to filter the TO
and CC
fields of e-mails.
A large portion of this change is a style and docstring cleanup to
bring it in line with our style guidelines as well as adding numerous
new unit tests to cover all the behaviour of the two new functions
and ensure it does not regress.
Ran unit tests.
Description | From | Last Updated |
---|---|---|
"through the", here and below. |
chipx86 | |
I'd say "site configuration setting". |
chipx86 | |
Missing "full name". |
chipx86 | |
Missing period. |
chipx86 | |
I think to link this right, it'll need to be reviewboard.reviews.models.groups.Group. You'd have to check with a docs build. |
chipx86 | |
This is pretty old code. We can just do: if ',' not in group.mailing_list: |
chipx86 | |
Blank line between these. |
chipx86 | |
Col: 1 E302 expected 2 blank lines, found 1 |
reviewbot | |
Missing a trailing period. |
chipx86 | |
Before, extra_recipients was a list of usernames. Now it's treated as a list of users. Is that correct? If so, … |
chipx86 | |
This is checking if the function is present. It needs to be called. |
chipx86 | |
I know I provided the code snippet earlier, but I think if we do is_active=True first, it'll let the DB … |
chipx86 | |
Same here. |
chipx86 | |
This will fail if the , is first, but anyway, it should be: if ',' in recipient.mailing_list: |
chipx86 | |
We should specifically check if it's a string, and have an else that logs an error saying it's an unknown … |
chipx86 | |
Should be one line. |
chipx86 | |
Missing docs. |
chipx86 | |
Alignment problem. Also, in this case, you can pass a list or tuple in to issubset(). No need to build … |
chipx86 | |
'QuerySet' imported but unused |
reviewbot | |
While we're busy making things more correct, we should replace this with a call to email.utils.formataddr(), which will do correct … |
david | |
formataddr will do the right thing if the full name is falsy. |
david | |
This doesn't really work because these sets can now contain Group objects that users can be members of but we … |
EL elatt | |
Why is the cc_field set not being discarded as well? Also, it is unfortunate that we have to duplicate this … |
EL elatt |
-
Wow, big change. Looks like some great performance improvements.
Not that I want to add to your plate, but I'm going to want to see more unit tests covering more combinations of things. All the different conditionals we now have for choosing what ends up in sets should be tested.
Since it's broken up now, these should be easier to test. The new utility functions can be individually tested with every combination, and the send e-mail functions can be tested with the knowledge that those utility functions are working.
E-mail is pretty critical, and any bug will affect nearly every install, so it's just absolutely crucial that nothing slips by us here.
-
-
-
-
-
I think to link this right, it'll need to be
reviewboard.reviews.models.groups.Group
.You'd have to check with a docs build.
-
-
-
-
Before,
extra_recipients
was a list of usernames. Now it's treated as a list of users. Is that correct?If so, we should make sure to specify exactly what's expected in the docs above. We should also sanity-check the contents and log a suitable error about migrating the call, in case an extension is already calling this manually (I think there are some out there that do).
-
-
I know I provided the code snippet earlier, but I think if we do
is_active=True
first, it'll let the DB engine check that before checking the joins. -
-
-
We should specifically check if it's a string, and have an
else
that logs an error saying it's an unknown value, showing the repr of the value. -
-
-
Alignment problem.
Also, in this case, you can pass a list or tuple in to
issubset()
. No need to build aset
of the data.
- Change Summary:
-
Added unit tests. Fixed some bugs.
- Description:
-
The recipient building portion of
send_review_mail
has beenrefactored out into two methods: build_recipients
, which returns setsof User
s andGroup
s that should receive the e-mail, as well asrecipients_to_addresses
, which builds sets of addresses with fewerqueries than before. The logic of determing the recipients of an e-mail has been moved out
of send_review_mail
and the signature of the function has changed toaccept the TO
andCC
fields as sets or lists ofUser
s and~ Group
s.~ Group
s. The logic has also been corrected to no longer send e-mails+ to the following: + + - users who have starred a review request but are no longer in the
review request's local site;
+ - users in the
limit_recipients_to
list who are inactive; and
+ - users in the
limit_recipients_to
list who are no longer part of
the review request's local site.
All methods that call into
send_review_mail
to send e-mail now mustcalculate the addresses they will be sending to. This is to allow for a future change to allow extensions to filter the TO
andCC
fields of e-mails. A large portion of this change is a style and docstring cleanup to
~ bring it in line with our style guidelines. ~ bring it in line with our style guidelines as well as adding numerous + new unit tests to cover all the behaviour of the two new functions + and ensure it does not regress. - users who have starred a review request but are no longer in the
-
Tool: Pyflakes Processed Files: reviewboard/notifications/email.py reviewboard/notifications/tests.py Tool: PEP8 Style Checker Processed Files: reviewboard/notifications/email.py reviewboard/notifications/tests.py
-
Tool: Pyflakes Processed Files: reviewboard/notifications/email.py reviewboard/notifications/tests.py Tool: PEP8 Style Checker Processed Files: reviewboard/notifications/email.py reviewboard/notifications/tests.py
-
Tool: Pyflakes Processed Files: reviewboard/notifications/email.py reviewboard/notifications/tests.py Tool: PEP8 Style Checker Processed Files: reviewboard/notifications/email.py reviewboard/notifications/tests.py
-
Tool: Pyflakes Processed Files: reviewboard/notifications/email.py reviewboard/notifications/tests.py Tool: PEP8 Style Checker Processed Files: reviewboard/notifications/email.py reviewboard/notifications/tests.py
-
The current code doesn't quite work for users that have should_send_own_updates set to false, and a review is assigned to a group that the user is a member of, and this change is by said user. The problem is that the earlier filtering in build_recipients() can't detect this case b/c it just sees opaque Group objects, then in send_review_mail() these lists of User and Group objects get converted to lists of email addrs and we go and process should_send_own_updates again but for some reason ignore the cc_field list which is where the user's email addr is a member of now. Who are the clients of build_recipients()? Is it possible for build_recipients() to expand the User and Group objects into email addrs before returning its two sets? If we could, we could completely remove all that extra logic from send_review_mail() and it can just worry about sending email to the exact list of email addrs it was given. Otherwise, the only solution I see is that the should_send_own_updates() logic in build_recipients() get removed and the contract for the method should be updated to explicitly state that it is up to the clients of the method to do that processing (for both the to and cc field sets).
-
This doesn't really work because these sets can now contain Group objects that users can be members of but we don't expand the groups until outside of the method.
-
Why is the cc_field set not being discarded as well? Also, it is unfortunate that we have to duplicate this logic here. It would be easier to test if this logic was outside of this method