Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion backend/api/models/annotation/annotation_file_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from backend.aplose.models import User
from .annotation_task import AnnotationTask
from ..common.__abstract_permission import AbstractPermission
from ..data import Spectrogram


Expand Down Expand Up @@ -63,7 +64,7 @@ def filter_editable_by(self, user: User, **kwargs):
)


class AnnotationFileRange(models.Model):
class AnnotationFileRange(AbstractPermission, models.Model):
"""Gives a range of files to annotate by an annotator within a campaign"""

objects = models.Manager.from_queryset(AnnotationFileRangeQuerySet)()
Expand Down
6 changes: 6 additions & 0 deletions backend/api/models/annotation/annotation_phase.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from backend.api.models.common.__abstract_archivable import AbstractArchivable
from backend.aplose.models import User
from .annotation_file_range import AnnotationFileRange


class AnnotationPhaseQuerySet(ExtendedQuerySet):
Expand Down Expand Up @@ -99,3 +100,8 @@ def has_change_permission(self, user: "User") -> bool:
or user.id == self.created_by_id
or user.id == self.annotation_campaign.owner_id
)

def has_file_range_change_permission(self, user: "User") -> bool:
return self.has_change_permission(
user
) and AnnotationFileRange.has_global_change_permission(user)
10 changes: 7 additions & 3 deletions backend/api/models/common/__abstract_permission.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ class AbstractPermission(models.Model):
class Meta:
abstract = True

def has_change_permission(self, user: "User") -> bool:
@classmethod
def has_global_change_permission(cls, user: "User") -> bool:
edit_permissions = Permission.objects.filter(
codename__startswith="change",
content_type__app_label=self._meta.app_label,
content_type__model=self._meta.model_name,
content_type__app_label=cls._meta.app_label,
content_type__model=cls._meta.model_name,
).first()
return user.has_perm(edit_permissions)

def has_change_permission(self, user: "User") -> bool:
return self.has_global_change_permission(user=user)
10 changes: 10 additions & 0 deletions backend/api/schema/nodes/annotation_phase.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import graphene_django_optimizer
from django.db.models import Sum
from django_extension.schema.types import ExtendedNode
from graphql import GraphQLResolveInfo

from backend.api.models import AnnotationPhase, AnnotationTask
from backend.api.schema.enums import AnnotationPhaseType
Expand Down Expand Up @@ -78,3 +79,12 @@ def resolve_annotators(self: AnnotationPhase, info):
).distinct(),
info,
)

has_file_range_change_permission = graphene.Boolean(required=True)

@graphene_django_optimizer.resolver_hints()
def resolve_has_file_range_change_permission(
self: AnnotationPhase, info: GraphQLResolveInfo
):
# pylint: disable=not-callable
return self.has_file_range_change_permission(info.context.user)
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export const FileRangeActionBar: React.FC<{ isPending?: boolean }> = ({ isPendin
</Dialog.Root>
</div>

{ phase?.hasChangePermission && <Fragment>
{ phase?.hasFileRangeChangePermission && <Fragment>
{/* Manage annotators */ }
<Popover.Root>
<Popover.TriggerLink data-testid="manage"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ query getAnnotationPhase(
id
phase
hasChangePermission
hasFileRangeChangePermission
archived
hasAnnotations
tasksCount
Expand Down
6 changes: 5 additions & 1 deletion frontend/tests/utils/mock/phase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export const PHASE_QUERIES: {
userTasksCount,
archived: phase.archived,
hasAnnotations: phase.hasAnnotations,
hasChangePermission: true
hasChangePermission: true,
hasFileRangeChangePermission: true,
},
},
managerVerification: {
Expand All @@ -41,6 +42,7 @@ export const PHASE_QUERIES: {
archived: phase.archived,
hasAnnotations: phase.hasAnnotations,
hasChangePermission: true,
hasFileRangeChangePermission: true,
},
},
Annotation: {
Expand All @@ -54,6 +56,7 @@ export const PHASE_QUERIES: {
archived: phase.archived,
hasAnnotations: phase.hasAnnotations,
hasChangePermission: false,
hasFileRangeChangePermission: false,
},
},
Verification: {
Expand All @@ -67,6 +70,7 @@ export const PHASE_QUERIES: {
archived: phase.archived,
hasAnnotations: phase.hasAnnotations,
hasChangePermission: false,
hasFileRangeChangePermission: false,
},
},
},
Expand Down
24 changes: 12 additions & 12 deletions frontend/tests/utils/mock/types/phase.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { type AnnotationPhaseNode } from '../../../../src/api/types.gql-generated';

export type Phase =
Omit<AnnotationPhaseNode, 'hasChangePermission' | 'annotationComments' | 'annotationFileRanges' | 'createdBy' | 'annotationTasks' |
'annotations' | 'annotationCampaign' | 'endedBy' | 'annotationCampaignId' | 'phase' | 'isEditable' |
'isUserAllowedToManage' | 'tasksCount' | 'userTasksCount' | 'userCompletedTasksCount' | 'completedTasksCount' | 'annotators'
>
Omit<AnnotationPhaseNode, 'hasChangePermission' | 'hasFileRangeChangePermission' | 'annotationComments' | 'annotationFileRanges' | 'createdBy' | 'annotationTasks' |
'annotations' | 'annotationCampaign' | 'endedBy' | 'annotationCampaignId' | 'phase' | 'isEditable' |
'isUserAllowedToManage' | 'tasksCount' | 'userTasksCount' | 'userCompletedTasksCount' | 'completedTasksCount' | 'annotators'
>

export const phase: Phase = {
id: '1',
createdAt: new Date().toISOString(),
archived: false,
hasAnnotations: true,
id: '1',
createdAt: new Date().toISOString(),
archived: false,
hasAnnotations: true,
}
export const otherPhase: Phase = {
id: '2',
createdAt: new Date().toISOString(),
archived: false,
hasAnnotations: true,
id: '2',
createdAt: new Date().toISOString(),
archived: false,
hasAnnotations: true,
}
export const completedTasksCount = 50;
export const tasksCount = 100;
Expand Down
Loading