330 lines
9.5 KiB
Python
330 lines
9.5 KiB
Python
from django.contrib.auth.models import User
|
|
from django.core.validators import ValidationError
|
|
from django.db import models
|
|
from django.db.models import Q
|
|
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 members.models import Member
|
|
from taggit.managers import TaggableManager
|
|
# import documents
|
|
|
|
|
|
# from ckeditor_uploader import RichTextUploadingField
|
|
# import uuid
|
|
import re
|
|
from rest_framework import serializers
|
|
|
|
from datetime import timedelta
|
|
|
|
import logging
|
|
logger = logging.getLogger('posts')
|
|
|
|
|
|
############
|
|
# MANAGERS #
|
|
############
|
|
|
|
class PostManager(models.Manager):
|
|
def get_queryset(self):
|
|
return super().get_queryset()
|
|
|
|
|
|
class ArticleManager(models.Manager):
|
|
"""
|
|
Provide a query set only for "Article"
|
|
regular fet meetings should not be contained in the news stream
|
|
"""
|
|
def get_queryset(self):
|
|
return super().get_queryset().filter(
|
|
Q(post_type='E')
|
|
| Q(post_type='N')
|
|
).order_by('-public_date')
|
|
|
|
|
|
class NewsManager(models.Manager):
|
|
def get_queryset(self):
|
|
return super().get_queryset().filter(~Q(is_event=True))
|
|
|
|
|
|
class EventManager(models.Manager):
|
|
"""
|
|
Provide a query set only for "Events"
|
|
regular fet meetings should not be contained in the news stream
|
|
"""
|
|
def get_queryset(self):
|
|
return super().get_queryset().filter(
|
|
Q(is_event=True)
|
|
& ~Q(post_type='F')
|
|
).order_by('-public_date')
|
|
|
|
def get_all_events(self):
|
|
date_today = timezone.now().date()
|
|
return super().get_queryset().filter(
|
|
Q(is_event=True)
|
|
& Q(event_start__gt=date_today)
|
|
).order_by('-event_start')
|
|
|
|
def get_five_events(self):
|
|
return super().get_queryset().filter(
|
|
Q(is_event=True)
|
|
).order_by('-event_start')[:5]
|
|
|
|
|
|
class FetMeetingManager(models.Manager):
|
|
def get_queryset(self):
|
|
return super().get_queryset().filter(Q(post_type='F'))
|
|
|
|
|
|
##########
|
|
# MODELS #
|
|
##########
|
|
|
|
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):
|
|
# id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
legacy_id = models.IntegerField(null=True)
|
|
legacy_rubrik_id = models.IntegerField(null=True)
|
|
# 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)
|
|
# Body Text Artikel Text soll später mit WYSIWG Editor bearbeitet werden
|
|
body = models.TextField(null=True, blank=True)
|
|
# Ein Haupt Bild für den Post
|
|
image = models.ImageField(null=True, blank=True)
|
|
# Wer hat das geschrieben
|
|
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
|
|
|
|
tags = TaggableManager(blank=True)
|
|
# Datum ab dem etwas öffentlich sein soll
|
|
public_date = models.DateField('date published', null=True, blank=True, default=timezone.now)
|
|
|
|
imported_from = models.CharField(max_length=200, null=True, blank=True)
|
|
|
|
__choices = [
|
|
('N', _('News')),
|
|
('E', _('Event')),
|
|
('F', _('FetMeeting'))
|
|
]
|
|
post_type = models.CharField(max_length=1, choices=__choices, editable=False)
|
|
|
|
is_event = models.BooleanField(default=False)
|
|
|
|
# Zusatz Info wenn ein Event gepostet wird
|
|
event_start = models.DateTimeField('Event Start', null=True, blank=True)
|
|
event_end = models.DateTimeField('Event Ende', null=True, blank=True)
|
|
event_place = models.CharField(max_length=200, null=True, blank=True)
|
|
|
|
# Dokumente v.a. fuer Sitzungen
|
|
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)
|
|
|
|
# Managers
|
|
objects = PostManager()
|
|
article_objects = ArticleManager()
|
|
|
|
def get_tags(self):
|
|
"""Returns assigned tags as a comma seperated list."""
|
|
return ",".join(self.tags.names())
|
|
|
|
@property
|
|
def get_tagnames(self):
|
|
return ["#%s" % t for t in self.tags.names()]
|
|
|
|
def imageurl(self):
|
|
""" returns the url to the image"""
|
|
if self.image:
|
|
return self.image.url
|
|
else:
|
|
image = self.find_an_image()
|
|
if image:
|
|
return image.url
|
|
else:
|
|
return ""
|
|
|
|
def key(self):
|
|
return self.slug or self.id
|
|
|
|
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
|
|
|
|
# posts2=self.tags.similar_objects()
|
|
# for p in posts2:
|
|
# if p.image is not None:
|
|
# return p.image
|
|
return None
|
|
|
|
@property
|
|
def url(self):
|
|
return reverse('posts.show', kwargs={"id": self.slug})
|
|
|
|
@property
|
|
def author_member(self):
|
|
return (Member.all_members.get(nickname=self.author.username))
|
|
|
|
def save(self, *args, **kwargs):
|
|
"save the post with some defaults"
|
|
if (self.id is None) and (not self.slug):
|
|
self.slug = slugify(self.public_date.date()) + "-" + slugify(self.title)
|
|
|
|
if self.has_agenda and (self.agenda_key == "" or self.agenda_key is None):
|
|
print("should create an agenda document")
|
|
|
|
if self.has_protocol and (self.agenda_key == "" or self.agenda_key is None):
|
|
print("should initialize protocol document")
|
|
|
|
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 PostSerializer(serializers.HyperlinkedModelSerializer):
|
|
class Meta:
|
|
model = Post
|
|
fields = [
|
|
'slug',
|
|
'title',
|
|
'subtitle',
|
|
'body',
|
|
'url',
|
|
'public_date',
|
|
'legacy_id',
|
|
'image',
|
|
'event_start',
|
|
'event_end',
|
|
'is_fetsitzung',
|
|
]
|
|
|
|
|
|
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):
|
|
objects = EventManager()
|
|
|
|
class Meta:
|
|
proxy = True
|
|
|
|
verbose_name = "Event"
|
|
verbose_name_plural = "Events"
|
|
|
|
@property
|
|
def event_start_month(self):
|
|
return self.event_start.strftime("%b")
|
|
|
|
@property
|
|
def event_start_day(self):
|
|
return self.event_start.strftime("%d")
|
|
|
|
def clean(self):
|
|
if self.event_end is None or self.event_start is None:
|
|
raise ValidationError(_('Das Datum des Events fehlt.'))
|
|
elif self.event_end < self.event_start:
|
|
raise ValidationError(_('Das Ende des Events liegt vor dem Beginn.'))
|
|
|
|
def save(self, *args, **kwargs):
|
|
self.is_event = True
|
|
|
|
if not self.post_type:
|
|
self.post_type = 'E'
|
|
|
|
super().save(*args, **kwargs)
|
|
|
|
|
|
class FetMeeting(Event):
|
|
objects = FetMeetingManager()
|
|
|
|
class Meta:
|
|
proxy = True
|
|
|
|
verbose_name = "Fet Sitzung"
|
|
verbose_name_plural = "Fet Sitzungen"
|
|
|
|
def clean(self):
|
|
if self.event_start is None:
|
|
raise ValidationError(_('Das Datum des Events fehlt.'))
|
|
|
|
slug = slugify(self.event_start.date()) + "-" + slugify("Fachschaftssitzung")
|
|
|
|
if Post.objects.filter(slug=slug).count() != 0:
|
|
raise ValidationError(_('Es existiert bereits eine Sitzung mit demselben Datum.'))
|
|
|
|
def save(self, *args, **kwargs):
|
|
self.title = "Fachschaftssitzung"
|
|
self.slug = slugify(self.event_start.date()) + "-" + slugify(self.title)
|
|
self.body = "TODO: Agenda + Protokoll Link"
|
|
|
|
# TODO
|
|
# self.image
|
|
|
|
self.has_protocol = True
|
|
self.has_agenda = True
|
|
|
|
# TODO
|
|
# self.protocol_key
|
|
# self.agenda_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)
|