Browse Source

Deny member to delete label types when allow_member_to_create_label_type is True

pull/2207/head
Hironsan 1 year ago
parent
commit
c05733dba2
4 changed files with 39 additions and 38 deletions
  1. 7
      backend/api/tests/utils.py
  2. 55
      backend/label_types/tests/test_views.py
  3. 2
      backend/label_types/views.py
  4. 13
      frontend/services/application/project/projectApplicationService.ts

7
backend/api/tests/utils.py

@ -29,8 +29,11 @@ class CRUDMixin(APITestCase):
self.assertEqual(response.status_code, expected)
return response
def assert_delete(self, user=None, expected=status.HTTP_403_FORBIDDEN):
def assert_delete(self, user=None, expected=status.HTTP_403_FORBIDDEN, data=None):
if user:
self.client.force_login(user)
response = self.client.delete(self.url)
if data is None:
data = {}
response = self.client.delete(self.url, data=data)
self.assertEqual(response.status_code, expected)

55
backend/label_types/tests/test_views.py

@ -15,16 +15,18 @@ DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
class TestLabelList(CRUDMixin):
@classmethod
def setUpTestData(cls):
cls.non_member = make_user()
cls.project_a = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION)
cls.label = make_label(cls.project_a.item)
cls.url = reverse(viewname="category_types", args=[cls.project_a.item.id])
def setUp(self):
self.non_member = make_user()
self.project_a = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION)
self.label = make_label(self.project_a.item)
self.url = reverse(viewname="category_types", args=[self.project_a.item.id])
# Ensure that the API does not return the labels of the other project.
cls.project_b = make_project(task="Any", users=["admin"], roles=[settings.ROLE_PROJECT_ADMIN])
make_label(cls.project_b.item)
self.project_b = make_project(task="Any", users=["admin"], roles=[settings.ROLE_PROJECT_ADMIN])
make_label(self.project_b.item)
# for label creation
self.data = {"text": "example"}
def test_returns_labels_to_project_member(self):
for member in self.project_a.members:
@ -38,32 +40,11 @@ class TestLabelList(CRUDMixin):
def test_does_not_return_labels_to_unauthenticated_user(self):
self.assert_fetch(expected=status.HTTP_403_FORBIDDEN)
class TestLabelSearch(CRUDMixin):
def setUp(self):
self.project = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION)
make_label(self.project.item)
self.url = reverse(viewname="category_types", args=[self.project.item.id])
def test_search(self):
for member in self.project.members:
response = self.assert_fetch(member, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
class TestLabelCreate(CRUDMixin):
@classmethod
def setUpTestData(cls):
cls.non_member = make_user(ProjectType.DOCUMENT_CLASSIFICATION)
cls.project = prepare_project()
cls.url = reverse(viewname="category_types", args=[cls.project.item.id])
cls.data = {"text": "example"}
def test_allows_admin_to_create_label(self):
self.assert_create(self.project.admin, status.HTTP_201_CREATED)
self.assert_create(self.project_a.admin, status.HTTP_201_CREATED)
def test_denies_project_staff_to_create_label(self):
for member in self.project.staffs:
for member in self.project_a.staffs:
self.assert_create(member, status.HTTP_403_FORBIDDEN)
def test_denies_non_project_member_to_create_label(self):
@ -72,11 +53,19 @@ class TestLabelCreate(CRUDMixin):
def test_denies_unauthenticated_user_to_create_label(self):
self.assert_create(expected=status.HTTP_403_FORBIDDEN)
def test_allows_admin_to_bulk_delete_label(self):
self.assert_delete(self.project_a.admin, status.HTTP_204_NO_CONTENT, data={"ids": [self.label.id]})
def test_denies_project_staff_to_bulk_delete_label(self):
member = self.project_a.staffs[0]
self.assert_delete(member, status.HTTP_403_FORBIDDEN, data={"ids": [self.label.id]})
class TestAllowMemberToCreateLabelType(CRUDMixin):
@classmethod
def setUpTestData(cls):
cls.project = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION, allow_member_to_create_label_type=True)
cls.label = make_label(cls.project.item)
cls.url = reverse(viewname="category_types", args=[cls.project.item.id])
cls.data = {"text": "example"}
@ -85,6 +74,10 @@ class TestAllowMemberToCreateLabelType(CRUDMixin):
self.data["text"] = member.username
self.assert_create(member, status.HTTP_201_CREATED)
def test_denies_project_staff_to_bulk_delete_label(self):
member = self.project.staffs[0]
self.assert_delete(member, status.HTTP_403_FORBIDDEN, data={"ids": [self.label.id]})
class TestLabelDetailAPI(CRUDMixin):
@classmethod

2
backend/label_types/views.py

@ -44,7 +44,7 @@ class LabelList(generics.ListCreateAPIView):
def get_permissions(self):
project = get_object_or_404(Project, pk=self.kwargs["project_id"])
if project.allow_member_to_create_label_type:
if project.allow_member_to_create_label_type and self.request.method == "POST":
self.permission_classes = [IsAuthenticated & IsProjectMember]
else:
self.permission_classes = [IsAuthenticated & (IsProjectAdmin | IsProjectStaffAndReadOnly)]

13
frontend/services/application/project/projectApplicationService.ts

@ -15,6 +15,7 @@ type ProjectFields = {
allowOverlappingSpans: boolean
enableGraphemeMode: boolean
useRelation: boolean
allowMemberToCreateLabelType: boolean
}
export interface SearchQueryData {
@ -52,7 +53,8 @@ export class ProjectApplicationService {
enableGraphemeMode,
useRelation,
tags,
guideline = ''
guideline = '',
allowMemberToCreateLabelType = false
}: ProjectFields): Promise<Project> {
const project = Project.create(
0,
@ -66,7 +68,8 @@ export class ProjectApplicationService {
allowOverlappingSpans,
enableGraphemeMode,
useRelation,
tags.map((tag) => TagItem.create(tag))
tags.map((tag) => TagItem.create(tag)),
allowMemberToCreateLabelType
)
try {
return await this.repository.create(project)
@ -87,7 +90,8 @@ export class ProjectApplicationService {
allowOverlappingSpans,
enableGraphemeMode,
useRelation,
guideline = ''
guideline = '',
allowMemberToCreateLabelType
}: Omit<ProjectFields, 'tags'>
): Promise<void> {
const project = Project.create(
@ -102,7 +106,8 @@ export class ProjectApplicationService {
allowOverlappingSpans,
enableGraphemeMode,
useRelation,
[]
[],
allowMemberToCreateLabelType
)
try {

Loading…
Cancel
Save