Skip to content

Commit 5c9b6b1

Browse files
committed
fix template and notification capture issues
1 parent fd85623 commit 5c9b6b1

17 files changed

Lines changed: 149 additions & 117 deletions

addons/base/tests/views.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,13 @@ def test_import_auth_cant_write_node(self):
183183
user.save()
184184

185185
node = ProjectFactory(creator=self.user)
186-
node.add_contributor(user, permissions=permissions.READ, auth=self.auth, save=True)
186+
node.add_contributor(
187+
user,
188+
permissions=permissions.READ,
189+
auth=self.auth,
190+
save=True,
191+
notification_type=False
192+
)
187193
node.add_addon(self.ADDON_SHORT_NAME, auth=self.auth)
188194
node.save()
189195
url = node.api_url_for(f'{self.ADDON_SHORT_NAME}_import_auth')
@@ -219,7 +225,13 @@ def test_get_config(self):
219225
def test_get_config_unauthorized(self):
220226
url = self.project.api_url_for(f'{self.ADDON_SHORT_NAME}_get_config')
221227
user = AuthUserFactory()
222-
self.project.add_contributor(user, permissions=permissions.READ, auth=self.auth, save=True)
228+
self.project.add_contributor(
229+
user,
230+
permissions=permissions.READ,
231+
auth=self.auth,
232+
save=True,
233+
notification_type=False
234+
)
223235
res = self.app.get(url, auth=user.auth, )
224236
assert res.status_code == http_status.HTTP_403_FORBIDDEN
225237

addons/bitbucket/tests/test_views.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ def test_set_config(self, mock_account, mock_repo):
7979
class TestBitbucketViews(OsfTestCase):
8080

8181
def setUp(self):
82-
super().setUp()
8382
self.user = AuthUserFactory()
8483
self.consolidated_auth = Auth(user=self.user)
8584

addons/osfstorage/tests/test_models.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from osf import models
2525
from addons.osfstorage import utils
2626
from addons.osfstorage import settings
27+
from tests.utils import capture_notifications
2728
from website.files.exceptions import FileNodeCheckedOutError, FileNodeIsPrimaryFile
2829

2930
SessionStore = import_module(django_conf_settings.SESSION_ENGINE).SessionStore
@@ -866,7 +867,8 @@ def setUp(self):
866867

867868
def test_checkout_logs(self):
868869
non_admin = factories.AuthUserFactory()
869-
self.node.add_contributor(non_admin, permissions=WRITE)
870+
with capture_notifications():
871+
self.node.add_contributor(non_admin, permissions=WRITE)
870872
self.node.save()
871873
self.file.check_in_or_out(non_admin, non_admin, save=True)
872874
self.file.reload()

osf/models/notification.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def send(
3939
f"\ncontext={self.event_context}"
4040
f"\nemail={email_context}"
4141
)
42-
elif protocol_type == 'email' and settings.DEV_MODE:
42+
if protocol_type == 'email' and settings.DEV_MODE:
4343
email.send_email_over_smtp(
4444
recipient_address,
4545
self.subscription.notification_type,

osf/models/preprint.py

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,35 +1026,29 @@ def _add_creator_as_contributor(self):
10261026
def _send_preprint_confirmation(self, auth):
10271027
# Send creator confirmation email
10281028
recipient = self.creator
1029-
if self.provider._id == 'osf':
1030-
logo = settings.OSF_PREPRINTS_LOGO
1031-
else:
1032-
logo = self.provider._id
1033-
1034-
context = {
1035-
'domain': settings.DOMAIN,
1036-
'reviewable_title': self.title,
1037-
'reviewable_absolute_url': self.absolute_url,
1038-
'reviewable_provider_name': self.provider.name,
1039-
'workflow': self.provider.reviews_workflow,
1040-
'provider_url': '{domain}preprints/{provider_id}'.format(
1041-
domain=self.provider.domain or settings.DOMAIN,
1042-
provider_id=self.provider._id if not self.provider.domain else '').strip('/'),
1043-
'provider_contact_email': self.provider.email_contact or settings.OSF_CONTACT_EMAIL,
1044-
'provider_support_email': self.provider.email_support or settings.OSF_SUPPORT_EMAIL,
1045-
'no_future_emails': False,
1046-
'is_creator': True,
1047-
'provider_name': 'OSF Preprints' if self.provider.name == 'Open Science Framework' else self.provider.name,
1048-
'logo': logo,
1049-
'document_type': self.provider.preprint_word
1050-
}
1051-
10521029
NotificationType.objects.get(
10531030
name=NotificationType.Type.PROVIDER_REVIEWS_SUBMISSION_CONFIRMATION
10541031
).emit(
10551032
subscribed_object=self.provider,
10561033
user=recipient,
1057-
event_context=context,
1034+
event_context={
1035+
'domain': settings.DOMAIN,
1036+
'user_fullname': recipient.fullname,
1037+
'referrer_fullname': recipient.fullname,
1038+
'reviewable_title': self.title,
1039+
'reviewable_absolute_url': self.absolute_url,
1040+
'reviewable_provider_name': self.provider.name,
1041+
'workflow': self.provider.reviews_workflow,
1042+
'provider_url': f'{self.provider.domain or settings.DOMAIN}preprints/'
1043+
f'{(self.provider._id if not self.provider.domain else '').strip('/')}',
1044+
'provider_contact_email': self.provider.email_contact or settings.OSF_CONTACT_EMAIL,
1045+
'provider_support_email': self.provider.email_support or settings.OSF_SUPPORT_EMAIL,
1046+
'no_future_emails': False,
1047+
'is_creator': True,
1048+
'provider_name': 'OSF Preprints' if self.provider.name == 'Open Science Framework' else self.provider.name,
1049+
'logo': settings.OSF_PREPRINTS_LOGO if self.provider._id == 'osf' else self.provider._id,
1050+
'document_type': self.provider.preprint_word
1051+
},
10581052
)
10591053

10601054
# FOLLOWING BEHAVIOR NOT SPECIFIC TO PREPRINTS

osf_tests/factories.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,10 @@ def _create(cls, target_class, *args, **kwargs):
796796
instance.set_subjects(subjects, auth=auth)
797797
if license_details:
798798
instance.set_preprint_license(license_details, auth=auth)
799-
instance.set_published(is_published, auth=auth)
799+
from tests.utils import capture_notifications
800+
801+
with capture_notifications():
802+
instance.set_published(is_published, auth=auth)
800803
create_task_patcher = mock.patch('website.identifiers.utils.request_identifiers')
801804
mock_create_identifier = create_task_patcher.start()
802805
if is_published and set_doi:

tests/base.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,11 @@ class OsfTestCase(DbTestCase, AppTestCase, SearchTestCase):
161161
application. Note: superclasses must call `super` in order for all setup and
162162
teardown methods to be called correctly.
163163
"""
164-
pass
164+
def setUp(self):
165+
from tests.utils import capture_notifications
166+
167+
with capture_notifications():
168+
return super().setUp()
165169

166170

167171
class ApiTestCase(DbTestCase, ApiAppTestCase, SearchTestCase):

tests/test_adding_contributor_views.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
)
2828
from tests.utils import capture_notifications
2929
from website.profile.utils import add_contributor_json, serialize_unregistered
30-
from website import settings
3130
from website.project.views.contributor import (
3231
deserialize_contributors,
3332
notify_added_contributor,

tests/utils.py

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -255,23 +255,38 @@ def run_celery_tasks():
255255

256256

257257
@contextlib.contextmanager
258-
def capture_notifications():
258+
def capture_notifications(capture_email: bool = True):
259259
"""
260-
Context manager to capture NotificationType emits without interfering with ORM calls.
261-
Yields a list of captured emits:
262-
[{'type': <NotificationType.Type>, 'args': ..., 'kwargs': ...}, ...]
260+
Context manager to capture NotificationType emits without interfering with ORM calls
261+
and (optionally) stub out actual email sending so tests don't open sockets.
262+
263+
Yields a dict with two lists:
264+
{
265+
"emits": [
266+
{"type": <str name>, "args": tuple, "kwargs": dict}, ...
267+
],
268+
"emails": [
269+
{
270+
"protocol": "smtp" | "sendgrid",
271+
"to": <str or user object>,
272+
"notification_type": <NotificationType or str>,
273+
"context": <dict>,
274+
"email_context": <dict>
275+
}, ...
276+
]
277+
}
263278
"""
264279
NotificationType = apps.get_model('osf', 'NotificationType')
265280
real_get = NotificationType.objects.get # Save the real .get()
266281

267-
captured = []
282+
captured = {'emits': [], 'emails': []}
268283

269284
def side_effect(*args, **kwargs):
270285
notifier = real_get(*args, **kwargs) # Call the real .get()
271286
original_emit = notifier.emit
272287

273288
def wrapped_emit(*emit_args, **emit_kwargs):
274-
captured.append({
289+
captured['emits'].append({
275290
'type': notifier.name,
276291
'args': emit_args,
277292
'kwargs': emit_kwargs
@@ -281,7 +296,34 @@ def wrapped_emit(*emit_args, **emit_kwargs):
281296
notifier.emit = wrapped_emit
282297
return notifier
283298

284-
with mock.patch('osf.models.notification_type.NotificationType.objects.get', side_effect=side_effect):
285-
yield captured
299+
patches = [
300+
mock.patch('osf.models.notification_type.NotificationType.objects.get', side_effect=side_effect),
301+
]
302+
if capture_email:
303+
def _fake_send_over_smtp(to_email, notification_type, context, email_context):
304+
captured['emails'].append({
305+
'protocol': 'smtp',
306+
'to': to_email,
307+
'notification_type': notification_type,
308+
'context': context,
309+
'email_context': email_context,
310+
})
286311

312+
def _fake_send_with_sendgrid(user, notification_type, context, email_context):
313+
captured['emails'].append({
314+
'protocol': 'sendgrid',
315+
'to': user, # keeping the object for tests that assert user props
316+
'notification_type': notification_type,
317+
'context': context,
318+
'email_context': email_context,
319+
})
287320

321+
patches.extend([
322+
mock.patch('osf.email.send_email_over_smtp', new=_fake_send_over_smtp),
323+
mock.patch('osf.email.send_email_with_send_grid', new=_fake_send_with_sendgrid),
324+
])
325+
326+
with contextlib.ExitStack() as stack:
327+
for p in patches:
328+
stack.enter_context(p)
329+
yield captured

website/project/views/contributor.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -625,17 +625,19 @@ def notify_added_contributor(node, contributor, notification_type, auth=None, *a
625625
throttle = kwargs.get('throttle', settings.CONTRIBUTOR_ADDED_EMAIL_THROTTLE)
626626
if notification_type and check_email_throttle(contributor, notification_type, throttle=throttle):
627627
return
628-
628+
referrer_name = getattr(getattr(auth, 'user', None), 'fullname', '') if auth else ''
629629
NotificationType.objects.get(
630630
name=notification_type
631631
).emit(
632632
user=contributor,
633633
event_context={
634-
'user': contributor.id,
635-
'referrer_name': getattr(getattr(auth, 'user', None), 'fullname', '') if auth else '',
634+
'user_fullname': contributor.fullname,
635+
'referred_text': referrer_name + ' has added you' if referrer_name else 'You have been add',
636+
'referrer_name': referrer_name,
636637
'is_initiator': getattr(getattr(auth, 'user', None), 'id', None) == contributor.id if auth else False,
637-
'all_global_subscriptions_none': False,
638638
'branded_service': getattr(getattr(node, 'provider', None), 'id', None),
639+
'node_title': node.title,
640+
'node_absolute_url': node.absolute_url,
639641
'can_change_preferences': False,
640642
'logo': logo,
641643
'osf_contact_email': settings.OSF_CONTACT_EMAIL,

0 commit comments

Comments
 (0)