Files
fet2020/fet2020/posts/models.py
2021-05-07 11:28:31 +00:00

335 lines
9.9 KiB
Python

import re
import logging
from urllib.request import URLError
from datetime import timedelta
from django.contrib.auth.models import User
from django.core.validators import ValidationError
from django.db import models
from django.urls import reverse
from django.utils import timezone
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
from taggit.managers import TaggableManager
from documents import getPadHTML, setPadHTML, createPadifNotExists
from .managers import (
PostManager,
ArticleManager,
NewsManager,
AllEventManager,
EventManager,
FetMeetingManager,
)
logger = logging.getLogger(__name__)
request_logger = logging.getLogger("django.request")
def create_pad_for_post(slug, typ="agenda"):
"Creates a Etherpad Pad and returns EtherpadKey"
return createPadifNotExists(slug + "-" + typ)
class Category(models.Model):
# Titel des Posts
title = models.CharField(max_length=200)
subtitle = models.CharField(max_length=500, null=True, blank=True)
# Slug = Text Basierter url bestandteil zb Fetsitzung 22.1.2020 --> fetsitzung_22_1_2020 für Url
slug = models.SlugField(unique=True, null=True, blank=True)
# Ein Haupt Bild für den Post
image = models.ImageField(null=True, blank=True)
tags = TaggableManager(blank=True)
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
class Post(models.Model):
# legacy id is for the posts from the old website
legacy_id = models.IntegerField(null=True, blank=True)
title = models.CharField(verbose_name="Titel", max_length=200)
subtitle = models.CharField(max_length=500, null=True, blank=True)
tags = TaggableManager(blank=True)
# Slug = Text Basierter url bestandteil zb Fetsitzung 22.1.2020 --> fetsitzung_22_1_2020 für Url
slug = models.SlugField(unique=True, blank=True)
body = models.TextField(null=True, blank=True)
image = models.ImageField(null=True, blank=True)
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
public_date = models.DateField(
verbose_name="Veröffentlichung", null=True, blank=True, default=timezone.now
)
__choices = [("N", _("News")), ("E", _("Event")), ("F", _("FetMeeting"))]
post_type = models.CharField(max_length=1, choices=__choices, editable=True)
# post is pinned at main page
is_pinned = models.BooleanField(verbose_name="ANGEHEFTET", default=False)
# post is hidden from newsfeed (e.g. about)
is_hidden = models.BooleanField(verbose_name="UNSICHTBAR", default=False)
# addional infos for events
event_start = models.DateTimeField(verbose_name="Event Start", null=True, blank=True)
event_end = models.DateTimeField(verbose_name="Event Ende", null=True, blank=True)
event_place = models.CharField(max_length=200, null=True, blank=True)
# protocol for fet meeting
has_protocol = models.BooleanField(default=False)
has_agenda = models.BooleanField(default=False)
protocol_key = models.CharField(max_length=200, null=True, blank=True)
agenda_key = models.CharField(max_length=200, null=True, blank=True)
# TimeStamps
date_modified = models.DateTimeField(auto_now=True)
date_created = models.DateTimeField(auto_now_add=True)
# useless (-_-)
legacy_rubrik_id = models.IntegerField(null=True, blank=True)
imported_from = models.CharField(max_length=200, null=True, blank=True)
# Managers
objects = PostManager()
articles = ArticleManager()
def get_tags(self):
"""Returns assigned tags as a comma seperated list."""
return ",".join(self.tags.names())
@property
def agenda_html(self):
"Agenda HTML from Etherpad Pad"
if not self.agenda_key:
return None
return getPadHTML(self.agenda_key)
@property
def protocol_html(self):
"Protocol HTML from Etherpad Pad"
if not self.protocol_key:
return None
return getPadHTML(self.protocol_key)
@agenda_html.setter
def agenda_html(self, value):
if not self.agenda_key:
self.agenda_key = self.get_agenda_key()
if not value or not self.agenda_key:
return None
setPadHTML(self.agenda_key, value)
request_logger.info(
"set etherpad! for post %s id: %s", self.slug, self.agenda_key
)
return value
@protocol_html.setter
def protocol_html(self, value):
if not self.protocol_key:
self.protocol_key = self.get_protocol_key()
if not value or not self.protocol_key:
return None
setPadHTML(self.protocol_key, value)
request_logger.info(
"set etherpad! for post %s id: %s", self.slug, self.protocol_key
)
return value
def get_agenda_key(self):
"""Create a Etherpad Id for the Pad associated to this post.
Creates the pad if it doesn't exist"""
if not self.slug:
return None
return create_pad_for_post(self.slug, typ="agenda")
def get_protocol_key(self):
"""Create a Etherpad Id for the Pad associated to this post.
Creates the pad if it doesn't exist"""
if not self.slug:
return None
return create_pad_for_post(self.slug, typ="protocol")
@property
def get_tagnames(self):
return ["#%s" % t for t in self.tags.names()]
@property
def tag_string(self):
return self.get_tags()
@property
def imageurl(self):
""" returns the url to the image"""
if self.image:
return self.image.url
image = self.find_an_image()
if image:
return image.url
return ""
def find_an_image(self):
"find an image via another post"
# TODO: Explain why this image is selected on save of the image
# Query all posts that have a slug that equals one of the tags
posts1 = (
Post.objects.filter(slug__in=self.tags.names())
.filter(image__isnull=False)[0:1]
.all()
)
if len(posts1) > 0:
return posts1.get().image
return None
@property
def url(self):
return reverse("posts.show", kwargs={"id": self.slug})
def clean(self):
if self.event_end and self.event_end < self.event_start:
raise ValidationError(_("Das Ende des Events liegt vor dem Beginn."))
if self.event_start and self.post_type not in ["E", "F"]:
raise ValidationError("Für diesen Post Typ ist kein Event Start zulässig")
super().clean()
def save(self, *args, **kwargs):
# save the post with some defaults
if not self.public_date:
self.public_date = timezone.now().date()
if not self.slug:
self.slug = slugify(self.public_date) + "-" + slugify(self.title)
super().save(*args, **kwargs)
self.tags.set(
*re.findall(r"\#([\d\w-]+)", str(self.subtitle)),
*re.findall(r"\#([\d\w-]+)", str(self.title))
)
def __str__(self):
return "Post (%s, %s): %s" % (
self.slug,
self.public_date.strftime("%d.%m.%Y"),
self.title,
)
class News(Post):
objects = NewsManager()
class Meta:
proxy = True
verbose_name = "News"
verbose_name_plural = "News"
def save(self, *args, **kwargs):
if not self.post_type:
self.post_type = "N"
super().save(*args, **kwargs)
class Event(Post):
only_events = EventManager()
all_events = AllEventManager()
class Meta:
proxy = True
verbose_name = "Event"
verbose_name_plural = "Events"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.post_type = "E"
def clean(self):
if not self.event_start:
raise ValidationError(_("Das Datum des Events fehlt."))
super().clean()
def save(self, *args, **kwargs):
if not self.post_type:
self.post_type = "E"
if not self.event_end:
self.event_end = self.event_start + timedelta(hours=2)
super().save(*args, **kwargs)
class FetMeeting(Event):
objects = FetMeetingManager()
class Meta:
proxy = True
verbose_name = "Fet Sitzung"
verbose_name_plural = "Fet Sitzungen"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.post_type = "F"
def __get_slug(self):
slug = slugify(self.event_start.date()) + "-" + slugify("Fachschaftssitzung")
if Post.objects.filter(slug=slug).exists():
if Post.objects.get(slug=slug).id != self.id:
raise ValidationError(
_("Es existiert bereits eine Sitzung mit demselben Datum.")
)
return slug
def clean(self):
super().clean()
if not self.slug:
self.slug = self.__get_slug()
def save(self, *args, **kwargs):
self.title = "Fachschaftssitzung"
if not self.slug:
self.slug = self.__get_slug()
self.has_agenda = True
self.has_protocol = True
self.agenda_key = self.get_agenda_key()
self.protocol_key = self.get_protocol_key()
if not self.post_type:
self.post_type = "F"
if not self.event_place:
self.event_place = "FET"
# make duration 2 hours if not specified otherwise
if not self.event_end:
self.event_end = self.event_start + timedelta(hours=2)
super().save(*args, **kwargs)
class FileUpload(models.Model):
title = models.CharField(verbose_name="Titel", max_length=200)
file_field = models.FileField(verbose_name="Dokument", upload_to="uploads/posts/files/")
post = models.ForeignKey(Post, on_delete=models.CASCADE)
objects = models.Manager()
def __str__(self):
return self.title