Skip to content

Commit a166eb1

Browse files
committed
Merge branch 'develop' into upstream/azure-blob-storage
2 parents b566ea8 + a920785 commit a166eb1

File tree

99 files changed

+1311
-334
lines changed

Some content is hidden

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

99 files changed

+1311
-334
lines changed

CHANGELOG

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

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

5+
25.17.6 (2025-10-11)
6+
====================
7+
8+
- Fix sitemap for preprint files download
9+
10+
25.17.5 (2025-10-11)
11+
====================
12+
13+
- Fix sitemap for nodes and registrations overview
14+
- Make is_public and bookmarks field filterable for collections
15+
16+
25.17.4 (2025-10-10)
17+
====================
18+
19+
- Misc. fixes for Angular migration
20+
21+
25.17.3 (2025-10-10)
22+
====================
23+
24+
- Misc. fixes for Angular migration
25+
26+
25.17.2 (2025-10-09)
27+
====================
28+
29+
- Misc. fixes for Angular migration
30+
31+
25.17.1 (2025-10-09)
32+
====================
33+
34+
- Misc. fixes for Angular migration
35+
36+
25.17.0 (2025-10-03)
37+
====================
38+
39+
- Misc. fixes for Angular migration
40+
41+
25.16.0 (2025-09-17)
42+
====================
43+
44+
- Misc. fixes for Angular migration
45+
46+
25.15.2 (2025-09-10)
47+
====================
48+
49+
- Handle duplicate SSO emails during institution SSO
50+
51+
25.15.1 (2025-09-04)
52+
====================
53+
54+
- Notification refactor project phase 1 migration fix
55+
556
25.15.0 (2025-08-29)
657
====================
758

admin/brands/forms.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class Meta:
1111
widgets = {
1212
'primary_color': TextInput(attrs={'class': 'colorpicker'}),
1313
'secondary_color': TextInput(attrs={'class': 'colorpicker'}),
14+
'background_color': TextInput(attrs={'class': 'colorpicker'}),
1415
'topnav_logo_image': TextInput(attrs={'placeholder': 'Logo should be max height of 40px', 'size': 200}),
1516
'hero_logo_image': TextInput(
1617
attrs={'placeholder': 'Logo image should be max height of 100px', 'size': 200}

admin/brands/views.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ class BrandChangeForm(PermissionRequiredMixin, UpdateView):
6060
raise_exception = True
6161
model = Brand
6262
form_class = BrandForm
63+
template_name = 'brands/detail.html'
64+
65+
def get_context_data(self, **kwargs):
66+
context = super().get_context_data(**kwargs)
67+
context['change_form'] = context.get('form')
68+
brand_obj = self.get_object()
69+
context['brand'] = model_to_dict(brand_obj)
70+
return context
6371

6472
def get_object(self, queryset=None):
6573
brand_id = self.kwargs.get('brand_id')
@@ -81,13 +89,17 @@ def post(self, request, *args, **kwargs):
8189
view = BrandChangeForm.as_view()
8290
primary_color = request.POST.get('primary_color')
8391
secondary_color = request.POST.get('secondary_color')
92+
background_color = request.POST.get('background_color')
8493

8594
if not is_a11y(primary_color):
8695
messages.warning(request, """The selected primary color is not a11y compliant.
8796
For more information, visit https://color.a11y.com/""")
8897
if not is_a11y(secondary_color):
8998
messages.warning(request, """The selected secondary color is not a11y compliant.
9099
For more information, visit https://color.a11y.com/""")
100+
if background_color and not is_a11y(background_color):
101+
messages.warning(request, """The selected background color is not a11y compliant.
102+
For more information, visit https://color.a11y.com/""")
91103
return view(request, *args, **kwargs)
92104

93105

@@ -109,11 +121,15 @@ def get_context_data(self, *args, **kwargs):
109121
def post(self, request, *args, **kwargs):
110122
primary_color = request.POST.get('primary_color')
111123
secondary_color = request.POST.get('secondary_color')
124+
background_color = request.POST.get('background_color')
112125

113126
if not is_a11y(primary_color):
114127
messages.warning(request, """The selected primary color is not a11y compliant.
115128
For more information, visit https://color.a11y.com/""")
116129
if not is_a11y(secondary_color):
117130
messages.warning(request, """The selected secondary color is not a11y compliant.
118131
For more information, visit https://color.a11y.com/""")
132+
if background_color and not is_a11y(background_color):
133+
messages.warning(request, """The selected background color is not a11y compliant.
134+
For more information, visit https://color.a11y.com/""")
119135
return super().post(request, *args, **kwargs)

admin/static/js/banners/banners.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ $(document).ready(function() {
2626
}
2727
});
2828

29-
$(".colorpicker").colorpicker();
29+
$(".colorpicker").colorpicker({
30+
format: 'hex',
31+
useAlpha: false
32+
});
3033

3134
});

admin/static/js/brands/brands.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ require('bootstrap-colorpicker/dist/css/bootstrap-colorpicker.min.css');
55

66
$(document).ready(function() {
77

8-
$(".colorpicker").colorpicker();
8+
$(".colorpicker").colorpicker({
9+
format: 'hex',
10+
useAlpha: false
11+
});
912

1013
});

admin/users/views.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from django.contrib.auth.mixins import PermissionRequiredMixin
1313
from django.urls import reverse
1414
from django.core.exceptions import PermissionDenied
15-
from django.core.mail import send_mail
1615
from django.shortcuts import redirect
1716
from django.core.paginator import Paginator
1817
from django.core.exceptions import ValidationError
@@ -47,7 +46,8 @@
4746
AddSystemTagForm
4847
)
4948
from admin.base.views import GuidView
50-
from website.settings import DOMAIN, OSF_SUPPORT_EMAIL
49+
from api.users.services import send_password_reset_email
50+
from website.settings import DOMAIN
5151
from django.urls import reverse_lazy
5252

5353

@@ -503,7 +503,7 @@ def get_claim_links(self, user):
503503

504504
for guid, value in user.unclaimed_records.items():
505505
obj = Guid.load(guid)
506-
url = f'{DOMAIN}user/{user._id}/{guid}/claim/?token={value["token"]}'
506+
url = f'{DOMAIN}legacy/user/{user._id}/{guid}/claim/?token={value["token"]}'
507507
links.append(f'Claim URL for {obj.content_type.model} {obj._id}: {url}')
508508

509509
return links or ['User currently has no active unclaimed records for any nodes.']
@@ -523,17 +523,9 @@ class ResetPasswordView(UserMixin, View):
523523
def post(self, request, *args, **kwargs):
524524
email = self.request.POST['emails']
525525
user = get_user(email)
526-
url = furl(DOMAIN)
527526

528-
user.verification_key_v2 = generate_verification_key(verification_type='password_admin')
529-
user.save()
530-
url.add(path=f'resetpassword/{user._id}/{user.verification_key_v2["token"]}')
531-
send_mail(
532-
subject='Reset OSF Password',
533-
message=f'Follow this link to reset your password: {url.url}\n Note: this link will expire in 12 hours',
534-
from_email=OSF_SUPPORT_EMAIL,
535-
recipient_list=[email]
536-
)
527+
send_password_reset_email(user, email, institutional=False, verification_type='password_admin')
528+
537529
update_admin_log(
538530
user_id=self.request.user.id,
539531
object_id=user.pk,

api/base/serializers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,13 @@ def to_representation(self, obj):
11831183
if hasattr(obj, 'get_absolute_info_url'):
11841184
ret['info'] = self._extend_url_with_vol_key(obj.get_absolute_info_url())
11851185

1186+
request = self.context['request']
1187+
referer = request.headers.get('Referer', '')
1188+
if 'html' in ret and 'legacy' in referer:
1189+
parsed_html_url = urlparse(ret['html'])
1190+
legacy_url = urlparse(referer)
1191+
ret['html'] = parsed_html_url._replace(scheme=legacy_url.scheme, netloc=legacy_url.netloc).geturl()
1192+
11861193
return ret
11871194

11881195

api/brands/serializers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class BrandSerializer(JSONAPISerializer):
1515

1616
primary_color = ser.CharField(read_only=True, max_length=7)
1717
secondary_color = ser.CharField(read_only=True, max_length=7)
18+
background_color = ser.CharField(read_only=True, allow_null=True, max_length=7)
1819

1920
links = LinksField({
2021
'self': 'get_absolute_url',

api/collections/serializers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class CollectionSerializer(JSONAPISerializer):
2929
'title',
3030
'date_created',
3131
'date_modified',
32+
'is_public',
33+
'bookmarks',
3234
])
3335

3436
id = IDField(source='_id', read_only=True)

api/collections/views.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
CollectedRegistrationsRelationshipSerializer,
3737
)
3838
from api.nodes.serializers import NodeSerializer
39+
from api.nodes.filters import NodesFilterMixin
3940
from api.preprints.serializers import PreprintSerializer
4041
from api.subjects.views import SubjectRelationshipBaseView, BaseResourceSubjectsList
4142
from api.registrations.serializers import RegistrationSerializer
@@ -506,7 +507,7 @@ def get_resource(self, check_object_permissions=True):
506507
return self.get_collection_submission(check_object_permissions)
507508

508509

509-
class LinkedNodesList(JSONAPIBaseView, generics.ListAPIView, CollectionMixin, NodeOptimizationMixin):
510+
class LinkedNodesList(JSONAPIBaseView, generics.ListAPIView, CollectionMixin, NodeOptimizationMixin, NodesFilterMixin):
510511
"""List of nodes linked to this node. *Read-only*.
511512
512513
Linked nodes are the project/component nodes pointed to by node links. This view will probably replace node_links in the near future.
@@ -569,12 +570,15 @@ class LinkedNodesList(JSONAPIBaseView, generics.ListAPIView, CollectionMixin, No
569570

570571
ordering = ('-modified',)
571572

572-
def get_queryset(self):
573+
def get_default_queryset(self):
573574
auth = get_user_auth(self.request)
574575
node_ids = self.get_collection().active_guids.filter(content_type_id=ContentType.objects.get_for_model(Node).id).values_list('object_id', flat=True)
575576
nodes = Node.objects.filter(id__in=node_ids, is_deleted=False).can_view(user=auth.user, private_link=auth.private_link).order_by('-modified')
576577
return self.optimize_node_queryset(nodes)
577578

579+
def get_queryset(self):
580+
return self.get_queryset_from_request()
581+
578582
# overrides APIView
579583
def get_parser_context(self, http_request):
580584
"""

0 commit comments

Comments
 (0)