diff --git a/backend/label_types/tests/test_views.py b/backend/label_types/tests/test_views.py index 00198e9c..ab1d36aa 100644 --- a/backend/label_types/tests/test_views.py +++ b/backend/label_types/tests/test_views.py @@ -73,6 +73,19 @@ class TestLabelCreate(CRUDMixin): self.assert_create(expected=status.HTTP_403_FORBIDDEN) +class TestAllowMemberToCreateLabelType(CRUDMixin): + @classmethod + def setUpTestData(cls): + cls.project = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION, allow_member_to_create_label_type=True) + cls.url = reverse(viewname="category_types", args=[cls.project.item.id]) + cls.data = {"text": "example"} + + def test_allows_member_to_create_label_type(self): + for member in self.project.members: + self.data["text"] = member.username + self.assert_create(member, status.HTTP_201_CREATED) + + class TestLabelDetailAPI(CRUDMixin): @classmethod def setUpTestData(cls): diff --git a/backend/label_types/views.py b/backend/label_types/views.py index 875cbc89..4293a1d4 100644 --- a/backend/label_types/views.py +++ b/backend/label_types/views.py @@ -2,6 +2,7 @@ import json import re from django.db import IntegrityError, transaction +from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend from rest_framework import generics, status from rest_framework.exceptions import ParseError @@ -18,7 +19,12 @@ from .serializers import ( RelationTypeSerializer, SpanTypeSerializer, ) -from projects.permissions import IsProjectAdmin, IsProjectStaffAndReadOnly +from projects.models import Project +from projects.permissions import ( + IsProjectAdmin, + IsProjectMember, + IsProjectStaffAndReadOnly, +) def camel_to_snake(name): @@ -35,7 +41,14 @@ class LabelList(generics.ListCreateAPIView): filter_backends = [DjangoFilterBackend] serializer_class = LabelSerializer pagination_class = None - permission_classes = [IsAuthenticated & (IsProjectAdmin | IsProjectStaffAndReadOnly)] + + def get_permissions(self): + project = get_object_or_404(Project, pk=self.kwargs["project_id"]) + if project.allow_member_to_create_label_type: + self.permission_classes = [IsAuthenticated & IsProjectMember] + else: + self.permission_classes = [IsAuthenticated & (IsProjectAdmin | IsProjectStaffAndReadOnly)] + return super().get_permissions() def get_queryset(self): return self.model.objects.filter(project=self.kwargs["project_id"]) diff --git a/backend/projects/migrations/0008_project_allow_member_to_create_label_type_and_more.py b/backend/projects/migrations/0008_project_allow_member_to_create_label_type_and_more.py new file mode 100644 index 00000000..af41b307 --- /dev/null +++ b/backend/projects/migrations/0008_project_allow_member_to_create_label_type_and_more.py @@ -0,0 +1,36 @@ +# Generated by Django 4.1.7 on 2023-06-07 04:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("projects", "0007_imagecaptioningproject_alter_project_project_type"), + ] + + operations = [ + migrations.AddField( + model_name="project", + name="allow_member_to_create_label_type", + field=models.BooleanField(default=False), + ), + migrations.AlterField( + model_name="project", + name="project_type", + field=models.CharField( + choices=[ + ("DocumentClassification", "Document Classification"), + ("SequenceLabeling", "Sequence Labeling"), + ("Seq2seq", "Seq2Seq"), + ("IntentDetectionAndSlotFilling", "Intent Detection And Slot Filling"), + ("Speech2text", "Speech2Text"), + ("ImageClassification", "Image Classification"), + ("BoundingBox", "Bounding Box"), + ("Segmentation", "Segmentation"), + ("ImageCaptioning", "Image Captioning"), + ], + max_length=30, + ), + ), + ] diff --git a/backend/projects/models.py b/backend/projects/models.py index ed5d4218..c53a1059 100644 --- a/backend/projects/models.py +++ b/backend/projects/models.py @@ -38,6 +38,7 @@ class Project(PolymorphicModel): random_order = models.BooleanField(default=False) collaborative_annotation = models.BooleanField(default=False) single_class_classification = models.BooleanField(default=False) + allow_member_to_create_label_type = models.BooleanField(default=False) def add_admin(self): admin_role = Role.objects.get(name=settings.ROLE_PROJECT_ADMIN) diff --git a/backend/projects/serializers.py b/backend/projects/serializers.py index 3f8b09bc..861842d2 100644 --- a/backend/projects/serializers.py +++ b/backend/projects/serializers.py @@ -71,6 +71,7 @@ class ProjectSerializer(serializers.ModelSerializer): "author", "collaborative_annotation", "single_class_classification", + "allow_member_to_create_label_type", "is_text_project", "tags", ]