Skip to content
Snippets Groups Projects
models.py 3.98 KiB
Newer Older
  • Learn to ignore specific revisions
  • Eliot Berriot's avatar
    Eliot Berriot committed
    from __future__ import absolute_import, unicode_literals
    
    from django.conf import settings
    
    from django.contrib.auth.models import AbstractUser
    
    Eliot Berriot's avatar
    Eliot Berriot committed
    from django.urls import reverse
    
    from django.utils.encoding import python_2_unicode_compatible
    from django.utils.translation import ugettext_lazy as _
    
    
    Eliot Berriot's avatar
    Eliot Berriot committed
    from funkwhale_api.common import fields, preferences
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        return binascii.b2a_hex(os.urandom(15)).decode("utf-8")
    
    PERMISSIONS_CONFIGURATION = {
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        "federation": {
            "label": "Manage library federation",
            "help_text": "Follow other instances, accept/deny library follow requests...",
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        "library": {
            "label": "Manage library",
            "help_text": "Manage library, delete files, tracks, artists, albums...",
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        "settings": {"label": "Manage instance-level settings", "help_text": ""},
        "upload": {"label": "Upload new content to the library", "help_text": ""},
    
    }
    
    PERMISSIONS = sorted(PERMISSIONS_CONFIGURATION.keys())
    
    @python_2_unicode_compatible
    class User(AbstractUser):
    
        # First Name and Last Name do not cover name patterns
        # around the globe.
        name = models.CharField(_("Name of User"), blank=True, max_length=255)
    
    
        # updated on logout or password change, to invalidate JWT
        secret_key = models.UUIDField(default=uuid.uuid4, null=True)
    
        privacy_level = fields.get_privacy_field()
    
    
        # Unfortunately, Subsonic API assumes a MD5/password authentication
        # scheme, which is weak in terms of security, and not achievable
        # anyway since django use stronger schemes for storing passwords.
        # Users that want to use the subsonic API from external client
        # should set this token and use it as their password in such clients
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        subsonic_api_token = models.CharField(blank=True, null=True, max_length=255)
    
        permission_federation = models.BooleanField(
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            PERMISSIONS_CONFIGURATION["federation"]["label"],
            help_text=PERMISSIONS_CONFIGURATION["federation"]["help_text"],
            default=False,
        )
    
        permission_library = models.BooleanField(
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            PERMISSIONS_CONFIGURATION["library"]["label"],
            help_text=PERMISSIONS_CONFIGURATION["library"]["help_text"],
            default=False,
        )
    
        permission_settings = models.BooleanField(
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            PERMISSIONS_CONFIGURATION["settings"]["label"],
            help_text=PERMISSIONS_CONFIGURATION["settings"]["help_text"],
            default=False,
        )
    
        permission_upload = models.BooleanField(
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            PERMISSIONS_CONFIGURATION["upload"]["label"],
            help_text=PERMISSIONS_CONFIGURATION["upload"]["help_text"],
            default=False,
        )
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            defaults = preferences.get("users__default_permissions")
    
    Eliot Berriot's avatar
    Eliot Berriot committed
                    self.is_superuser
                    or getattr(self, "permission_{}".format(p))
                    or p in defaults
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        def has_permissions(self, *perms, operator="and"):
            if operator not in ["and", "or"]:
                raise ValueError("Invalid operator {}".format(operator))
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            checker = all if operator == "and" else any
    
            return checker([permissions[p] for p in perms])
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            return reverse("users:detail", kwargs={"username": self.username})
    
    
        def update_secret_key(self):
            self.secret_key = uuid.uuid4()
            return self.secret_key
    
    
        def update_subsonic_api_token(self):
    
            self.subsonic_api_token = get_token()
    
            return self.subsonic_api_token
    
    
        def set_password(self, raw_password):
            super().set_password(raw_password)
            self.update_secret_key()
    
            if self.subsonic_api_token:
                self.update_subsonic_api_token()
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            return settings.FUNKWHALE_URL + "/@{}".format(self.username)