Skip to content

Commit 981ef4a

Browse files
adliuscslzchenOstap-ZherebetskyiVlad0n20futa-ikeda
authored
Merge develop into Feature/pbs 26 2 (#11642)
* [ENG-10083] Add type<-->is_digest "relation" and update subscription (#11575) * Add is_digest_type property to NotificationType and log message in emit method * Fix is_digest handling in NotificationType.emit method * Log message update in NotificationType.emit method for is_digest handling * fix unit tests --------- Co-authored-by: Ostap Zherebetskyi <ozherebetskyi@exoft.net> * Add notification subscriptions de-duplication v2 command (#11576) Co-authored-by: Ostap Zherebetskyi <ozherebetskyi@exoft.net> * [ENG-10190][ENG-10214] Permanently update a couple of templates to match admin/admin changes Update archive_size_exceeded_user and provider_reviews_resubmission_confirmation templates * Update changelog and bump version * Exclude spam and deleted Registration from queryset (#11572) * [ENG-10135] - Fix/eng 10135 (#11587) * Exclude spam and deleted Registration from queryset * Update RegistrationActionList to check deleted flag * Fix tests * Fix test * Feature/fair signposting (#11599) * linkset initial implementation * linkset initial implementation (updating data extraction and adding serialization) * and \n in EOF instead of % * update code * get file mediatype from metadata * add unittests for linkset approach (TODO: ?) * update code * update code and unit tests and * update file related code and unit tests * refactor code after CR | implement 'describes' | check file type differs from parent project / registry / preprint * update files to compare on unittests run * implement datacite - scheme type mapping for linkset draft version (need tests updates and maybe some type yield logic ) * Update osf/metadata/osf_gathering.py Co-authored-by: abram axel booth <aaxelb@users.noreply.github.com> * Update osf/metadata/serializers/linkset.py Co-authored-by: abram axel booth <aaxelb@users.noreply.github.com> * implement datacite - schema mapping * update tests expected results * resolve CR * refactor code | resolve CR * remove redundant describes from file response (#11590) * [ENG-10256] 2.1.9 BE: Fix permission issue where users without permission to an object can access the metadata (#11588) * Fix permission issue where users without permission to an object can access the metadata (add decorator is_contributor_or_public_resource) * refactor code * resolve CR | refactor code * resolve CR | add unittests * add *args, **kwargs for decorated view * [ENG-10167] 2.1.6 BE: add link header to guid metadata endpoints (#11594) * add link header to guid metadata endpoints for registry and project * update code * avoid Component Registration/Project JSON Contains type: null (#11597) * [ENG-10168] 2.1.7 BE: add link header to cedar metadata records endpoints (#11596) * add link header to guid metadata endpoints for registry and project * update code * add link header to cedar metadata records endpoints * change ResearchProject for CreativeWork for projects (#11603) * [ENG-10169] 2.1.8 BE: add link header to file download URL (#11600) * avoid Component Registration/Project JSON Contains type: null * add link header to file download URL * update unittests * resolve CR --------- Co-authored-by: mkovalua <mkoval@exoft.net> Co-authored-by: abram axel booth <aaxelb@users.noreply.github.com> * Bump versio no. Add CHANGELOG * [ENG-10054] feature/ror-migration (#11610) * feat(osf): script to migrate Crossref Funder IDs to ROR IDs * feat(osf): Fix fot the script to migrate Crossref Funder IDs to ROR IDs * feat(osf): Update OSF metadata model code and tests for ROR funder identifier support * feat(osf): Add DataCite client tests for ROR funder identifier support * feat(osf): update migration script to remove unmapped crossref funders * add another stat to the migration script --------- Co-authored-by: Andriy Sheredko <sheredko.andriy@gmail.com> * bump version & update changelog * add command to migrate ror funder names * bump version & update changelog * [ENG-10538] Post-NR Project PR (#11623) * Create global_file_updated and global_reviews subscriptions if missing * Use USER_FILE_UPDATED for group global_file_updated * Use REVIEWS_SUBMISSION_STATUS for group global_reviews * Add missing `is_digest=True` for new OSF user subscriptions * Extend otf subscription creation to apply to _node_file_updated group * Fix typo for `_is_digest` * add is_digest_type property * Add is_digest_type property to NotificationType and log message in emit method * Fix is_digest handling in NotificationType.emit method * Log message update in NotificationType.emit method for is_digest handling * fix unit tests * Move set-deafult-subscriptions out of non-effective try-except * Add fake_sent field to Notification model and update notification creation logic * add unique_together constraint * Add 'PARTIAL_SUCCESS' status to EmailTask model and update email task handling logic * NR migration [ENG-10040, ENG-10025, ENG-9854] * Remove subscription if notifications.tasks.send_moderator_email_task fails with permission error * Apply suggestion from @Ostap-Zherebetskyi * remove datetime * Add 'no_login_email_last_sent' field to OSFUser and update email task logic * Enforce and improve permission check for subscriptions * Fix typo in annotated_obj_qs for NODE_FILE_UPDATED * Add unit tests for testing node_file_updated subscription detail * Implement notifications cleanup task and related settings; add tests for functionality * Fix legacy subscription ID for NODE_FILE_UPDATED: "guid_files_updated" * Fix duplicate and mismatched type NODE_FILE(S)_UPDATED * removed email.py * Fix annotated qs for global reviews and update unit tests * Update tests for node_file(s)_updated subscription detail * Rename fixtures for notification subscription detail tests * Annotate with legacy_id for serializer to handle created subscriptions * Add unit tests for creating missing subscriptions on the fly * clear useless code * Rename migration name for NR post-release * Improve unit test: test_emit_frequency_none * Remove `seen` from `Notification` and re-make migrations * `mark_sent()` now handles `fake_sent=True`, and only `save()` once * Update default settings * remove useless import * Enhance SubscriptionList queryset with additional content types and refactor notification type handling * fix unit test * Refactor SubscriptionList queryset to use a single provider content type and update related notification handling; add script to update notification subscriptions' content types. * fix CR comments * Update comments * split into 3 files * remove populate_notification_subscriptions * Renamed files, refactor of populate notification subscriptions user global file updated * added try/except, added timers * converted populate_notification_subscriptions_user_global_reviews.py * fix batch time execution * converted populate_notification_subscriptions_node_file_updated * convert to separate update and create scripts * updated, added parameters * move to remove_after_use * add time track to last batch, fix proper time track for batch in node_file_updated * convert to use review_nt * Fix unit tests due to new constraints * Move missing subscription creation to a helper function in utils * Subscription list view now creates missing attributes on-the-fly * Note: only works for when filter on "legacy id"; logs message to sentry for tracking purpose when filter on "event names". * Fix broken `.exists()` due to complex annotated QS with `.distinct()` * fix names of tasks * Add notification subscriptions de-duplication v2 command * fix naming * Add deduplication command to notification migration * Fix notification handling by updating legacy ID suffix from '_files_updated' to '_file_updated' across utils and views; adjust related test cases accordingly. * fix unit tests * Update the name of the NotificationType NODE_FILE_UPDATED to be consistent * Rename notification type from node_files_updated to node_file_updated for consistency * clean keys * fix naming in templates, event_context * remove leftover comments * Refactor notification type references to use NotificationTypeEnum - Updated all instances of NotificationType.Type to NotificationTypeEnum in test files and application code. - Ensured consistency in notification type usage across various tests including auth, claims, events, and more. - This change improves clarity and maintainability by standardizing the notification type references. * Fix notification type reference for FILE_UPDATED * Refactor notification type references to use NotificationTypeEnum across views and scripts * fix unit tests * remove imports * fix USER_CROSSREF_DOI_PENDING event_context * sync naming * added explanation * Add Celery task to disable removed beat tasks from PeriodicTask entries * Apply suggestion from @Ostap-Zherebetskyi * Apply suggestion from @cslzchen * Add migrations to remove duplicate notification subscriptions and refactor notification model * removed comment * Refactor no-login email filtering to ensure last sent date is before last login date * Add test to exclude users logged in before no_login_email_last_sent * Refactor no-login email user filtering to exclude those with pending EmailTasks and recent no-login emails * Fix CollectionSubmission URLs to use absolute_url method for consistency * Refactor logo handling in notification methods to improve consistency and readability * Add management command to sync notification templates * Apply suggestion from @cslzchen * Add management command for deleting withdrawn or failed registration files to CeleryConfig * fix: update logo handling in send_moderator_email_task for favicon support --------- Co-authored-by: Longze Chen <cslzchen@gmail.com> Co-authored-by: Ostap Zherebetskyi <ozherebetskyi@exoft.net> Co-authored-by: Bohdan Odintsov <bodintsov@exoft.net> * Updated cut-off time and added comments for NR settings * Update changelog and bump version * resolve merge conflicts * respond to CR comments * fix tests * fix tests again --------- Co-authored-by: Longze Chen <cslzchen@gmail.com> Co-authored-by: Ostap Zherebetskyi <ozherebetskyi@exoft.net> Co-authored-by: Vlad0n20 <137097005+Vlad0n20@users.noreply.github.com> Co-authored-by: futa-ikeda <51409893+futa-ikeda@users.noreply.github.com> Co-authored-by: mkovalua <mkoval@exoft.net> Co-authored-by: abram axel booth <aaxelb@users.noreply.github.com> Co-authored-by: Fitz Elliott <fitz@cos.io> Co-authored-by: Andriy Sheredko <sheredko.andriy@gmail.com> Co-authored-by: Bohdan Odintsov <bodintsov@exoft.net>
1 parent 3cefffe commit 981ef4a

197 files changed

Lines changed: 4581 additions & 2854 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,38 @@
22

33
We follow the CalVer (https://calver.org/) versioning scheme: YY.MINOR.MICRO.
44

5+
26.5.0 (2026-03-13)
6+
===================
7+
8+
- Notification refactor post-release project (Post-NR)
9+
10+
26.4.1 (2026-03-01)
11+
===================
12+
13+
- Add script to update ROR funder names
14+
15+
26.4.0 (2026-02-26)
16+
===================
17+
18+
- Transition funder ids from CrossRef to ROR
19+
20+
26.3.0 (2026-02-24)
21+
===================
22+
23+
- FAIR Signposting
24+
25+
26.2.1 (2026-02-09)
26+
===================
27+
28+
- Permanently update two notification types
29+
- Link digest to types and fix/log incorrect usage
30+
- Update notifiction dedupe command
31+
32+
26.2.0
33+
======
34+
35+
- TODO: add date and log
36+
537
26.1.6 (2026-01-14)
638
===================
739

addons/base/views.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
DraftRegistration,
5252
Guid,
5353
FileVersionUserMetadata,
54-
FileVersion, NotificationType
54+
FileVersion, NotificationTypeEnum
5555
)
5656
from osf.metrics import PreprintView, PreprintDownload
5757
from osf.utils import permissions
@@ -575,14 +575,13 @@ def create_waterbutler_log(payload, **kwargs):
575575

576576
if payload.get('email') or payload.get('errors'):
577577
if payload.get('email'):
578-
notification_type = NotificationType.Type.USER_FILE_OPERATION_SUCCESS.instance
578+
notification_type = NotificationTypeEnum.USER_FILE_OPERATION_SUCCESS.instance
579579
if payload.get('errors'):
580-
notification_type = NotificationType.Type.USER_FILE_OPERATION_FAILED.instance
580+
notification_type = NotificationTypeEnum.USER_FILE_OPERATION_FAILED.instance
581581
notification_type.emit(
582582
user=user,
583583
subscribed_object=node,
584584
event_context={
585-
'user_fullname': user.fullname,
586585
'action': payload['action'],
587586
'source_node': source_node._id,
588587
'source_node_title': source_node.title,
@@ -1035,9 +1034,12 @@ def persistent_file_download(auth, **kwargs):
10351034

10361035
query_params = request.args.to_dict()
10371036

1038-
return redirect(
1039-
file.generate_waterbutler_url(**query_params),
1040-
code=http_status.HTTP_302_FOUND
1037+
return make_response(
1038+
'', http_status.HTTP_302_FOUND, {
1039+
'Location': file.generate_waterbutler_url(**query_params),
1040+
'Link': f'<{settings.DOMAIN}metadata/{id_or_guid}/?format=linkset> ; rel="linkset" ; type="application/linkset",'
1041+
f' <{settings.DOMAIN}metadata/{id_or_guid}/?format=linkset-json"> ; rel="linkset-json" ; type="application/linkset+json"',
1042+
}
10411043
)
10421044

10431045

addons/boa/tasks.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from addons.boa.boa_error_code import BoaErrorCode
1515
from framework import sentry
1616
from framework.celery_tasks import app as celery_app
17-
from osf.models import OSFUser, NotificationType
17+
from osf.models import OSFUser, NotificationTypeEnum
1818
from osf.utils.fields import ensure_str, ensure_bytes
1919
from website import settings as osf_settings
2020

@@ -183,18 +183,15 @@ async def submit_to_boa_async(host, username, password, user_guid, project_guid,
183183

184184
logger.info('Successfully uploaded query output to OSF.')
185185
logger.debug('Task ends <<<<<<<<')
186-
NotificationType.Type.ADDONS_BOA_JOB_COMPLETE.instance.emit(
186+
NotificationTypeEnum.ADDONS_BOA_JOB_COMPLETE.instance.emit(
187187
user=user,
188188
event_context={
189189
'user_fullname': user.fullname,
190-
'query_file_name': query_file_name,
191190
'query_file_full_path': file_full_path,
192191
'output_file_name': output_file_name,
193192
'job_id': boa_job.id,
194193
'project_url': project_url,
195194
'boa_job_list_url': boa_settings.BOA_JOB_LIST_URL,
196-
'boa_support_email': boa_settings.BOA_SUPPORT_EMAIL,
197-
'osf_support_email': osf_settings.OSF_SUPPORT_EMAIL,
198195
}
199196
)
200197
return BoaErrorCode.NO_ERROR
@@ -209,12 +206,11 @@ def handle_boa_error(message, code, username, fullname, project_url, query_file_
209206
sentry.log_message(message, skip_session=True)
210207
except Exception:
211208
pass
212-
NotificationType.Type.ADDONS_BOA_JOB_FAILURE.instance.emit(
209+
NotificationTypeEnum.ADDONS_BOA_JOB_FAILURE.instance.emit(
213210
destination_address=username,
214211
event_context={
215212
'user_fullname': fullname,
216213
'code': code,
217-
'query_file_name': query_file_name,
218214
'file_size': file_size,
219215
'message': message,
220216
'max_file_size': boa_settings.MAX_SUBMISSION_SIZE,

addons/boa/tests/test_tasks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from addons.boa import settings as boa_settings
1010
from addons.boa.boa_error_code import BoaErrorCode
1111
from addons.boa.tasks import submit_to_boa, submit_to_boa_async, handle_boa_error
12-
from osf.models import NotificationType
12+
from osf.models import NotificationTypeEnum
1313
from osf_tests.factories import AuthUserFactory, ProjectFactory
1414
from tests.base import OsfTestCase
1515
from tests.utils import capture_notifications
@@ -66,7 +66,7 @@ def test_handle_boa_error(self):
6666
job_id=self.job_id
6767
)
6868
assert len(notifications['emits']) == 1
69-
assert notifications['emits'][0]['type'] == NotificationType.Type.ADDONS_BOA_JOB_FAILURE
69+
assert notifications['emits'][0]['type'] == NotificationTypeEnum.ADDONS_BOA_JOB_FAILURE
7070
mock_sentry_log_message.assert_called_with(self.error_message, skip_session=True)
7171
mock_logger_error.assert_called_with(self.error_message)
7272
assert return_value == BoaErrorCode.UNKNOWN

addons/osfstorage/tests/test_models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from framework.auth import Auth
1111
from addons.osfstorage.models import OsfStorageFile, OsfStorageFileNode, OsfStorageFolder
12-
from osf.models import BaseFileNode, NotificationType
12+
from osf.models import BaseFileNode, NotificationTypeEnum
1313
from osf.exceptions import ValidationError
1414
from osf.utils.permissions import WRITE, ADMIN
1515

@@ -750,7 +750,7 @@ def test_after_fork_copies_versions(self, node, node_settings, auth_obj):
750750
fork = node.fork_node(auth_obj)
751751

752752
assert len(notifications['emits']) == 1
753-
assert notifications['emits'][0]['type'] == NotificationType.Type.NODE_CONTRIBUTOR_ADDED_DEFAULT
753+
assert notifications['emits'][0]['type'] == NotificationTypeEnum.NODE_CONTRIBUTOR_ADDED_DEFAULT
754754
fork_node_settings = fork.get_addon('osfstorage')
755755
fork_node_settings.reload()
756756

addons/osfstorage/tests/test_views.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1539,11 +1539,19 @@ def test_download_file(self):
15391539
# Test download works with path
15401540
url = base_url.format(file._id)
15411541
redirect = self.app.get(url, auth=self.user.auth)
1542+
link_header = (f'<{settings.DOMAIN}metadata/{file._id}/?format=linkset> ; rel="linkset" ; type="application/linkset", '
1543+
f'<{settings.DOMAIN}metadata/{file._id}/?format=linkset-json"> ; rel="linkset-json" ; type="application/linkset+json"')
1544+
assert link_header == redirect.headers['Link']
15421545
assert redirect.status_code == 302
15431546

15441547
# Test download works with guid
1545-
url = base_url.format(file.get_guid(create=True)._id)
1548+
guid = file.get_guid(create=True)._id
1549+
url = base_url.format(guid)
15461550
redirect = self.app.get(url, auth=self.user.auth)
1551+
link_header = (
1552+
f'<{settings.DOMAIN}metadata/{guid}/?format=linkset> ; rel="linkset" ; type="application/linkset", '
1553+
f'<{settings.DOMAIN}metadata/{guid}/?format=linkset-json"> ; rel="linkset-json" ; type="application/linkset+json"')
1554+
assert link_header == redirect.headers['Link']
15471555
assert redirect.status_code == 302
15481556

15491557
# Test nonexistent file 404's

admin/management/urls.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,7 @@
1717
re_path(r'^ingest_cedar_metadata_templates', views.IngestCedarMetadataTemplates.as_view(), name='ingest_cedar_metadata_templates'),
1818
re_path(r'^bulk_resync', views.BulkResync.as_view(), name='bulk-resync'),
1919
re_path(r'^empty_metadata_dataarchive_registration_bulk_resync', views.EmptyMetadataDataarchiveRegistrationBulkResync.as_view(),
20-
name='empty-metadata-dataarchive-registration-bulk-resync')
20+
name='empty-metadata-dataarchive-registration-bulk-resync'),
21+
re_path(r'^sync_notification_templates', views.SyncNotificationTemplates.as_view(),
22+
name='sync_notification_templates')
2123
]

admin/management/views.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from osf.management.commands.monthly_reporters_go import monthly_reporters_go
1212
from osf.management.commands.fetch_cedar_metadata_templates import ingest_cedar_metadata_templates
1313
from osf.management.commands.sync_doi_metadata import sync_doi_metadata, sync_doi_empty_metadata_dataarchive_registrations
14+
from osf.management.commands.populate_notification_types import populate_notification_types
1415
from scripts.find_spammy_content import manage_spammy_content
1516
from django.urls import reverse
1617
from django.shortcuts import redirect
@@ -172,3 +173,11 @@ def post(self, request):
172173
})
173174
messages.success(request, 'Resyncing with DataCite! It will take some time.')
174175
return redirect(reverse('management:commands'))
176+
177+
178+
class SyncNotificationTemplates(ManagementCommandPermissionView):
179+
180+
def post(self, request):
181+
populate_notification_types()
182+
messages.success(request, 'Notification templates have been successfully synced.')
183+
return redirect(reverse('management:commands'))

admin/providers/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from django.shortcuts import redirect
22
from django.views.generic import TemplateView
33
from django.contrib import messages
4-
from osf.models import RegistrationProvider, OSFUser, CollectionProvider, NotificationType
4+
from osf.models import RegistrationProvider, OSFUser, CollectionProvider, NotificationTypeEnum
55
from website.settings import DOMAIN
66

77

@@ -63,7 +63,7 @@ def post(self, request, *args, **kwargs):
6363

6464
context['provider_url'] = f'{provider.domain or DOMAIN}{provider_type_word}/{(provider._id if not provider.domain else '').strip('/')}'
6565
messages.success(request, f'The following {target_type} was successfully added: {target_user.fullname} ({target_user.username})')
66-
notification_type = NotificationType.Type.PROVIDER_MODERATOR_ADDED
66+
notification_type = NotificationTypeEnum.PROVIDER_MODERATOR_ADDED
6767
notification_type.instance.emit(
6868
user=target_user,
6969
event_context=context,

admin/templates/management/commands.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,19 @@ <h4><u>Resync empty metadata dataarchive registrations with DataCite</u></h4>
152152
</nav>
153153
</form>
154154
</section>
155+
<section>
156+
<h4><u>Sync Notification Templates</u></h4>
157+
<p>
158+
Use this management command to sync notification templates. Warning: existing templates modifications via django admin will be overridden if they haven't been updated in code. In addition, templates are cached for 2 hours so changes won't be effective immediately.
159+
</p>
160+
<form method="post"
161+
action="{% url 'management:sync_notification_templates'%}">
162+
{% csrf_token %}
163+
<nav>
164+
<input class="btn btn-success" type="submit" value="Run" />
165+
</nav>
166+
</form>
167+
</section>
155168
</div>
156169
</section>
157170
{% endblock %}

0 commit comments

Comments
 (0)