Skip to content

Commit 4bf1849

Browse files
committed
Merge remote-tracking branch 'upstream/develop' into add-new-notifications-data-model
Conflicts will be fixed in next commit: * api/users/views.py * api_tests/users/views/test_user_settings.py
2 parents 4afeeea + 48e37bc commit 4bf1849

File tree

63 files changed

+805
-110
lines changed

Some content is hidden

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

63 files changed

+805
-110
lines changed

CHANGELOG

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

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

5+
25.16.0 (2025-09-17)
6+
====================
7+
8+
- Misc. fixes for Angular migration
9+
510
25.15.2 (2025-09-10)
611
====================
712

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: 4 additions & 12 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
@@ -48,7 +47,8 @@
4847
AddSystemTagForm
4948
)
5049
from admin.base.views import GuidView
51-
from website.settings import DOMAIN, OSF_SUPPORT_EMAIL
50+
from api.users.services import send_password_reset_email
51+
from website.settings import DOMAIN
5252
from django.urls import reverse_lazy
5353

5454

@@ -532,17 +532,9 @@ class ResetPasswordView(UserMixin, View):
532532
def post(self, request, *args, **kwargs):
533533
email = self.request.POST['emails']
534534
user = get_user(email)
535-
url = furl(DOMAIN)
536535

537-
user.verification_key_v2 = generate_verification_key(verification_type='password_admin')
538-
user.save()
539-
url.add(path=f'resetpassword/{user._id}/{user.verification_key_v2["token"]}')
540-
send_mail(
541-
subject='Reset OSF Password',
542-
message=f'Follow this link to reset your password: {url.url}\n Note: this link will expire in 12 hours',
543-
from_email=OSF_SUPPORT_EMAIL,
544-
recipient_list=[email]
545-
)
536+
send_password_reset_email(user, email, institutional=False, verification_type='password_admin')
537+
546538
update_admin_log(
547539
user_id=self.request.user.id,
548540
object_id=user.pk,

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/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
"""

api/custom_metadata/serializers.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import rest_framework.serializers as ser
33

44
from framework.auth.core import Auth
5+
from osf.metadata.definitions.datacite import DATACITE_RESOURCE_TYPES_GENERAL
56
from api.base.serializers import (
67
IDField,
78
JSONAPISerializer,
@@ -80,10 +81,10 @@ class CustomItemMetadataSerializer(JSONAPISerializer):
8081
allow_blank=True,
8182
max_length=REASONABLE_MAX_LENGTH,
8283
)
83-
resource_type_general = ser.CharField(
84+
resource_type_general = ser.ChoiceField(
8485
required=False,
8586
allow_blank=True,
86-
max_length=REASONABLE_MAX_LENGTH,
87+
choices=sorted(DATACITE_RESOURCE_TYPES_GENERAL),
8788
)
8889
funders = FundingInfoSerializer(
8990
many=True,

api/institutions/views.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@ def get_default_search(self):
592592
InstitutionalUserReport.search()
593593
.filter('term', report_yearmonth=str(_yearmonth))
594594
.filter('term', institution_id=self.get_institution()._id)
595+
.exclude('term', user_name='Deleted user')
595596
)
596597

597598

0 commit comments

Comments
 (0)