Files
fet2020/fet2020/posts/models.py
2024-08-06 01:30:39 +02:00

420 lines
12 KiB
Python

import logging
from datetime import timedelta
from django.conf import settings
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 core.models import CustomFlatPage
from documents.api import (
ep_create_new_pad,
ep_get_html,
ep_get_url,
ep_pad_exists,
ep_set_html,
)
from .managers import (
AllEventManager,
ArticleManager,
EventManager,
FetMeetingManager,
NewsManager,
PostManager,
)
logger = logging.getLogger(__name__)
request_logger = logging.getLogger("django.request")
def create_pad_for_post(slug, item="agenda"):
"""
Create a Etherpad pad.
Return a Etherpad key.
"""
logger.info(f"Pad-Type: {item}")
pad_id = slug + "-" + item
if ep_create_new_pad(pad_id):
# Set template into the newly created pad if it exists.
if page := CustomFlatPage.objects.filter(title__iexact=item).first():
ep_set_html(pad_id, page.content)
logger.info(f"Template is set. Template: {page.title}")
return pad_id
return "#"
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)
class Status(models.TextChoices):
DRAFT = "10", _("DRAFT")
ONLY_INTERN = "15", _("ONLY_INTERN")
PUBLIC = "20", _("PUBLIC")
status = models.CharField(
verbose_name="Status",
max_length=2,
choices=Status.choices,
default=Status.DRAFT,
)
# post is pinned at main page
is_pinned = models.BooleanField(verbose_name="ANGEHEFTET", 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 __str__(self):
return "Post (%s, %s): %s" % (
self.slug,
self.public_date.strftime("%d.%m.%Y"),
self.title,
)
def get_absolute_url(self):
return reverse("posts:post", kwargs={"slug": self.slug})
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)
@property
def agenda_html(self) -> (str | None):
"Agenda HTML from Etherpad Pad"
if self.agenda_key in [None, "#"]:
return None
return ep_get_html(self.agenda_key)
@property
def protocol_html(self) -> (str | None):
"Protocol HTML from Etherpad Pad"
if self.protocol_key in [None, "#"]:
return None
return ep_get_html(self.protocol_key)
@agenda_html.setter
def agenda_html(self, value: str) -> (str | None):
if self.agenda_key is None:
self.create_agenda_key()
if value is None or self.agenda_key in [None, "#"]:
return None
ep_set_html(self.agenda_key, value)
request_logger.info(f"Set agenda etherpad. Post: {self.slug}. Key: {self.agenda_key}")
return value
@protocol_html.setter
def protocol_html(self, value: str) -> (str | None):
if self.protocol_key is None:
self.create_protocol_key()
if value is None or self.protocol_key in [None, "#"]:
return None
ep_set_html(self.protocol_key, value)
request_logger.info(f"Set protocol etherpad. Post: {self.slug}. Key: {self.protocol_key}")
return value
_agenda_filename = None
_agenda_url = None
@property
def agenda_url(self) -> (str | None):
if self.has_agenda is not True:
self._agenda_url = None
self._agenda_filename = None
return self._agenda_url
if self._agenda_url is not None:
return self._agenda_url
if (url := ep_get_url(self.agenda_key)) not in [None, "#"]:
self._agenda_url = url
self._agenda_filename = self.slug + "-agenda.pdf"
else:
self._agenda_url = None
self._agenda_filename = None
return self._agenda_url
@property
def agenda_filename(self) -> (str | None):
if self._agenda_filename is not None:
return self._agenda_filename
if self.has_agenda and self.agenda_url:
return self.slug + "-agenda.pdf"
return None
_protocol_filename = None
_protocol_url = None
@property
def protocol_url(self) -> (str | None):
if self.has_protocol is not True:
self._protocol_url = None
self._protocol_filename = None
return self._protocol_url
if self._protocol_url is not None:
return self._protocol_url
if (url := ep_get_url(self.protocol_key)) not in [None, "#"]:
self._protocol_url = url
self._protocol_filename = self.slug + "-protokoll.pdf"
else:
self._protocol_url = None
self._protocol_filename = None
return self._protocol_url
@property
def protocol_filename(self) -> (str | None):
if self._protocol_filename is not None:
return self._protocol_filename
if self.has_protocol and self.protocol_url:
return self.slug + "-protokoll.pdf"
return None
def create_agenda_key(self) -> None:
"""
Create a Etherpad Id for the Pad associated to this post.
Create the pad if it doesn't exist.
"""
if self.slug:
self.agenda_key = create_pad_for_post(self.slug, "agenda")
def create_protocol_key(self) -> None:
"""
Create a Etherpad Id for the Pad associated to this post.
Create the pad if it doesn't exist.
"""
if self.slug:
self.protocol_key = create_pad_for_post(self.slug, "protocol")
def get_model_name(self):
return self._meta.model_name
@property
def three_tag_names(self):
return self.tags.names()[:3]
@property
def tag_names(self):
return [t for t in self.tags.names()]
@property
def imageurl(self) -> str:
"""
returns the url to the image
"""
if self.image:
return self.image.url
# return default image
return settings.STATIC_URL + "img/FET-Logo-2014-quadrat.png"
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.")
@property
def published(self):
if self.status == self.Status.PUBLIC:
return True
return False
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()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.post_type = "E"
class Meta:
proxy = True
verbose_name = "Event"
verbose_name_plural = "Events"
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)
def clean(self):
super().clean()
if not self.event_start:
raise ValidationError("Das Datum des Events fehlt.")
class FetMeeting(Event):
objects = FetMeetingManager()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.post_type = "F"
class Meta:
proxy = True
verbose_name = "Fet Sitzung"
verbose_name_plural = "Fet Sitzungen"
def save(self, *args, **kwargs):
self.title = "Fachschaftssitzung"
if not self.slug:
self.slug = self.__get_slug()
if ep_pad_exists(self.agenda_key) is not True or self.slug not in self.agenda_key:
self.create_agenda_key()
if self.agenda_key not in [None, "#"]:
self.has_agenda = True
if ep_pad_exists(self.protocol_key) is not True or self.slug not in self.protocol_key:
self.create_protocol_key()
if self.protocol_key not in [None, "#"]:
self.has_protocol = True
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)
# set FET Meeting always public
self.status = self.Status.PUBLIC
super().save(*args, **kwargs)
def __get_slug(self) -> str:
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()
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