Source code for groups.models

"""Database models for the groups app."""

from enum import Enum, EnumMeta
from pathlib import PurePath

from django.db import models
from django.shortcuts import reverse

from MangAdventure.models import (
    DiscordNameField, DiscordURLField, RedditField, TwitterField
)
from MangAdventure.storage import CDNStorage
from MangAdventure.validators import FileSizeValidator


def _logo_uploader(obj: 'Group', name: str) -> str:
    name = f'logo.{name.split(".")[-1]}'
    return str(obj.get_directory() / name)


class _ChoiceMeta(EnumMeta):
    def __new__(cls, name, bases, attrs):
        klass = super().__new__(cls, name, (Enum,) + bases, attrs)
        klass.do_not_call_in_templates = True
        return klass

    def __iter__(cls):
        return ((e.name, e.value) for e in super().__iter__())


[docs]class Group(models.Model): """A model representing a group.""" #: The group's ID. id = models.SmallIntegerField(primary_key=True, auto_created=True) #: The group's name. name = models.CharField(max_length=100, help_text="The group's name.") #: The group's website. website = models.URLField(blank=True, help_text="The group's website.") #: The group's description. description = models.TextField( blank=True, help_text='A description for the group.' ) #: The group's e-mail address. email = models.EmailField( blank=True, help_text="The group's E-mail address." ) #: The Discord server URL of the group. discord = DiscordURLField(blank=True, help_text="The group's Discord link.") #: The Twitter username of the group. twitter = TwitterField( blank=True, help_text="The group's Twitter username." ) #: The group's IRC. irc = models.CharField( max_length=63, blank=True, help_text="The group's IRC." ) #: The Reddit username or subreddit name of the group. reddit = RedditField( max_length=24, blank=True, help_text="The group's Reddit username or " "subreddit. (Include /u/ or /r/)" ) #: The group's logo. logo = models.ImageField( blank=True, storage=CDNStorage((150, 150)), upload_to=_logo_uploader, validators=(FileSizeValidator(2),), help_text="Upload the group's logo. Its size must not exceed 2 MBs.", )
[docs] def get_absolute_url(self) -> str: """ Get the absolute URL of the object. :return: The URL of :func:`groups.views.group`. """ return reverse('groups:group', args=(self.id,))
[docs] def get_directory(self) -> PurePath: """ Get the storage directory of the object. :return: A path relative to :const:`~MangAdventure.settings.MEDIA_ROOT`. """ return PurePath('groups', str(self.id))
@property def _increment(self) -> int: try: num = Group.objects.only('id').last().id + 1 except (Group.DoesNotExist, AttributeError): num = 1 return num
[docs] def save(self, *args, **kwargs): """Save the current instance.""" if not self.id: self.id = self._increment super(Group, self).save(*args, **kwargs)
[docs] def __str__(self) -> str: """ Return a string representing the object. :return: The name of the group. """ return self.name
[docs]class Member(models.Model): """A model representing a member.""" #: The name of the member. name = models.CharField(max_length=100, help_text="The member's name.") #: The member's Twitter username. twitter = TwitterField( blank=True, help_text="The member's Twitter username." ) #: The member's Discord username and discriminator. discord = DiscordNameField(blank=True, help_text=( "The member's Discord username and discriminator." )) #: The member's IRC username. irc = models.CharField( max_length=63, blank=True, help_text="The member's IRC username." ) #: The member's Reddit username. reddit = RedditField( blank=True, help_text="The member's Reddit username." ) #: The groups of this member. groups = models.ManyToManyField(Group, 'members', through='Role')
[docs] def __str__(self) -> str: """ Return a string representing the object. :return: The name of the member. """ return self.name
[docs]class Role(models.Model): """A model representing a role."""
[docs] class Choices(metaclass=_ChoiceMeta): """The possible role choices.""" LD = 'Leader' TL = 'Translator' PR = 'Proofreader' CL = 'Cleaner' RD = 'Redrawer' TS = 'Typesetter' RP = 'Raw Provider' QC = 'Quality Checker'
#: The member this role belongs to. member = models.ForeignKey( Member, on_delete=models.CASCADE, related_name='roles' ) #: The group this role belongs to. group = models.ForeignKey( Group, on_delete=models.CASCADE, related_name='roles' ) #: The value of the role. role = models.CharField(blank=False, max_length=2, choices=Choices) class Meta: verbose_name = 'Role' unique_together = ('member', 'role', 'group')
[docs] def __str__(self) -> str: """ Return a string representing the object. :return: The name and group of the role. """ return f'{self.get_role_display()} ({self.group})'
__all__ = ['Group', 'Member', 'Role']