from django.contrib.auth.models import User from django.db import models from django.utils.translation import gettext_lazy as _ from django_cryptography.fields import encrypt from lib.utils.general import get_random_string from lib.models.base import MetaDataModel def get_random_key(): return get_random_string(8) def get_random_secret(): return get_random_string(32) class TokenManager(models.Manager): """ Custom queryset which will prefetch related user table data when requesting a token from the database as the user is mostly needed every time the token is requested. """ def get_queryset(self): return super(TokenManager, self).get_queryset().select_related('user') class Token(MetaDataModel): """Token model that holds all the tokens that are used for the API authentication. A new token is generated every time when a new user is created. So there is no need for manual token creating. This is done through a signal :attr:`~apps.api.signals.create_user_token` Attributes ---------- user : :class:`~django.contrib.auth.models.User` The user to which this token belongs too key : str The key value that is used for token lookups secret : str The secret that is used for encrypting/signing the API messages last_access : datetime The date and time when the token is last used (logged in) """ class Meta: verbose_name = _('token') verbose_name_plural = _('tokens') user = models.OneToOneField(User, on_delete=models.CASCADE, help_text=_('Select the user for this token')) key = models.CharField(_('Key') , unique=True, default=get_random_key, max_length=16, help_text=_('The key for this token. This is used for Hawk verification.')) secret = encrypt(models.CharField(_('Secret') ,max_length=64, default=get_random_secret, help_text=_('The secret for this token. This is used for Hawk signing.'))) last_access = models.DateTimeField(_('Last access'),auto_now_add=True, help_text=_('The date and time when this token is last used.')) # Custom manager that will retrieve the related user table as well. objects = TokenManager() def is_supertoken(self): """Boolean check if the token is belonging to a user with super user rights. Then this token is a super token. Returns: bool: Returns true when the token belongs to a super user. """ # TODO: Is it allowed to be a super user and researcher? Could give conflict of interests. With the API token you can read other researchers data... return self.user.is_superuser == True is_supertoken.boolean = True is_supertoken.short_description = _('Super token') def __str__(self): """ Print the full name of the researcher based on the first and last name fields of the User model. """ return '{} ({})'.format(self.key,self.user.get_full_name())