Source code for applications.models

from uuid import uuid4

from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.conf import settings
from django.db import models
from django.urls import reverse
from django.utils.text import slugify

from rest_framework.authtoken.models import Token

from core.models import BaseAppDataModel, SoftDeletionManager
from provenance.models import ProvAbleModel, ProvApplicationModel


[docs]class Application(ProvAbleModel, ProvApplicationModel, BaseAppDataModel): """ Manage the state of and access to an external application. An external application may be e.g.: * A data / metadata visualisation tool * A data / metadata analysis pipeline """ objects = SoftDeletionManager() #: Address at which the API may be accessed url = models.URLField(blank=True, null=False) #: User who has responsibility for this application owner = models.ForeignKey(settings.AUTH_USER_MODEL, limit_choices_to={ 'groups__name': 'Application providers' }, on_delete=models.PROTECT, related_name='applications', editable=False, blank=False, null=False) #: Proxy user which this application will act as proxy_user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, related_name='application_proxy', editable=False, blank=True, null=True) #: Group of users who have read / use access to this data source / application users_group = models.OneToOneField(Group, on_delete=models.SET_NULL, related_name='+', editable=False, blank=True, null=True) #: Groups of users who have requested access to this data source / application users_group_requested = models.OneToOneField(Group, on_delete=models.SET_NULL, related_name='+', editable=False, blank=True, null=True) #: Do users require explicit permission to use this application? access_control = models.BooleanField(default=False, blank=False, null=False) #: Has this object been soft deleted? is_deleted = models.BooleanField(default=False, editable=False, blank=False, null=False)
[docs] def delete(self, using=None, keep_parents=False): """ Soft delete this object. """ self.is_deleted = True self.save()
@property def _access_group_name(self): return str(type(self)) + ' ' + self.name + ' Users'
[docs] def save(self, **kwargs): # Create access control groups if they do not exist # Make sure their names match self.name if they do exist if self.access_control: if self.users_group: # Update existing group name self.users_group.name = self._access_group_name self.users_group.save() else: self.users_group, created = Group.objects.get_or_create( name=self._access_group_name ) if self.users_group_requested: # Update existing group name self.users_group_requested.name = self._access_group_name + ' Requested' self.users_group_requested.save() else: self.users_group_requested, created = Group.objects.get_or_create( name=self._access_group_name + ' Requested' ) if not self.proxy_user: self.proxy_user = self._get_proxy_user() super().save(**kwargs)
[docs] def has_view_permission(self, user: settings.AUTH_USER_MODEL) -> bool: """ Does a user have permission to use this application? :param user: User to check :return: User has permission? """ if not self.access_control: return True if self.owner == user: return True return self.users_group.user_set.filter(pk=user.pk).exists()
def _get_proxy_user(self) -> settings.AUTH_USER_MODEL: """ Create a new proxy user for this application or return the existing one. :return: Instance of user model """ if self.proxy_user: return self.proxy_user # Add random UUID to username to allow multiple applications with the same name proxy_username = 'application-proxy-' + slugify(self.name) + str(uuid4()) proxy_user = get_user_model().objects.create_user(proxy_username) # Create an API access token for the proxy user proxy_user.create_auth_token() return proxy_user
[docs] def get_absolute_url(self): return reverse('applications:application.detail', kwargs={'pk': self.pk})