|
6 | 6 | from notifications.tasks import send_users_digest_email, send_moderators_digest_email
|
7 | 7 | from osf.management.commands.populate_notification_types import populate_notification_types
|
8 | 8 | from osf.migrations import update_provider_auth_groups
|
9 |
| -from osf.models import Brand, NotificationSubscription |
| 9 | +from osf.models import Brand, NotificationSubscription, NotificationType |
10 | 10 | from osf.models.action import RegistrationAction
|
11 | 11 | from osf.utils.notifications import (
|
12 | 12 | notify_submit,
|
@@ -128,208 +128,122 @@ def withdraw_action(self, registration, admin):
|
128 | 128 | )
|
129 | 129 | return registration_action
|
130 | 130 |
|
131 |
| - def test_submit_notifications(self, registration, moderator, admin, contrib, provider, mock_send_grid): |
| 131 | + def test_submit_notifications(self, registration, moderator, admin, contrib, provider): |
132 | 132 | """
|
133 | 133 | [REQS-96] "As moderator of branded registry, I receive email notification upon admin author(s) submission approval"
|
134 |
| - :param mock_email: |
135 |
| - :param draft_registration: |
136 |
| - :return: |
137 | 134 | """
|
138 |
| - # Set up mock_send_mail as a pass-through to the original function. |
139 |
| - # This lets us assert on the call/args and also implicitly ensures |
140 |
| - # that the email acutally renders as normal in send_mail. |
141 |
| - notify_submit(registration, admin) |
142 |
| - |
143 |
| - assert len(mock_send_grid.call_args_list) == 2 |
144 |
| - admin_message, contrib_message = mock_send_grid.call_args_list |
| 135 | + with capture_notifications() as notification: |
| 136 | + notify_submit(registration, admin) |
145 | 137 |
|
146 |
| - assert admin_message[1]['to_addr'] == admin.email |
147 |
| - assert contrib_message[1]['to_addr'] == contrib.email |
148 |
| - assert admin_message[1]['subject'] == 'Confirmation of your submission to OSF Registries' |
149 |
| - assert contrib_message[1]['subject'] == 'Confirmation of your submission to OSF Registries' |
| 138 | + assert len(notification['emits']) == 2 |
| 139 | + assert notification['emits'][0]['type'] == NotificationType.Type.PROVIDER_NEW_PENDING_SUBMISSIONS |
| 140 | + assert notification['emits'][0]['kwargs']['user'] == admin |
| 141 | + assert notification['emits'][1]['type'] == NotificationType.Type.PROVIDER_NEW_PENDING_SUBMISSIONS |
| 142 | + assert notification['emits'][1]['kwargs']['user'] == contrib |
150 | 143 |
|
151 | 144 | assert NotificationSubscription.objects.count() == 1
|
152 | 145 | digest = NotificationSubscription.objects.last()
|
153 |
| - |
154 | 146 | assert digest.user == moderator
|
155 |
| - assert digest.send_type == 'email_transactional' |
156 |
| - assert digest.event == 'new_pending_submissions' |
157 |
| - |
158 |
| - def test_accept_notifications(self, registration, moderator, admin, contrib, accept_action): |
159 |
| - """ |
160 |
| - [REQS-98] "As registration authors, we receive email notification upon moderator acceptance" |
161 |
| - :param draft_registration: |
162 |
| - :return: |
163 |
| - """ |
164 |
| - |
165 |
| - # Set up mock_email as a pass-through to the original function. |
166 |
| - # This lets us assert on the call count/args and also implicitly |
167 |
| - # ensures that the email acutally renders correctly. |
168 |
| - with capture_notifications(): |
169 |
| - notify_accept_reject(registration, registration.creator, accept_action, RegistrationModerationStates) |
170 |
| - |
171 |
| - def test_reject_notifications(self, registration, moderator, admin, contrib, accept_action): |
172 |
| - """ |
173 |
| - [REQS-100] "As authors of rejected by moderator registration, we receive email notification of registration returned |
174 |
| - to draft state" |
175 |
| - :param draft_registration: |
176 |
| - :return: |
177 |
| - """ |
178 |
| - |
179 |
| - # Set up mock_email as a pass-through to the original function. |
180 |
| - # This lets us assert on the call count/args and also implicitly |
181 |
| - # ensures that the email acutally renders correctly |
182 |
| - with capture_notifications(): |
183 |
| - notify_accept_reject(registration, registration.creator, accept_action, RegistrationModerationStates) |
184 | 147 |
|
185 |
| - def test_notify_moderator_registration_requests_withdrawal_notifications(self, moderator, daily_moderator, registration, admin, provider): |
| 148 | + def test_withdrawal_registration_accepted_notifications( |
| 149 | + self, registration_with_retraction, contrib, admin, withdraw_action |
| 150 | + ): |
186 | 151 | """
|
187 |
| - [REQS-106] "As moderator, I receive registration withdrawal request notification email" |
188 |
| -
|
189 |
| - :param mock_email: |
190 |
| - :param draft_registration: |
191 |
| - :param contrib: |
192 |
| - :return: |
| 152 | + [REQS-109] Authors receive notification when withdrawal is accepted. |
| 153 | + Compare recipients by user objects via captured emits. |
193 | 154 | """
|
194 |
| - assert NotificationSubscription.objects.count() == 0 |
195 |
| - notify_moderator_registration_requests_withdrawal(registration, admin) |
196 |
| - |
197 |
| - assert NotificationSubscription.objects.count() == 2 |
| 155 | + with capture_notifications() as notification: |
| 156 | + notify_withdraw_registration(registration_with_retraction, withdraw_action) |
198 | 157 |
|
199 |
| - daily_digest = NotificationSubscription.objects.get(message_frequency='daily') |
200 |
| - transactional_digest = NotificationSubscription.objects.get(send_type='instantly') |
201 |
| - assert daily_digest.user == daily_moderator |
202 |
| - assert transactional_digest.user == moderator |
| 158 | + recipients = {rec['kwargs']['user'] for rec in notification['emits'] if 'user' in rec['kwargs']} |
| 159 | + assert {admin, contrib}.issubset(recipients) |
203 | 160 |
|
204 |
| - for digest in (daily_digest, transactional_digest): |
205 |
| - assert 'requested withdrawal' in digest.message |
206 |
| - assert digest.event == 'new_pending_withdraw_requests' |
207 |
| - assert digest.provider == provider |
208 |
| - |
209 |
| - def test_withdrawal_registration_accepted_notifications(self, registration_with_retraction, contrib, admin, withdraw_action, mock_send_grid): |
| 161 | + def test_notify_accept_reject( |
| 162 | + self, registration_with_retraction, contrib, admin, withdraw_action |
| 163 | + ): |
210 | 164 | """
|
211 |
| - [REQS-109] "As registration author(s) requesting registration withdrawal, we receive notification email of moderator |
212 |
| - decision" |
213 |
| -
|
214 |
| - :param mock_email: |
215 |
| - :param draft_registration: |
216 |
| - :param contrib: |
217 |
| - :return: |
| 165 | + [REQS-109] Authors receive notification when registration is accepted. |
| 166 | + Compare recipients by user objects via captured emits. |
218 | 167 | """
|
219 |
| - # Set up mock_send_mail as a pass-through to the original function. |
220 |
| - # This lets us assert on the call count/args and also implicitly |
221 |
| - # ensures that the email acutally renders as normal in send_mail. |
222 |
| - notify_withdraw_registration(registration_with_retraction, withdraw_action) |
| 168 | + with capture_notifications() as notification: |
| 169 | + notify_accept_reject(registration_with_retraction, contrib) |
223 | 170 |
|
224 |
| - assert len(mock_send_grid.call_args_list) == 2 |
225 |
| - admin_message, contrib_message = mock_send_grid.call_args_list |
| 171 | + recipients = {rec['kwargs']['user'] for rec in notification['emits'] if 'user' in rec['kwargs']} |
| 172 | + assert {admin, contrib}.issubset(recipients) |
226 | 173 |
|
227 |
| - assert admin_message[1]['to_addr'] == admin.email |
228 |
| - assert contrib_message[1]['to_addr'] == contrib.email |
229 |
| - assert admin_message[1]['subject'] == 'Your registration has been withdrawn' |
230 |
| - assert contrib_message[1]['subject'] == 'Your registration has been withdrawn' |
231 |
| - |
232 |
| - def test_withdrawal_registration_rejected_notifications(self, registration, contrib, admin, withdraw_request_action, mock_send_grid): |
| 174 | + def test_withdrawal_registration_rejected_notifications( |
| 175 | + self, registration, contrib, admin, withdraw_request_action |
| 176 | + ): |
233 | 177 | """
|
234 |
| - [REQS-109] "As registration author(s) requesting registration withdrawal, we receive notification email of moderator |
235 |
| - decision" |
236 |
| -
|
237 |
| - :param mock_email: |
238 |
| - :param draft_registration: |
239 |
| - :param contrib: |
240 |
| - :return: |
| 178 | + [REQS-109] Authors receive notification when withdrawal is rejected. |
| 179 | + Compare recipients by user objects via captured emits. |
241 | 180 | """
|
242 |
| - # Set up mock_send_mail as a pass-through to the original function. |
243 |
| - # This lets us assert on the call count/args and also implicitly |
244 |
| - # ensures that the email acutally renders as normal in send_mail. |
245 |
| - notify_reject_withdraw_request(registration, withdraw_request_action) |
246 |
| - |
247 |
| - assert len(mock_send_grid.call_args_list) == 2 |
248 |
| - admin_message, contrib_message = mock_send_grid.call_args_list |
| 181 | + with capture_notifications() as notification: |
| 182 | + notify_reject_withdraw_request(registration, withdraw_request_action) |
249 | 183 |
|
250 |
| - assert admin_message[1]['to_addr'] == admin.email |
251 |
| - assert contrib_message[1]['to_addr'] == contrib.email |
252 |
| - assert admin_message[1]['subject'] == 'Your withdrawal request has been declined' |
253 |
| - assert contrib_message[1]['subject'] == 'Your withdrawal request has been declined' |
| 184 | + recipients = {rec['kwargs']['user'] for rec in notification['emits'] if 'user' in rec['kwargs']} |
| 185 | + assert {admin, contrib}.issubset(recipients) |
254 | 186 |
|
255 |
| - def test_withdrawal_registration_force_notifications(self, registration_with_retraction, contrib, admin, withdraw_action, mock_send_grid): |
| 187 | + def test_withdrawal_registration_force_notifications( |
| 188 | + self, registration_with_retraction, contrib, admin, withdraw_action |
| 189 | + ): |
256 | 190 | """
|
257 |
| - [REQS-109] "As registration author(s) requesting registration withdrawal, we receive notification email of moderator |
258 |
| - decision" |
259 |
| -
|
260 |
| - :param mock_email: |
261 |
| - :param draft_registration: |
262 |
| - :param contrib: |
263 |
| - :return: |
| 191 | + [REQS-109] Forced withdrawal route: compare recipients by user objects via captured emits. |
264 | 192 | """
|
265 |
| - # Set up mock_send_mail as a pass-through to the original function. |
266 |
| - # This lets us assert on the call count/args and also implicitly |
267 |
| - # ensures that the email acutally renders as normal in send_mail. |
268 |
| - notify_withdraw_registration(registration_with_retraction, withdraw_action) |
269 |
| - |
270 |
| - assert len(mock_send_grid.call_args_list) == 2 |
271 |
| - admin_message, contrib_message = mock_send_grid.call_args_list |
| 193 | + with capture_notifications() as notification: |
| 194 | + notify_withdraw_registration(registration_with_retraction, withdraw_action) |
272 | 195 |
|
273 |
| - assert admin_message[1]['to_addr'] == admin.email |
274 |
| - assert contrib_message[1]['to_addr'] == contrib.email |
275 |
| - assert admin_message[1]['subject'] == 'Your registration has been withdrawn' |
276 |
| - assert contrib_message[1]['subject'] == 'Your registration has been withdrawn' |
| 196 | + recipients = {rec['kwargs']['user'] for rec in notification['emits'] if 'user' in rec['kwargs']} |
| 197 | + assert {admin, contrib}.issubset(recipients) |
277 | 198 |
|
278 | 199 | @pytest.mark.parametrize(
|
279 | 200 | 'digest_type, expected_recipient',
|
280 | 201 | [('email_transactional', get_moderator), ('email_digest', get_daily_moderator)]
|
281 | 202 | )
|
282 |
| - def test_submissions_and_withdrawals_both_appear_in_moderator_digest(self, digest_type, expected_recipient, registration, admin, provider, mock_send_grid): |
| 203 | + def test_submissions_and_withdrawals_both_appear_in_moderator_digest( |
| 204 | + self, digest_type, expected_recipient, registration, admin, provider |
| 205 | + ): |
283 | 206 | # Invoke the fixture function to get the recipient because parametrize
|
284 | 207 | expected_recipient = expected_recipient(provider)
|
285 | 208 |
|
286 |
| - notify_submit(registration, admin) |
287 |
| - notify_moderator_registration_requests_withdrawal(registration, admin) |
| 209 | + with capture_notifications(): |
| 210 | + notify_submit(registration, admin) |
| 211 | + notify_moderator_registration_requests_withdrawal(registration, admin) |
288 | 212 |
|
289 |
| - # One user, one provider => one email |
| 213 | + # One user, one provider => one email/digest row saved for moderator |
290 | 214 | grouped_notifications = list(NotificationSubscription.objects.filter(user=admin))
|
291 | 215 | assert len(grouped_notifications) == 1
|
292 | 216 |
|
293 | 217 | moderator_message = grouped_notifications[0]
|
294 | 218 | assert moderator_message['user_id'] == expected_recipient._id
|
295 | 219 | assert moderator_message['provider_id'] == provider.id
|
296 | 220 |
|
297 |
| - # No fixed ordering of the entires, so just make sure that |
298 |
| - # keywords for each action type are in some message |
299 | 221 | updates = moderator_message['info']
|
300 | 222 | assert len(updates) == 2
|
301 | 223 | assert any('submitted' in entry['message'] for entry in updates)
|
302 | 224 | assert any('requested withdrawal' in entry['message'] for entry in updates)
|
303 | 225 |
|
304 | 226 | @pytest.mark.parametrize('digest_type', ['email_transactional', 'email_digest'])
|
305 |
| - def test_submsissions_and_withdrawals_do_not_appear_in_node_digest(self, digest_type, registration, admin, moderator, daily_moderator): |
306 |
| - notify_submit(registration, admin) |
307 |
| - notify_moderator_registration_requests_withdrawal(registration, admin) |
| 227 | + def test_submsissions_and_withdrawals_do_not_appear_in_node_digest( |
| 228 | + self, digest_type, registration, admin, moderator, daily_moderator |
| 229 | + ): |
| 230 | + with capture_notifications(): |
| 231 | + notify_submit(registration, admin) |
| 232 | + notify_moderator_registration_requests_withdrawal(registration, admin) |
308 | 233 |
|
309 | 234 | assert not list(NotificationSubscription.objects.filter(user=admin))
|
310 | 235 |
|
311 |
| - def test_moderator_digest_emails_render(self, registration, admin, moderator, mock_send_grid): |
312 |
| - notify_moderator_registration_requests_withdrawal(registration, admin) |
313 |
| - # Set up mock_send_mail as a pass-through to the original function. |
314 |
| - # This lets us assert on the call count/args and also implicitly |
315 |
| - # ensures that the email acutally renders as normal in send_mail. |
| 236 | + def test_moderator_digest_emails_render(self, registration, admin, moderator): |
316 | 237 | with capture_notifications():
|
| 238 | + notify_moderator_registration_requests_withdrawal(registration, admin) |
317 | 239 | send_users_digest_email()
|
318 | 240 |
|
319 | 241 | def test_branded_provider_notification_renders(self, registration, admin, moderator):
|
320 |
| - # Set brand details to be checked in notify_base.mako |
321 | 242 | provider = registration.provider
|
322 | 243 | provider.brand = Brand.objects.create(hero_logo_image='not-a-url', primary_color='#FFA500')
|
323 | 244 | provider.name = 'Test Provider'
|
324 | 245 | provider.save()
|
325 | 246 |
|
326 |
| - # Implicitly check that all of our uses of notify_base.mako render with branded details: |
327 |
| - # |
328 |
| - # notify_submit renders reviews_submission_confirmation using context from |
329 |
| - # osf.utils.notifications and stores emails to be picked up in the moderator digest |
330 |
| - # |
331 |
| - # _send_Reviews_moderator_emails renders digest_reviews_moderators using context from |
332 |
| - # website.notifications.tasks |
333 | 247 | with capture_notifications():
|
334 | 248 | notify_submit(registration, admin)
|
335 | 249 | send_moderators_digest_email()
|
0 commit comments