Skip to content

Commit d33e1e3

Browse files
fix unit tests
1 parent 78e968c commit d33e1e3

File tree

14 files changed

+198
-114
lines changed

14 files changed

+198
-114
lines changed

api/institutions/authentication.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020

2121
from osf import features
2222
from osf.exceptions import InstitutionAffiliationStateError
23-
from osf.models import Institution
23+
from osf.models import Institution, NotificationType
2424
from osf.models.institution import SsoFilterCriteriaAction
2525

26-
from website.mails import send_mail, WELCOME_OSF4I, DUPLICATE_ACCOUNTS_OSF4I, ADD_SSO_EMAIL_OSF4I
26+
from website.mails import send_mail, DUPLICATE_ACCOUNTS_OSF4I, ADD_SSO_EMAIL_OSF4I
2727
from website.settings import OSF_SUPPORT_EMAIL, DOMAIN
2828
from website.util.metrics import institution_source_tag
2929

@@ -334,14 +334,13 @@ def authenticate(self, request):
334334
user.save()
335335

336336
# Send confirmation email for all three: created, confirmed and claimed
337-
send_mail(
338-
to_addr=user.username,
339-
mail=WELCOME_OSF4I,
340-
user=user,
341-
domain=DOMAIN,
342-
osf_support_email=OSF_SUPPORT_EMAIL,
343-
storage_flag_is_active=flag_is_active(request, features.STORAGE_I18N),
344-
)
337+
notification_type = NotificationType.objects.filter(name='welcome_osf4i')
338+
if not notification_type.exists():
339+
raise NotificationType.DoesNotExist(
340+
'NotificationType with name welcome_osf4i does not exist.',
341+
)
342+
notification_type = notification_type.first()
343+
notification_type.emit(user=user, message_frequency='instantly', event_context={'domain': DOMAIN, 'osf_support_email': OSF_SUPPORT_EMAIL, 'storage_flag_is_active': flag_is_active(request, features.STORAGE_I18N)})
345344

346345
# Add the email to the user's account if it is identified by the eppn
347346
if email_to_add:

api/users/views.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
OSFUser,
100100
Email,
101101
Tag,
102-
NotificationType
102+
NotificationType,
103103
)
104104
from osf.utils.tokens import TokenHandler
105105
from osf.utils.tokens.handlers import sanction_handler
@@ -847,10 +847,10 @@ def get(self, request, *args, **kwargs):
847847
notification_type = NotificationType.objects.filter(name=mail_template)
848848
if not notification_type.exists():
849849
raise NotificationType.DoesNotExist(
850-
f'NotificationType with name {mail_template} does not exist.'
850+
f'NotificationType with name {mail_template} does not exist.',
851851
)
852852
notification_type = notification_type.first()
853-
notification_type.emit(user=user_obj, event_context={'can_change_preferences': False, 'reset_link': reset_link})
853+
notification_type.emit(user=user_obj, message_frequency='instantly', event_context={'can_change_preferences': False, 'reset_link': reset_link})
854854

855855
return Response(status=status.HTTP_200_OK, data={'message': status_message, 'kind': kind, 'institutional': institutional})
856856

@@ -1066,10 +1066,10 @@ def _process_external_identity(self, user, external_identity, service_url):
10661066
notification_type = NotificationType.objects.filter(name='external_confirm_success')
10671067
if not notification_type.exists():
10681068
raise NotificationType.DoesNotExist(
1069-
'NotificationType with name external_confirm_success does not exist.'
1069+
'NotificationType with name external_confirm_success does not exist.',
10701070
)
10711071
notification_type = notification_type.first()
1072-
notification_type.emit(user=user, event_context={'can_change_preferences': False, 'external_id_provider': provider})
1072+
notification_type.emit(user=user, message_frequency='instantly', event_context={'can_change_preferences': False, 'external_id_provider': provider})
10731073

10741074
enqueue_task(update_affiliation_for_orcid_sso_users.s(user._id, provider_id))
10751075

@@ -1387,10 +1387,10 @@ def post(self, request, *args, **kwargs):
13871387
notification_type = NotificationType.objects.filter(name='external_confirm_success')
13881388
if not notification_type.exists():
13891389
raise NotificationType.DoesNotExist(
1390-
'NotificationType with name external_confirm_success does not exist.'
1390+
'NotificationType with name external_confirm_success does not exist.',
13911391
)
13921392
notification_type = notification_type.first()
1393-
notification_type.emit(user=user, event_context={'can_change_preferences': False, 'external_id_provider': provider})
1393+
notification_type.emit(user=user, message_frequency='instantly', event_context={'can_change_preferences': False, 'external_id_provider': provider})
13941394

13951395
enqueue_task(update_affiliation_for_orcid_sso_users.s(user._id, provider_id))
13961396

api_tests/institutions/views/test_institution_auth.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ def type_2_ineligible_user_roles():
183183

184184

185185
@pytest.mark.django_db
186+
@pytest.mark.usefixtures('mock_notification_send')
186187
class TestInstitutionAuth:
187188

188189
def test_invalid_payload(self, app, url_auth_institution):
@@ -280,7 +281,7 @@ def test_new_user_names_used_when_provided(self, app, institution, url_auth_inst
280281
assert user.given_name == 'Foo'
281282
assert user.family_name == 'Bar'
282283

283-
def test_user_active(self, app, institution, url_auth_institution):
284+
def test_user_active(self, mock_notification_send, app, institution, url_auth_institution):
284285

285286
username, fullname, password = '[email protected]', 'Foo Bar', 'FuAsKeEr'
286287
user = make_user(username, fullname)
@@ -316,7 +317,7 @@ def test_user_active(self, app, institution, url_auth_institution):
316317
# Confirm affiliation
317318
assert institution in user.get_affiliated_institutions()
318319

319-
def test_user_unclaimed(self, app, institution, url_auth_institution):
320+
def test_user_unclaimed(self, mock_notification_send, app, institution, url_auth_institution):
320321

321322
username, fullname = '[email protected]', 'Foo Bar'
322323
project = ProjectFactory()
@@ -399,7 +400,7 @@ def test_user_unconfirmed(self, app, institution, url_auth_institution):
399400
# Confirm affiliation
400401
assert institution in user.get_affiliated_institutions()
401402

402-
def test_user_inactive(self, app, institution, url_auth_institution):
403+
def test_user_inactive(self, mock_notification_send, app, institution, url_auth_institution):
403404

404405
username, fullname, password = '[email protected]', 'Foo Bar', 'FuAsKeEr'
405406
user = make_user(username, fullname)

api_tests/users/views/test_user_confirm.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
@pytest.mark.django_db
9+
@pytest.mark.usefixtures('mock_notification_send')
910
class TestConfirmEmail:
1011

1112
@pytest.fixture()
@@ -147,8 +148,7 @@ def test_post_success_create(self, mock_send_mail, app, confirm_url, user_with_e
147148
assert user.external_identity == {'ORCID': {'0002-0001-0001-0001': 'VERIFIED'}}
148149
assert user.emails.filter(address=email.lower()).exists()
149150

150-
@mock.patch('website.mails.send_mail')
151-
def test_post_success_link(self, mock_send_mail, app, confirm_url, user_with_email_verification):
151+
def test_post_success_link(self, mock_notification_send, app, confirm_url, user_with_email_verification):
152152
user, token, email = user_with_email_verification
153153
user.external_identity['ORCID']['0000-0000-0000-0000'] = 'LINK'
154154
user.save()
@@ -168,14 +168,13 @@ def test_post_success_link(self, mock_send_mail, app, confirm_url, user_with_ema
168168
)
169169
assert res.status_code == 201
170170

171-
assert mock_send_mail.called
171+
assert mock_notification_send.called
172172

173173
user.reload()
174174
assert user.external_identity['ORCID']['0000-0000-0000-0000'] == 'VERIFIED'
175175

176-
@mock.patch('website.mails.send_mail')
177176
def test_post_success_link_with_email_verification_none(
178-
self, mock_send_mail, app, confirm_url, user_with_none_identity
177+
self, mock_notification_send, app, confirm_url, user_with_none_identity
179178
):
180179
user, token, email = user_with_none_identity
181180
user.save()
@@ -195,15 +194,14 @@ def test_post_success_link_with_email_verification_none(
195194
)
196195
assert res.status_code == 201
197196

198-
assert not mock_send_mail.called # no orcid sso message
197+
assert not mock_notification_send.called # no orcid sso message
199198

200199
user.reload()
201200
assert not user.external_identity
202201

203-
@mock.patch('website.mails.send_mail')
204202
def test_post_success_link_with_email_already_exists(
205203
self,
206-
mock_send_mail,
204+
mock_notification_send,
207205
app,
208206
confirm_url,
209207
user_with_email_verification

api_tests/users/views/test_user_external_login.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414

1515
@pytest.mark.django_db
16+
@pytest.mark.usefixtures('mock_notification_send')
1617
class TestExternalLogin:
1718

1819
@pytest.fixture()
@@ -73,7 +74,7 @@ def test_invalid_payload(self, app, url, session_data, csrf_token):
7374
res = app.post_json_api(url, payload, expect_errors=True, headers={'X-CSRFToken': csrf_token})
7475
assert res.status_code == 400
7576

76-
def test_existing_user(self, app, payload, url, user_one, session_data, csrf_token):
77+
def test_existing_user(self, mock_notification_send, app, payload, url, user_one, session_data, csrf_token):
7778
app.set_cookie(CSRF_COOKIE_NAME, csrf_token)
7879
app.set_cookie(settings.COOKIE_NAME, str(session_data))
7980
payload['data']['attributes']['email'] = user_one.username

api_tests/users/views/test_user_settings.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def unconfirmed_address():
2828

2929

3030
@pytest.mark.django_db
31+
@pytest.mark.usefixtures('mock_notification_send')
3132
@pytest.mark.usefixtures('mock_send_grid')
3233
class TestUserRequestExport:
3334

@@ -48,7 +49,7 @@ def test_get(self, app, user_one, url):
4849
res = app.get(url, auth=user_one.auth, expect_errors=True)
4950
assert res.status_code == 405
5051

51-
def test_post(self, mock_send_grid, app, user_one, user_two, url, payload):
52+
def test_post(self, mock_send_grid, mock_notification_send, app, user_one, user_two, url, payload):
5253
# Logged out
5354
res = app.post_json_api(url, payload, expect_errors=True)
5455
assert res.status_code == 401
@@ -65,14 +66,14 @@ def test_post(self, mock_send_grid, app, user_one, user_two, url, payload):
6566
assert user_one.email_last_sent is not None
6667
assert mock_send_grid.call_count == 1
6768

68-
def test_post_invalid_type(self, mock_send_grid, app, user_one, url, payload):
69+
def test_post_invalid_type(self, mock_notification_send, app, user_one, url, payload):
6970
assert user_one.email_last_sent is None
7071
payload['data']['type'] = 'Invalid Type'
7172
res = app.post_json_api(url, payload, auth=user_one.auth, expect_errors=True)
7273
assert res.status_code == 409
7374
user_one.reload()
7475
assert user_one.email_last_sent is None
75-
assert mock_send_grid.call_count == 0
76+
assert mock_notification_send.call_count == 0
7677

7778
def test_exceed_throttle(self, app, user_one, url, payload):
7879
assert user_one.email_last_sent is None
@@ -87,6 +88,7 @@ def test_exceed_throttle(self, app, user_one, url, payload):
8788

8889

8990
@pytest.mark.django_db
91+
@pytest.mark.usefixtures('mock_notification_send')
9092
class TestUserChangePassword:
9193

9294
@pytest.fixture()
@@ -168,7 +170,7 @@ def test_multiple_errors(self, app, user_one, url, payload):
168170

169171

170172
@pytest.mark.django_db
171-
@pytest.mark.usefixtures('mock_send_grid')
173+
@pytest.mark.usefixtures('mock_notification_send')
172174
class TestResetPassword:
173175

174176
@pytest.fixture()
@@ -187,22 +189,22 @@ def url(self):
187189
def csrf_token(self):
188190
return csrf._mask_cipher_secret(csrf._get_new_csrf_string())
189191

190-
def test_get(self, mock_send_grid, app, url, user_one):
192+
def test_get(self, mock_notification_send, app, url, user_one):
191193
encoded_email = urllib.parse.quote(user_one.email)
192194
url = f'{url}?email={encoded_email}'
193195
res = app.get(url)
194196
assert res.status_code == 200
195197

196198
user_one.reload()
197-
assert mock_send_grid.call_args[1]['to_addr'] == user_one.username
199+
assert mock_notification_send.called
198200

199-
def test_get_invalid_email(self, mock_send_grid, app, url):
201+
def test_get_invalid_email(self, mock_notification_send, app, url):
200202
url = f'{url}?email={'invalid_email'}'
201203
res = app.get(url)
202204
assert res.status_code == 200
203-
assert not mock_send_grid.called
205+
assert not mock_notification_send.called
204206

205-
def test_post(self, app, url, user_one, csrf_token):
207+
def test_post(self, mock_notification_send, app, url, user_one, csrf_token):
206208
app.set_cookie(CSRF_COOKIE_NAME, csrf_token)
207209
encoded_email = urllib.parse.quote(user_one.email)
208210
url = f'{url}?email={encoded_email}'
@@ -222,6 +224,7 @@ def test_post(self, app, url, user_one, csrf_token):
222224
user_one.reload()
223225
assert res.status_code == 200
224226
assert user_one.check_password('password2')
227+
assert mock_notification_send.called
225228

226229
def test_post_empty_payload(self, app, url, csrf_token):
227230
app.set_cookie(CSRF_COOKIE_NAME, csrf_token)

conftest.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from framework.celery_tasks import app as celery_app
1919
from osf.external.spam import tasks as spam_tasks
2020
from website import settings as website_settings
21+
from osf.management.commands.migrate_notifications import update_notification_types
2122

2223

2324
logger = logging.getLogger(__name__)
@@ -374,3 +375,25 @@ def start_mock_send_grid(test_case):
374375
test_case.addCleanup(patcher.stop)
375376
mocked_send.return_value = True
376377
return mocked_send
378+
379+
380+
@pytest.fixture()
381+
def mock_notification_send():
382+
with mock.patch.object(website_settings, 'USE_EMAIL', True):
383+
with mock.patch.object(website_settings, 'USE_CELERY', False):
384+
with mock.patch('osf.models.notification.Notification.send') as mock_emit:
385+
mock_emit.return_value = None # Or True, if needed
386+
yield mock_emit
387+
388+
389+
def start_mock_notification_send(test_case):
390+
patcher = mock.patch('osf.models.notification.Notification.send')
391+
mocked_emit = patcher.start()
392+
test_case.addCleanup(patcher.stop)
393+
mocked_emit.return_value = None
394+
return mocked_emit
395+
396+
397+
@pytest.fixture(autouse=True)
398+
def load_notification_types(*args, **kwargs):
399+
update_notification_types(*args, **kwargs)

framework/auth/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from osf.exceptions import ValidationValueError, BlockedEmailError
3434
from osf.models.provider import PreprintProvider
3535
from osf.models.tag import Tag
36-
from osf.models.notification import NotificationType
36+
from osf.models.notification_type import NotificationType
3737
from osf.utils.requests import check_select_for_update
3838
from website.util.metrics import CampaignClaimedTags, CampaignSourceTags
3939
from website.ember_osf_web.decorators import ember_flag_is_active
@@ -279,7 +279,7 @@ def _forgot_password_post(mail_template, reset_route, institutional=False):
279279
f'NotificationType with name {mail_template} does not exist.'
280280
)
281281
notification_type = notification_type.first()
282-
notification_type.emit(user=user_obj, event_context={'can_change_preferences': False, 'reset_link': reset_link})
282+
notification_type.emit(user=user_obj, message_frequency='instantly', event_context={'can_change_preferences': False, 'reset_link': reset_link})
283283

284284
# institutional forgot password page displays the message as main text, not as an alert
285285
if institutional:

notifications.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,52 @@ notification_types:
1414
object_content_type_model_name: osfuser
1515
template: 'website/templates/emails/new_pending_submissions.html.mako'
1616
notification_freq_default: instantly
17+
- name: password_reset
18+
__docs__: ...
19+
object_content_type_model_name: osfuser
20+
template: 'website/templates/emails/password_reset.html.mako'
21+
notification_freq_default: instantly
22+
- name: forgot_password
23+
__docs__: ...
24+
object_content_type_model_name: osfuser
25+
template: 'website/templates/emails/forgot_password.html.mako'
26+
notification_freq_default: instantly
27+
- name: welcome_osf4i
28+
__docs__: ...
29+
object_content_type_model_name: osfuser
30+
template: 'website/templates/emails/welcome_osf4i.html.mako'
31+
notification_freq_default: instantly
32+
- name: invite_preprints_osf
33+
__docs__: ...
34+
object_content_type_model_name: osfuser
35+
template: 'website/templates/emails/invite_preprints_osf.html.mako'
36+
notification_freq_default: instantly
37+
- name: invite_preprints
38+
__docs__: ...
39+
object_content_type_model_name: osfuser
40+
template: 'website/templates/emails/invite_preprints.html.mako'
41+
notification_freq_default: instantly
42+
- name: invite_draft_registration
43+
__docs__: ...
44+
object_content_type_model_name: osfuser
45+
template: 'website/templates/emails/invite_draft_registration.html.mako'
46+
notification_freq_default: instantly
47+
- name: invite_default
48+
__docs__: ...
49+
object_content_type_model_name: osfuser
50+
template: 'website/templates/emails/invite_default.html.mako'
51+
notification_freq_default: instantly
52+
- name: pending_invite
53+
__docs__: ...
54+
object_content_type_model_name: osfuser
55+
template: 'website/templates/emails/pending_invite.html.mako'
56+
notification_freq_default: instantly
57+
- name: forward_invite
58+
__docs__: ...
59+
object_content_type_model_name: osfuser
60+
template: 'website/templates/emails/forward_invite.html.mako'
61+
notification_freq_default: instantly
62+
1763
#### PROVIDER
1864
- name: new_pending_submissions
1965
__docs__: ...

0 commit comments

Comments
 (0)