Files
Tablequizwiki/content/models.py
Holger Sielaff 5b1c2ce0c9 ...
2024-09-21 12:33:00 +02:00

218 lines
7.0 KiB
Python

import csv
from datetime import datetime
import json
import os
from colorfield.fields import ColorField
from django.contrib.auth.models import User
from django.db import models
from django.forms.models import model_to_dict
from django.utils.safestring import mark_safe
from filer.fields.file import FilerFileField
from lib.core.db.models.base import SharedPermissionBase
from lib.core.db.models.mixins import DateAware, AuthorAware, DescriptionAware, NameAware, PublishedAware
from tablequizwiki.settings import BASE_DIR
class MediaFile(NameAware, DateAware, AuthorAware, DescriptionAware):
# https://django-filer.readthedocs.io/en/latest/extending_filer.html
# https://pypi.org/project/django-thumbnails/
file = FilerFileField(on_delete=models.RESTRICT, related_name='media_file')
def __str__(self):
return self.name
def __repr__(self):
return self.file.name
class Link(NameAware, DateAware, AuthorAware, DescriptionAware):
url = models.URLField(unique=True, db_index=True)
def __str__(self):
return self.url
def __repr__(self):
return self.url
class Level(NameAware, DateAware, AuthorAware, DescriptionAware):
value = models.IntegerField(unique=True, db_index=True)
color = ColorField(default='#F90F90')
def __str__(self):
return f'{self.value} - {self.name}'
def __repr__(self):
return f'{self.value}'
class Label(NameAware, DateAware, AuthorAware, DescriptionAware):
color = ColorField(default='#666666')
def __str__(self):
return self.name
def __repr__(self):
return self.name
class SharedQuestion(SharedPermissionBase):
class Meta:
abstract = False
class SubmittedQuestion(DateAware):
name = models.CharField(max_length=500, unique=True)
buzzword = models.CharField(max_length=25, null=True, blank=True)
question = models.TextField()
awnser = models.TextField()
level = models.ForeignKey(Level, on_delete=models.SET_NULL, null=True, blank=True)
labels = models.ManyToManyField(Label, blank=True)
medias = models.ManyToManyField(MediaFile, blank=True)
links = models.ManyToManyField(Link, blank=True)
shares = models.ManyToManyField(SharedQuestion, blank=True)
release = models.BooleanField(default=False)
released = models.BooleanField(default=False)
released_at = models.DateTimeField(null=True,blank=True)
def __str__(self):
return f"{self.name} (#{self.id})"
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=SubmittedQuestion)
def release_submitted(sender, instance: SubmittedQuestion, **kwargs):
if instance.release:
n = Question.objects.create(
name=instance.name,
buzzword=instance.buzzword,
question=instance.question,
awnser=instance.awnser,
is_published=True,
)
try:
n.labels.set(instance.labels.all())
n.level_id = instance.level_id
n.save()
except:
n.delete()
raise
instance.released = True
instance.release = False
instance.released_at = datetime.now()
instance.save()
class Question(DateAware, AuthorAware, PublishedAware, DescriptionAware):
name = models.CharField(max_length=500, unique=True, db_index=True)
buzzword = models.CharField(max_length=25, null=True, blank=True)
question = models.TextField(db_index=True)
awnser = models.TextField(db_index=True)
level = models.ForeignKey(Level, on_delete=models.SET_NULL, null=True)
labels = models.ManyToManyField(Label, blank=True)
medias = models.ManyToManyField(MediaFile, blank=True)
links = models.ManyToManyField(Link, blank=True)
shares = models.ManyToManyField(SharedQuestion, blank=True)
def __str__(self):
return self.name
def __repr__(self):
return self.name
@staticmethod
def searchdomain(term, from_quiz=False):
return \
models.Q(name__icontains=term) \
| models.Q(question__icontains=term) \
| models.Q(awnser__icontains=term) \
| models.Q(buzzword__icontains=term) \
| models.Q(labels__name__icontains=term)
@staticmethod
def get_by_tearchterm(term, queryset=None):
if not queryset:
queryset = Question.objects
return queryset.filter(Question.searchdomain(term)).annotate(cnt=models.Count('id'))
def to_view(self, for_players: bool = False):
ret = {}
ret['name'] = '{}{}'.format(self.name, f'({self.buzzword})' if self.buzzword else '')
ret['question'] = self.question
if self.description:
ret['question'] += ' \n\n------------------------------\n\n' + self.description
ret['awnser'] = self.awnser
ret['level'] = self.level.value
ret['medias'] = []
ret['links'] = []
for media in self.medias.all():
ret.setdefault('medias', []).append(os.path.basename(media.file.path))
for link in self.links.all():
ret.setdefault('links', []).append(link.url)
ret['question'] = mark_safe(ret['question'].replace('\n', '\n<br />'))
return ret
@property
def zippath(self):
return str(BASE_DIR) + f'/filestore/zip/question.{self.id}.zip'
@property
def pdfpath(self):
return str(BASE_DIR) + f'/filestore/pdf/question.{self.id}.pdf'
@property
def csvpath(self):
return str(BASE_DIR) + f'/filestore/csv/question.{self.id}.csv'
def default_json(o):
if isinstance(o, (MediaFile,)):
return str(o)
return json.dumps(model_to_dict(o))
def to_csv(self, fh=None):
if fh:
cf = fh
else:
cf = open(self.csvpath, 'w')
items = self.to_view()
keys = items.keys()
dw = csv.DictWriter(cf, fieldnames=list(keys))
dw.writeheader()
dw.writerow(items)
if not fh:
cf.close()
return cf if fh else self.csvpath
class QuestionVersion(DateAware, AuthorAware):
question = models.ForeignKey(Question, on_delete=models.SET_NULL, null=True)
data = models.JSONField()
def __str__(self):
return f'{self.question} - {self.created_at}' if self.question else f'{self.data.name} - {self.created_at}'
@receiver(models.signals.post_save, sender=Question)
def versionize_question(sender, instance: Question, *args, **kwargs):
data = model_to_dict(instance)
# to be able to json.dumps in model
data['medias'] = [{'id': m.id, '__str__': str(m)} for m in data['medias']]
data['links'] = [{'id': m.id, '__str__': str(m)} for m in data['links']]
data['labels'] = [{'id': m.id, '__str__': str(m)} for m in data['labels']]
data['shares'] = list(map(str, data['shares']))
QuestionVersion.objects.create(
question=instance,
data=data,
# https://django-crum.readthedocs.io/en/latest/
# from crum import get_current_user
# author=get_current_user(),
)