Source code for memopolis.models

import os
import uuid

from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils.text import slugify
from django.utils.timezone import now
from django.conf import settings
from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _

from taggit.managers import TaggableManager

from jsoneditor.fields.django3_jsonfield import JSONField

from solo.models import SingletonModel


[docs] class SiteConfiguration(SingletonModel): home_map = models.ForeignKey("Map", on_delete=models.CASCADE, null=True, blank=True) default_organization_language = models.CharField(max_length=5, default="en") tos_url = models.URLField(default="#") privacy_url = models.URLField(default="#") def __str__(self): return "Site Configuration" class Meta: verbose_name = "Site Configuration"
[docs] class User(AbstractUser):
[docs] def get_default_user_json(): return { 'map': None, 'color': None }
language = models.CharField(max_length=10, choices=settings.LANGUAGES, default=settings.LANGUAGE_CODE) organization = models.ForeignKey("Organization", on_delete=models.CASCADE, related_name="users", null=True, blank=True) json = models.JSONField(default=get_default_user_json) invite_token = models.UUIDField(default=uuid.uuid4, null=True, blank=True) active_team = models.ForeignKey("Team", on_delete=models.CASCADE, null=True, blank=True) def __str__(self): return self.username + ((" (%s)" % str(self.organization)) if self.organization else "")
[docs] def get_default_language(): return SiteConfiguration.get_solo().default_organization_language
[docs] class Organization(models.Model): name = models.CharField(max_length=100) language = models.CharField(max_length=2, default=get_default_language) admins = models.ManyToManyField(User, related_name="admin_organizations", blank=True) def __str__(self): return self.name
[docs] class Team(models.Model): name = models.CharField(max_length=100) organization = models.ForeignKey(Organization, related_name="teams", on_delete=models.CASCADE) admins = models.ManyToManyField(User, related_name="admin_teams", blank=True) users = models.ManyToManyField(User, related_name="teams", blank=True) def __str__(self): return self.name
[docs] def content_filepath(instance, filename): return "content/{}/{}/{}/{}".format(slugify(instance.user.organization), slugify(instance.team), instance.user.pk, filename)
valid_file_extensions = { "Image": ['.png', '.jpg', '.jpeg', ], "Audio": ['.wav', '.mp3', '.flac', '.aac', ], "Video": ['.mp4', '.webm'] }
[docs] def validate_is_acceptable_content_file(file): ext = os.path.splitext(file.name)[1] for c, type in valid_file_extensions.items(): if ext.lower() in type: return raise ValidationError('Unacceptable file extension.')
# valid_mime_types = [ # 'application/jpeg', 'application/png', # 'audio/wav', 'audio/mp3', 'audio/flac', 'audio/aac', # 'video/mp4', 'video/webm', # ] # file_mime_type = magic.from_buffer(file.read(1024), mime=True) # print(file_mime_type) # if file_mime_type not in valid_mime_types: # raise ValidationError('Unsupported file type: ' + file_mime_type)
[docs] class Content(models.Model):
[docs] class ContentType(models.TextChoices): IMAGE = 'IM', _('Image') AUDIO = 'AU', _('Audio') VIDEO = 'VI', _('Video')
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="files") team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name="files", null=True, blank=True) image = models.FileField(null=True, blank=True, upload_to=content_filepath, validators=(validate_is_acceptable_content_file,)) type = models.CharField(max_length=2, choices=ContentType.choices, default=ContentType.IMAGE) created_at = models.DateTimeField(auto_now_add=True) special = models.CharField(max_length=100, default="", null=True, blank=True) tags = TaggableManager() class Meta: verbose_name_plural = "Content"
[docs] def content_type(self): return self.get_type_display().lower()
[docs] def cleaned_name(self): filename = os.path.basename(self.image.file.name) for t in ["object", "item", "character", "portal", "background"]: if t + "_" in filename: return filename.replace(".png", "").replace(t + "_", "").replace("_", " ")
[docs] def filename(self): return os.path.basename(self.image.name)
[docs] def save(self, *args, **kwargs): if self.image: ext = os.path.splitext(self.image.name)[1].lower() for c, type in valid_file_extensions.items(): if ext in type: if c == "Image": self.type = self.ContentType.IMAGE if c == "Audio": self.type = self.ContentType.AUDIO if c == "Video": self.type = self.ContentType.VIDEO break super(Content, self).save(*args, **kwargs)
def __str__(self): return os.path.basename(self.image.file.name)
[docs] class Map(models.Model):
[docs] def get_default_map_json(): return { 'tilemap': [], 'objects': {} }
name = models.CharField(max_length=100) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="maps", null=True, blank=True) parent_map = models.ForeignKey("Map", on_delete=models.CASCADE, null=True, blank=True, ) quest = models.ForeignKey("Quest", on_delete=models.CASCADE, null=True, blank=True, related_name="maps") json = models.JSONField(default=get_default_map_json) mark_for_deletion = models.BooleanField(default=False) def __str__(self): return self.name
[docs] class WorldObject(models.Model):
[docs] def get_default_worldobject_json(): return {}
uuid = models.UUIDField(default=uuid.uuid4) map = models.ForeignKey(Map, on_delete=models.CASCADE, related_name="users", null=True, blank=True) json = JSONField(default=get_default_worldobject_json)
[docs] class Quest(models.Model):
[docs] def get_default_quest_json(): return { "variables": [], "language": "en", "text": "" }
name = models.CharField(max_length=100) organization = models.ForeignKey(Organization, on_delete=models.CASCADE, related_name="quests") team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name="quests", null=True, blank=True) json = models.JSONField(default=get_default_quest_json) def __str__(self): return self.name
[docs] class FeedbackTicket(models.Model):
[docs] class Emotion(models.TextChoices): HAPPY = 'HA', 'Happy' OK = 'OK', 'OK' UNHAPPY = 'UN', 'Unhappy' ANGRY = "AN", 'Angry'
[docs] class Category(models.TextChoices): GENERAL = 'GE', 'General' BUG = 'BU', 'Bug' FEEDBACK = 'FE', 'Feedback' SUGGESTION = "SU", 'Suggestion' HELP = "HE", 'Help'
text = models.TextField(null=True, blank=True) emotion = models.CharField(max_length=2, choices=Emotion.choices) category = models.CharField(max_length=2, choices=Category.choices) timestamp = models.DateTimeField(default=now) git_hash = models.CharField(max_length=48) uuid = models.UUIDField(default=uuid.uuid4, editable=False) screenshot = models.ImageField(null=True, upload_to='%Y/%m/%d') os = models.CharField(max_length=100) session_data = JSONField(null=True, blank=True) user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
from . import signals