""" This file contains models used for permissions """ import logging logger = logging.getLogger(__name__) from .common import NamedCommonPK, AbstractChoice from django.db.models import ManyToManyField from enum import Enum from rest_framework.permissions import DjangoModelPermissions from django.contrib.auth.models import AbstractUser from django.contrib.postgres.fields import JSONField class TMSSUser(AbstractUser): """ A custom user model that allows for additional information on the user like project roles. """ # todo: The project roles field feels very free-form at the moment. # Maybe this can be modeled better somehow, with references to the ProjectRole table? # Otherwise, we should probably come up with a schema to makes sure things are consistent. # Also, I'd suggest to simply map project name to a list of roles instead of the structure that is used here. project_roles = JSONField(null=True, blank=True, help_text='A list of structures that contain a project name and project role') # e.g. [{'project': 'high', 'role': 'PI'}, {'project': 'high', 'role': 'Friend of Project'}] # # Project Permissions # class ProjectRole(AbstractChoice): """Defines the model and predefined list of possible project roles a user can have. The items in the Choices class below are automagically populated into the database via a data migration.""" class Choices(Enum): PI = "pi" CO_I = "co_i" CONTACT_AUTHOR = "contact" SHARED_SUPPORT = 'shared_support' SHARED_SUPPORT_PRIMARY = 'shared_support_primary' FRIEND_OF_PROJECT = 'friend_of_project' FRIEND_OF_PROJECT_PRIMARY = 'friend_of_project_primary' class ProjectPermission(NamedCommonPK): GET = ManyToManyField('ProjectRole', related_name='can_GET', blank=True) PUT = ManyToManyField('ProjectRole', related_name='can_PUT', blank=True) POST = ManyToManyField('ProjectRole', related_name='can_POST', blank=True) PATCH = ManyToManyField('ProjectRole', related_name='can_PATCH', blank=True) DELETE = ManyToManyField('ProjectRole', related_name='can_DELETE', blank=True) # todo: move to viewsets / merge with TMSSDjangoModelPermissions class class TMSSBasePermissions(DjangoModelPermissions): # This enforces permissions as "deny any" by default. view_permissions = ['%(app_label)s.view_%(model_name)s'] perms_map = { 'GET': view_permissions, 'OPTIONS': view_permissions, 'HEAD': view_permissions, 'POST': DjangoModelPermissions.perms_map['POST'], 'PUT': DjangoModelPermissions.perms_map['PUT'], 'PATCH': DjangoModelPermissions.perms_map['PATCH'], 'DELETE': DjangoModelPermissions.perms_map['DELETE'], }