You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
5.1 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. import abc
  2. from django.conf import settings
  3. from django.contrib.auth.models import User
  4. from django.core.exceptions import ValidationError
  5. from django.db import models
  6. from django.db.models import Manager
  7. from polymorphic.models import PolymorphicModel
  8. from roles.models import Role
  9. DOCUMENT_CLASSIFICATION = "DocumentClassification"
  10. SEQUENCE_LABELING = "SequenceLabeling"
  11. SEQ2SEQ = "Seq2seq"
  12. SPEECH2TEXT = "Speech2text"
  13. IMAGE_CLASSIFICATION = "ImageClassification"
  14. BOUNDING_BOX = "BoundingBox"
  15. SEGMENTATION = "Segmentation"
  16. IMAGE_CAPTIONING = "ImageCaptioning"
  17. INTENT_DETECTION_AND_SLOT_FILLING = "IntentDetectionAndSlotFilling"
  18. PROJECT_CHOICES = (
  19. (DOCUMENT_CLASSIFICATION, "document classification"),
  20. (SEQUENCE_LABELING, "sequence labeling"),
  21. (SEQ2SEQ, "sequence to sequence"),
  22. (INTENT_DETECTION_AND_SLOT_FILLING, "intent detection and slot filling"),
  23. (SPEECH2TEXT, "speech to text"),
  24. (IMAGE_CLASSIFICATION, "image classification"),
  25. (BOUNDING_BOX, "bounding box"),
  26. (SEGMENTATION, "segmentation"),
  27. (IMAGE_CAPTIONING, "image captioning"),
  28. )
  29. class Project(PolymorphicModel):
  30. name = models.CharField(max_length=100)
  31. description = models.TextField(default="")
  32. guideline = models.TextField(default="", blank=True)
  33. created_at = models.DateTimeField(auto_now_add=True)
  34. updated_at = models.DateTimeField(auto_now=True)
  35. created_by = models.ForeignKey(
  36. User,
  37. on_delete=models.SET_NULL,
  38. null=True,
  39. )
  40. project_type = models.CharField(max_length=30, choices=PROJECT_CHOICES)
  41. random_order = models.BooleanField(default=False)
  42. collaborative_annotation = models.BooleanField(default=False)
  43. single_class_classification = models.BooleanField(default=False)
  44. def add_admin(self):
  45. admin_role = Role.objects.get(name=settings.ROLE_PROJECT_ADMIN)
  46. Member.objects.create(
  47. project=self,
  48. user=self.created_by,
  49. role=admin_role,
  50. )
  51. @property
  52. @abc.abstractmethod
  53. def is_text_project(self) -> bool:
  54. return False
  55. def __str__(self):
  56. return self.name
  57. class TextClassificationProject(Project):
  58. @property
  59. def is_text_project(self) -> bool:
  60. return True
  61. class SequenceLabelingProject(Project):
  62. allow_overlapping = models.BooleanField(default=False)
  63. grapheme_mode = models.BooleanField(default=False)
  64. use_relation = models.BooleanField(default=False)
  65. @property
  66. def is_text_project(self) -> bool:
  67. return True
  68. class Seq2seqProject(Project):
  69. @property
  70. def is_text_project(self) -> bool:
  71. return True
  72. class IntentDetectionAndSlotFillingProject(Project):
  73. @property
  74. def is_text_project(self) -> bool:
  75. return True
  76. class Speech2textProject(Project):
  77. @property
  78. def is_text_project(self) -> bool:
  79. return False
  80. class ImageClassificationProject(Project):
  81. @property
  82. def is_text_project(self) -> bool:
  83. return False
  84. class BoundingBoxProject(Project):
  85. @property
  86. def is_text_project(self) -> bool:
  87. return False
  88. class SegmentationProject(Project):
  89. @property
  90. def is_text_project(self) -> bool:
  91. return False
  92. class ImageCaptioningProject(Project):
  93. @property
  94. def is_text_project(self) -> bool:
  95. return False
  96. class Tag(models.Model):
  97. text = models.TextField()
  98. project = models.ForeignKey(to=Project, on_delete=models.CASCADE, related_name="tags")
  99. def __str__(self):
  100. return self.text
  101. class MemberManager(Manager):
  102. def can_update(self, project: int, member_id: int, new_role: str) -> bool:
  103. """The project needs at least 1 admin.
  104. Args:
  105. project: The project id.
  106. member_id: The member id.
  107. new_role: The new role name.
  108. Returns:
  109. Whether the mapping can be updated or not.
  110. """
  111. queryset = self.filter(project=project, role__name=settings.ROLE_PROJECT_ADMIN)
  112. if queryset.count() > 1:
  113. return True
  114. else:
  115. admin = queryset.first()
  116. # we can change the role except for the only admin.
  117. return admin.id != member_id or new_role == settings.ROLE_PROJECT_ADMIN
  118. def has_role(self, project_id: int, user: User, role_name: str):
  119. return self.filter(project=project_id, user=user, role__name=role_name).exists()
  120. class Member(models.Model):
  121. user = models.ForeignKey(to=User, on_delete=models.CASCADE, related_name="role_mappings")
  122. project = models.ForeignKey(to=Project, on_delete=models.CASCADE, related_name="role_mappings")
  123. role = models.ForeignKey(to=Role, on_delete=models.CASCADE)
  124. created_at = models.DateTimeField(auto_now_add=True)
  125. updated_at = models.DateTimeField(auto_now=True)
  126. objects = MemberManager()
  127. def clean(self):
  128. members = self.__class__.objects.exclude(id=self.id)
  129. if members.filter(user=self.user, project=self.project).exists():
  130. message = "This user is already assigned to a role in this project."
  131. raise ValidationError(message)
  132. @property
  133. def username(self):
  134. return self.user.username
  135. class Meta:
  136. unique_together = ("user", "project")