2024-07-13 14:38:42 +02:00
|
|
|
import csv
|
2024-09-10 12:32:53 +02:00
|
|
|
from datetime import datetime
|
2024-07-03 21:41:03 +02:00
|
|
|
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
|
|
|
|
|
|
2024-07-12 17:22:17 +02:00
|
|
|
from lib.core.db.models.base import SharedPermissionBase
|
2024-07-13 10:19:49 +02:00
|
|
|
from lib.core.db.models.mixins import DateAware, AuthorAware, DescriptionAware, NameAware, PublishedAware
|
2024-07-13 14:38:42 +02:00
|
|
|
from tablequizwiki.settings import BASE_DIR
|
2024-07-03 21:41:03 +02:00
|
|
|
|
|
|
|
|
|
2024-07-12 17:22:17 +02:00
|
|
|
class MediaFile(NameAware, DateAware, AuthorAware, DescriptionAware):
|
2024-07-03 21:41:03 +02:00
|
|
|
# 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
|
|
|
|
|
|
|
|
|
|
|
2024-07-12 17:22:17 +02:00
|
|
|
class Link(NameAware, DateAware, AuthorAware, DescriptionAware):
|
2024-07-03 21:41:03 +02:00
|
|
|
url = models.URLField(unique=True, db_index=True)
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.url
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
return self.url
|
|
|
|
|
|
|
|
|
|
|
2024-07-12 17:22:17 +02:00
|
|
|
class Level(NameAware, DateAware, AuthorAware, DescriptionAware):
|
2024-07-03 21:41:03 +02:00
|
|
|
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}'
|
|
|
|
|
|
|
|
|
|
|
2024-07-12 17:22:17 +02:00
|
|
|
class Label(NameAware, DateAware, AuthorAware, DescriptionAware):
|
2024-07-03 21:41:03 +02:00
|
|
|
color = ColorField(default='#666666')
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
|
2024-07-12 17:22:17 +02:00
|
|
|
class SharedQuestion(SharedPermissionBase):
|
|
|
|
|
class Meta:
|
|
|
|
|
abstract = False
|
|
|
|
|
|
|
|
|
|
|
2024-09-10 12:32:53 +02:00
|
|
|
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,
|
|
|
|
|
)
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
|
|
2024-07-13 10:19:49 +02:00
|
|
|
class Question(DateAware, AuthorAware, PublishedAware, DescriptionAware):
|
2024-07-03 21:41:03 +02:00
|
|
|
name = models.CharField(max_length=500, unique=True, db_index=True)
|
|
|
|
|
buzzword = models.CharField(max_length=25, null=True, blank=True)
|
2024-09-10 12:32:53 +02:00
|
|
|
question = models.TextField(db_index=True)
|
2024-07-03 21:41:03 +02:00
|
|
|
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)
|
2024-07-12 17:22:17 +02:00
|
|
|
shares = models.ManyToManyField(SharedQuestion, blank=True)
|
2024-07-03 21:41:03 +02:00
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
2024-07-12 17:22:17 +02:00
|
|
|
@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
|
2024-07-13 10:19:49 +02:00
|
|
|
def get_by_tearchterm(term, queryset=None):
|
|
|
|
|
if not queryset:
|
|
|
|
|
queryset = Question.objects
|
|
|
|
|
return queryset.filter(Question.searchdomain(term)).annotate(cnt=models.Count('id'))
|
2024-07-12 17:22:17 +02:00
|
|
|
|
2024-07-13 14:38:42 +02:00
|
|
|
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
|
2024-07-03 21:41:03 +02:00
|
|
|
|
|
|
|
|
|
2024-07-12 17:22:17 +02:00
|
|
|
class QuestionVersion(DateAware, AuthorAware):
|
2024-07-03 21:41:03 +02:00
|
|
|
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']]
|
2024-07-12 17:22:17 +02:00
|
|
|
data['shares'] = list(map(str, data['shares']))
|
2024-07-03 21:41:03 +02:00
|
|
|
|
|
|
|
|
QuestionVersion.objects.create(
|
|
|
|
|
question=instance,
|
|
|
|
|
data=data,
|
|
|
|
|
# https://django-crum.readthedocs.io/en/latest/
|
|
|
|
|
# from crum import get_current_user
|
|
|
|
|
# author=get_current_user(),
|
|
|
|
|
)
|