from django.conf import settings from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.db import models from django.db.models import Manager from api.models import Project from roles.models import Role class MemberManager(Manager): def can_update(self, project: int, member_id: int, new_role: str) -> bool: """The project needs at least 1 admin. Args: project: The project id. member_id: The member id. new_role: The new role name. Returns: Whether the mapping can be updated or not. """ queryset = self.filter( project=project, role__name=settings.ROLE_PROJECT_ADMIN ) if queryset.count() > 1: return True else: admin = queryset.first() # we can change the role except for the only admin. return admin.id != member_id or new_role == settings.ROLE_PROJECT_ADMIN def has_role(self, project_id: int, user: User, role_name: str): return self.filter(project=project_id, user=user, role__name=role_name).exists() class Member(models.Model): user = models.ForeignKey( to=User, on_delete=models.CASCADE, related_name='role_mappings' ) project = models.ForeignKey( to=Project, on_delete=models.CASCADE, related_name='role_mappings' ) role = models.ForeignKey( to=Role, on_delete=models.CASCADE ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) objects = MemberManager() def clean(self): members = self.objects.exclude(id=self.id) if members.filter(user=self.user, project=self.project).exists(): message = 'This user is already assigned to a role in this project.' raise ValidationError(message) class Meta: unique_together = ('user', 'project')