Files
fet2020/fet2020/posts/models.py
2022-01-05 22:53:42 +00:00

369 lines
10 KiB
Python

import re
import logging
from datetime import timedelta
from django.contrib.auth.models import User
from django.core.validators import ValidationError
from django.db import models
from django.template.loader import render_to_string
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 core.models import CustomFlatPage
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"
padID = createPadifNotExists(slug + "-" + typ)
if padID:
page = CustomFlatPage.objects.filter(title__iexact=typ).first()
if page:
setPadHTML(padID, page.content)
return padID
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 three_tag_names(self):
tag_lst = []
count = 0
for t in self.tags.names():
tag_lst.append(t)
count += 1
if count > 2:
break
return tag_lst
@property
def tag_names(self):
return [t for t in self.tags.names()]
@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:posts.show", kwargs={"id": self.slug})
def get_absolute_url(self):
return self.url
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