import csv import json import os.path import zipfile import pdfkit import requests from django.contrib.auth.models import User from django.db import models from django.template.loader import render_to_string from django.utils.safestring import mark_safe from content.models import Question as QuestionContent from lib.core.db.models.mixins import AuthorAware, DateAware, PublishedAware from tablequizwiki.settings import BASE_DIR class Quiz(AuthorAware, DateAware, PublishedAware): name = models.CharField(max_length=250) # author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, default=get_current_user) # created_at = models.DateTimeField(auto_now_add=True) # updated_at = models.DateTimeField(auto_now=True) def __str__(self): return self.name @property def download_urls(self): return mark_safe( f'Tabelle' ' | ' f'CSV' ' | ' f'PDF' ' | ' f'ZIP' ) def to_view(self, for_players: bool = False): data = { 'name': self.name, 'items': [], 'json': '', } for _q in self.question_set.prefetch_related('question').order_by('order').all(): data['items'].append(_q.to_view(for_players=for_players)) data['json'] = json.dumps(data['items'], indent=4, default=repr) return data def to_pdf(self, fh=None): html = render_to_string('quiz/as_table.html', {'print': True, **self.to_view(), }) pdfkit.from_string( html, self.pdfpath, options={ 'orientation': 'landscape', } ) return self.pdfpath def to_csv(self, fh=None): with open(self.csvpath, 'w') as cf: items = self.to_view()['items'] keys = items[0].keys() dw = csv.DictWriter(cf, fieldnames=list(keys)) dw.writeheader() dw.writerows(items) return self.csvpath def to_zip(self, fh=None): with zipfile.ZipFile(self.zippath, 'w') as zf: zf.write(self.to_pdf(), arcname=os.path.basename(self.pdfpath)) zf.write(self.to_csv(), arcname=os.path.basename(self.csvpath)) medias = set(list(self.medias)) links = set(list(self.links)) for media in medias: zf.write(media, arcname='media/' + os.path.basename(media)) for link in links: filename = link.replace('/', '-').split('?')[0].strip(' \n/') + '.html' with open(f'/tmp/{filename}', 'w') as htmlfile: txt = '' try: response = requests.get(link) if response.ok: htmlfile.write(response.text) else: htmlfile.write(f"Could not download {link} - {response}") except Exception as e: htmlfile.write(f"Could not download {link} - {e}") zf.write(f'/tmp/{filename}', arcname='links/' + filename) return self.zippath @property def links(self): for q in self.question_set.all(): for link in q.question.links.all(): yield link.url @property def medias(self): for q in self.question_set.all(): for media in q.question.medias.all(): yield media.file.path @property def zippath(self): return str(BASE_DIR) + f'/filestore/zip/quiz.{self.id}.zip' @property def pdfpath(self): return str(BASE_DIR) + f'/filestore/pdf/quiz.{self.id}.pdf' @property def csvpath(self): return str(BASE_DIR) + f'/filestore/csv/quiz.{self.id}.csv' class Question(DateAware): question = models.ForeignKey(QuestionContent, on_delete=models.RESTRICT, related_name='content_question') quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE) points = models.DecimalField(max_digits=10, decimal_places=1, default=1.0) order = models.IntegerField(default=1) description = models.TextField(null=True, blank=True) def __str__(self): return str(self.question) def to_view(self, for_players: bool = False): ret = self.question.to_view(for_players=for_players) ret['points'] = self.points return ret