Skip to content

Commit

Permalink
make is_curator a boolean field to optimize
Browse files Browse the repository at this point in the history
  • Loading branch information
John Tordoff committed Jan 9, 2025
1 parent 4bcb1fa commit 8171f74
Show file tree
Hide file tree
Showing 9 changed files with 28 additions and 31 deletions.
2 changes: 1 addition & 1 deletion api/requests/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def has_permission(self, request, view):
except Institution.DoesNotExist:
raise exceptions.ValidationError({'institution': 'Institution is does not exist.'})

if get_user_auth(request).user.is_institutional_admin(institution):
if get_user_auth(request).user.is_institutional_admin_or_curator(institution):
return True
else:
raise exceptions.PermissionDenied({'institution': 'You do not have permission to perform this action for this institution.'})
Expand Down
2 changes: 1 addition & 1 deletion api/users/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,6 @@ def has_permission(self, request, view) -> bool:

message_type = request.data.get('message_type')
if message_type == MessageTypes.INSTITUTIONAL_REQUEST:
return user.is_institutional_admin(institution)
return user.is_institutional_admin_or_curator(institution)
else:
raise exceptions.ValidationError('Not valid message type.')
2 changes: 1 addition & 1 deletion api/users/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,7 @@ def create(self, validated_data: Dict[str, Any]) -> UserMessage:
'institution',
)

if not sender.is_institutional_admin(institution):
if not sender.is_institutional_admin_or_curator(institution):
raise Conflict({'sender': 'Only institutional administrators can create messages.'})

if not recipient.is_affiliated_with_institution(institution):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.13 on 2024-12-12 19:37
# Generated by Django 4.2.13 on 2025-01-09 18:05

from django.conf import settings
from django.db import migrations, models
Expand All @@ -14,6 +14,11 @@ class Migration(migrations.Migration):
]

operations = [
migrations.AddField(
model_name='contributor',
name='is_curator',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='noderequest',
name='requested_permissions',
Expand Down
19 changes: 3 additions & 16 deletions osf/models/contributor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from django.db import models, IntegrityError
from osf.utils.fields import NonNaiveDateTimeField
from osf.utils import permissions, workflows
from django.utils.functional import cached_property
from osf.utils import permissions


class AbstractBaseContributor(models.Model):
Expand Down Expand Up @@ -31,32 +30,20 @@ def permission(self):

class Contributor(AbstractBaseContributor):
node = models.ForeignKey('AbstractNode', on_delete=models.CASCADE)
is_curator = models.BooleanField(default=False)

@property
def _id(self):
return f'{self.node._id}-{self.user._id}'

@cached_property
def is_curator(self):
"""
Determine if the user is a curator on this node.
This avoids querying the database repeatedly by caching the result.
"""
from osf.models import NodeRequest
return NodeRequest.objects.filter(
target=self.node,
creator=self.user,
request_type=workflows.NodeRequestTypes.INSTITUTIONAL_REQUEST
).exists()

class Meta:
unique_together = ('user', 'node')
# Make contributors orderable
# NOTE: Adds an _order column
order_with_respect_to = 'node'

def save(self, *args, **kwargs):
if not self.user.is_institutional_admin():
if not self.user.is_institutional_admin_or_curator():
return super().save(*args, **kwargs)
elif self.visible:
raise IntegrityError('Curators cannot be made bibliographic contributors')
Expand Down
7 changes: 6 additions & 1 deletion osf/models/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -1327,7 +1327,7 @@ def _get_admin_contributors_query(self, users, require_active=True):
return qs

def add_contributor(self, contributor, permissions=None, visible=True,
send_email=None, auth=None, log=True, save=False):
send_email=None, auth=None, log=True, save=False, make_curator=False):
"""Add a contributor to the project.
:param User contributor: The contributor to be added
Expand Down Expand Up @@ -1393,6 +1393,11 @@ def add_contributor(self, contributor, permissions=None, visible=True,
if getattr(self, 'get_identifier_value', None) and self.get_identifier_value('doi'):
request, user_id = get_request_and_user_id()
self.update_or_enqueue_on_resource_updated(user_id, first_save=False, saved_fields=['contributors'])

if make_curator:
contributor_obj.is_curator = True
contributor_obj.save()

return contrib_to_add

def add_contributors(self, contributors, auth=None, log=True, save=False):
Expand Down
11 changes: 4 additions & 7 deletions osf/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -644,19 +644,16 @@ def osf_groups(self):
OSFGroup = apps.get_model('osf.OSFGroup')
return get_objects_for_user(self, 'member_group', OSFGroup, with_superuser=False)

def is_institutional_admin(self, institution=None, node=None):
def is_institutional_admin_or_curator(self, institution=None, node=None):
"""
Checks if user is admin of any or of a specific institution, or and curator on a specific node.
"""
if node:
contrib = Contributor.objects.filter(
return Contributor.objects.filter(
node=node,
user=self,
)
if contrib:
return contrib.get().is_curator
else:
return False
is_curator=True,
).exists()

if not institution:
return self.groups.filter(
Expand Down
7 changes: 5 additions & 2 deletions osf/utils/machines.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from osf.exceptions import InvalidTransitionError
from osf.models.preprintlog import PreprintLog
from osf.models.action import ReviewAction, NodeRequestAction, PreprintRequestAction

from osf.utils import permissions
from osf.utils.workflows import (
DefaultStates,
Expand All @@ -20,6 +19,7 @@
APPROVAL_TRANSITIONS,
CollectionSubmissionStates,
COLLECTION_SUBMISSION_TRANSITIONS,
NodeRequestTypes
)
from website.mails import mails
from website.reviews import signals as reviews_signals
Expand Down Expand Up @@ -202,13 +202,16 @@ def save_changes(self, ev):
if ev.event.name == DefaultTriggers.ACCEPT.value:
if not self.machineable.target.is_contributor(self.machineable.creator):
contributor_permissions = ev.kwargs.get('permissions', permissions.READ)
make_curator = True if self.machineable.request_type == NodeRequestTypes.INSTITUTIONAL_REQUEST.value else False
try:
self.machineable.target.add_contributor(
self.machineable.creator,
auth=Auth(ev.kwargs['user']),
permissions=contributor_permissions,
visible=ev.kwargs.get('visible', True),
send_email=f'{self.machineable.request_type}_request')
send_email=f'{self.machineable.request_type}_request',
make_curator=make_curator,
)
except IntegrityError as e:
if 'Curators cannot be made bibliographic contributors' in str(e):
raise Conflict(str(e)) from e
Expand Down
2 changes: 1 addition & 1 deletion website/profile/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def serialize_user(user, node=None, admin=False, full=False, is_profile=False, i
'surname': user.family_name,
'fullname': fullname,
'shortname': fullname if len(fullname) < 50 else fullname[:23] + '...' + fullname[-23:],
'is_curator': user.is_institutional_admin(node=node),
'is_curator': user.is_institutional_admin_or_curator(node=node),
'profile_image_url': user.profile_image_url(size=settings.PROFILE_IMAGE_MEDIUM),
'active': user.is_active,
}
Expand Down

0 comments on commit 8171f74

Please sign in to comment.