From 8c8a3d378a3a0ebba669a27cede0e33496a3b14e Mon Sep 17 00:00:00 2001 From: Patrick Mayr Date: Wed, 12 Jan 2022 22:44:00 +0000 Subject: [PATCH] add post status and delete is_hidden --- fet2020/fet2020/views.py | 24 +++--- fet2020/posts/admin.py | 12 +-- fet2020/posts/forms.py | 7 +- fet2020/posts/managers.py | 141 +++++++++++++++-------------------- fet2020/posts/models.py | 25 ++++++- fet2020/posts/serializers.py | 1 - fet2020/posts/urls.py | 12 +-- fet2020/posts/views.py | 96 +++++++++++++----------- 8 files changed, 164 insertions(+), 154 deletions(-) diff --git a/fet2020/fet2020/views.py b/fet2020/fet2020/views.py index 1130474f..053355ac 100644 --- a/fet2020/fet2020/views.py +++ b/fet2020/fet2020/views.py @@ -6,7 +6,7 @@ from posts.models import Post, FetMeeting, Event def index(request): - posts = deque(Post.articles.get_date_sorted_list()) + posts = deque(Post.articles.date_sorted_list()) posts_for_tags = deque(Post.objects.get_last_months_posts()) def get_tags(lst): @@ -17,28 +17,28 @@ def index(request): t = set(t for t in get_tags(posts_for_tags)) # set the pinned post - featured_post = Post.articles.get_pinned_article() - if not featured_post: + pinned_post = Post.articles.pinned() + if not pinned_post: # if a pinned post does not exist, take the last published one. if len(posts) >= 1: - featured_post = posts.popleft() - else: - featured_post = 0 + pinned_post = posts.popleft() else: # remove the pinned post - posts.remove(featured_post) + posts.remove(pinned_post) - featured_event = Event.only_events.get_future_events().first() + featured_event = Event.only_events.future_events().first() # if there is no futurity event if not featured_event: - featured_event = Event.only_events.get_past_events().first() + featured_event = Event.only_events.past_events().first() - featured_meeting = FetMeeting.objects.get_meetings() + featured_meeting = deque([]) + featured_meeting.append(FetMeeting.objects.future_events().first()) + featured_meeting.append(FetMeeting.objects.past_events().first()) context = { "posts": deque(list(posts)[:5]), - "events": Event.all_events.get_five_events(), - "featured_post": featured_post, + "events": Event.all_events.future_events()[:5], + "featured_post": pinned_post, "featured_event": featured_event, "featured_meeting": featured_meeting, "tags_list": " ".join(t), diff --git a/fet2020/posts/admin.py b/fet2020/posts/admin.py index b47ad4d2..47eeaa08 100644 --- a/fet2020/posts/admin.py +++ b/fet2020/posts/admin.py @@ -55,9 +55,9 @@ class FileUploadInline(admin.TabularInline): class PostAdmin(admin.ModelAdmin): form = PostForm model = Post - list_filter = ["is_pinned", "is_hidden"] - list_display = ["title", "slug", "public_date", "is_pinned", "is_hidden"] - ordering = ["is_hidden", "-public_date"] + list_filter = ["is_pinned", "status"] + list_display = ["title", "slug", "public_date", "status", "is_pinned"] + ordering = ["-public_date"] def add_view(self, request, form_url="", extra_context=None): extra_context = extra_context or {} @@ -104,8 +104,8 @@ class NewsAdmin(PostAdmin): class EventAdmin(PostAdmin): form = EventForm model = Event - list_filter = ["is_pinned"] - list_display = ["title", "slug", "event_start", "public_date", "is_pinned"] + list_filter = ["is_pinned", "status"] + list_display = ["title", "slug", "event_start", "status", "is_pinned"] ordering = ["-event_start"] actions = [make_fetmeeting] @@ -114,7 +114,7 @@ class FetMeetingAdmin(EventAdmin): form = FetMeetingForm model = FetMeeting list_filter = [] - list_display = ["title", "slug", "event_start", "public_date"] + list_display = ["title", "slug", "event_start"] actions = [] diff --git a/fet2020/posts/forms.py b/fet2020/posts/forms.py index bc54dc8c..9fb19ca2 100644 --- a/fet2020/posts/forms.py +++ b/fet2020/posts/forms.py @@ -39,13 +39,13 @@ class NewsForm(PostForm): "title", "subtitle", "tags", + "status", "image", "body", "slug", "author", "public_date", "is_pinned", - "is_hidden", ] labels = { @@ -57,7 +57,6 @@ class NewsForm(PostForm): "author": _("Autor"), "public_date": _("Veröffentlichung"), "is_pinned": _("Post anheften"), - "is_hidden": _("Post verstecken"), } help_texts = { @@ -68,9 +67,6 @@ class NewsForm(PostForm): "is_pinned": _( "Dieser Post soll an die Startseite als erster Post angeheftet werden." ), - "is_hidden": _( - "Dieser Post soll im News Feed nicht auftauchen, z.B. Impressum." - ), } widgets = {"body": CKEditorUploadingWidget(config_name="default")} @@ -89,6 +85,7 @@ class EventForm(PostForm): "title", "subtitle", "tags", + "status", "image", "body", "event_start", diff --git a/fet2020/posts/managers.py b/fet2020/posts/managers.py index a0dfd5fc..943b7a9a 100644 --- a/fet2020/posts/managers.py +++ b/fet2020/posts/managers.py @@ -1,20 +1,26 @@ from django.db import models -from django.db.models import Q +from django.db.models import Q, Manager from django.utils import timezone from datetime import timedelta -class PostManager(models.Manager): +class PublishedManager(Manager): + def published(self, public=True): + if public: + qs = self.get_queryset().filter(status="20") + else: + qs = self.get_queryset() + return qs + + +class PostManager(PublishedManager, Manager): def get_queryset(self): return super().get_queryset().order_by("-public_date") - def get_visible_articles(self): - return self.get_queryset().filter(is_hidden=False) - - def get_date_sorted_list(self): + def date_sorted_list(self, public=True): post_list = [] - for post in self.get_visible_articles(): + for post in self.published(public): if post.post_type != "N": post_list.append((post, post.event_start.date())) else: @@ -25,13 +31,20 @@ class PostManager(models.Manager): return posts - def get_date_filtered_list(self, year=None, month=None, fet_meeting_only=None): + def date_filtered_list( + self, + public=True, + year=None, + month=None, + fet_meeting_only=None, + ): post_list = [] + qs = self.published(public) if not fet_meeting_only: - posts = self.get_visible_articles().filter(~Q(post_type="N")) + posts = qs.filter(~Q(post_type="N")) else: - posts = self.get_visible_articles().filter(post_type="F") + posts = qs.filter(post_type="F") if year: posts = posts.filter(event_start__year=year) @@ -42,7 +55,7 @@ class PostManager(models.Manager): post_list.append((post, post.event_start.date())) if not fet_meeting_only: - posts = self.get_visible_articles().filter(post_type="N") + posts = qs.filter(post_type="N") if year: posts = posts.filter(public_date__year=year) @@ -57,40 +70,27 @@ class PostManager(models.Manager): return posts - def get_last_months_posts(self): + # use for finding tags at homepage - TODO: delete when new design published + def get_last_months_posts(self, public=True): date_today = timezone.now().date() - return self.get_visible_articles().filter( + return self.published(public).filter( public_date__gt=date_today - timedelta(days=365) ) - def get_all_posts_with_date(self): - return ( - self.get_queryset() - .filter(Q(event_start__isnull=False) & Q(event_end__isnull=False)) - .order_by("-event_start") - ) - -class ArticleManager(models.Manager): +class ArticleManager(PublishedManager, 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") - ) + qs = super().get_queryset().filter(Q(post_type="E") | Q(post_type="N")) + return qs.order_by("-public_date") - def get_visible_articles(self): - return self.get_queryset().filter(is_hidden=False) - - def get_date_sorted_list(self): + def date_sorted_list(self, public=True): post_list = [] - for post in self.get_visible_articles(): + for post in self.published(public): if post.post_type != "N": post_list.append((post, post.event_start.date())) else: @@ -101,11 +101,11 @@ class ArticleManager(models.Manager): return posts - def get_pinned_article(self): - return self.get_visible_articles().filter(is_pinned=True).first() + def pinned(self, public=True): + return self.published(public).filter(is_pinned=True).first() -class NewsManager(models.Manager): +class NewsManager(PublishedManager, Manager): """ Provide a query set only for "News" """ @@ -113,79 +113,60 @@ class NewsManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(post_type="N").order_by("-public_date") - def get_visible_articles(self): - return self.get_queryset().filter(is_hidden=False) - -class AllEventManager(models.Manager): +class AllEventManager(PublishedManager, Manager): """ Provide a query set for all events ("Event" and "Fet Meeting") """ def get_queryset(self): - return super().get_queryset().filter(Q(post_type="E") | Q(post_type="F")) - - def get_five_events(self): - date_today = timezone.now() return ( - self.get_queryset() - .filter(event_start__gt=date_today) - .order_by("event_start")[:5] + super() + .get_queryset() + .filter(Q(post_type="E") | Q(post_type="F")) + .order_by("-event_start") ) + def future_events(self, public=True): + date_today = timezone.now() + qs = self.published(public).filter(event_start__gt=date_today) + return qs.reverse() -class EventManager(models.Manager): + +class EventManager(PublishedManager, 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(post_type="E") + return super().get_queryset().filter(post_type="E").order_by("-event_start") - def get_future_events(self): + def future_events(self, public=True): date_today = timezone.now() - return ( - self.get_queryset() - .filter(event_start__gt=date_today) - .order_by("event_start") - ) + qs = self.published(public).filter(event_start__gt=date_today) + return qs.reverse() - def get_past_events(self): + def past_events(self, public=True): date_today = timezone.now() - return ( - self.get_queryset() - .filter(event_start__lt=date_today) - .order_by("-event_start") - ) + qs = self.published(public).filter(event_start__lt=date_today) + return qs -class FetMeetingManager(models.Manager): +class FetMeetingManager(PublishedManager, Manager): """ Provide a query set only for "Fet Meeting" """ def get_queryset(self): - return super().get_queryset().filter(post_type="F") + return super().get_queryset().filter(post_type="F").order_by("-event_start") - def _get_future_events(self): + def future_events(self): date_today = timezone.now() - return ( - self.get_queryset() - .filter(event_start__gt=date_today) - .order_by("event_start") - ) + qs = self.published().filter(event_start__gt=date_today) + return qs.reverse() - def _get_past_events(self): + def past_events(self): date_today = timezone.now() - return ( - self.get_queryset() - .filter(event_start__lt=date_today) - .order_by("-event_start") - ) - - def get_meetings(self): - meetings = [] - meetings.append(self._get_future_events().first()) - meetings.append(self._get_past_events().first()) - return meetings + qs = self.published().filter(event_start__lt=date_today) + return qs diff --git a/fet2020/posts/models.py b/fet2020/posts/models.py index 0bfc7d7f..b9e2f250 100644 --- a/fet2020/posts/models.py +++ b/fet2020/posts/models.py @@ -88,12 +88,21 @@ class Post(models.Model): __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) - # 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 @@ -263,6 +272,13 @@ class Post(models.Model): ) super().clean() + @property + def published(self): + if self.status == self.Status.PUBLIC: + return True + + return False + class News(Post): objects = NewsManager() @@ -342,6 +358,9 @@ class FetMeeting(Event): 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): diff --git a/fet2020/posts/serializers.py b/fet2020/posts/serializers.py index d2810fa3..d9bf34c5 100644 --- a/fet2020/posts/serializers.py +++ b/fet2020/posts/serializers.py @@ -23,7 +23,6 @@ class PostSerializer(serializers.HyperlinkedModelSerializer): "image", "event_start", "event_end", - "is_hidden", "agenda_html", "protocol_html", "has_agenda", diff --git a/fet2020/posts/urls.py b/fet2020/posts/urls.py index 4f647cbe..53837f5e 100644 --- a/fet2020/posts/urls.py +++ b/fet2020/posts/urls.py @@ -7,18 +7,20 @@ from .utils import slug_calc, tag_complete app_name = apps.PostsConfig.name urlpatterns = [ - path("func/tag_complete", tag_complete), - path("func/slug_calc", slug_calc), - path("t/", views.tags, name="posts.tags"), path("", views.index, name="posts.index"), - path("fet_calendar.ics", views.calendar, name="posts.calendar"), path("", views.show, name="posts.show"), re_path( - r"^(?P[-\w]+)/agenda.pdf$", views.show_pdf_agenda, name="show_pdf_agenda" + r"^(?P[-\w]+)/agenda.pdf$", + views.show_pdf_agenda, + name="show_pdf_agenda", ), re_path( r"^(?P[-\w]+)/protokoll.pdf$", views.show_pdf_protocol, name="show_pdf_protocol", ), + path("t/", views.tags, name="posts.tags"), + path("fet_calendar.ics", views.calendar, name="posts.calendar"), + path("func/tag_complete", tag_complete), + path("func/slug_calc", slug_calc), ] diff --git a/fet2020/posts/views.py b/fet2020/posts/views.py index fc0b8aac..99b33fc6 100644 --- a/fet2020/posts/views.py +++ b/fet2020/posts/views.py @@ -14,7 +14,7 @@ from documents.api import get_pad_link from documents.etherpadlib import add_ep_cookie from members.models import Member, JobMember from .forms import PostSearchForm -from .models import Post, FetMeeting, FileUpload +from .models import Event, FetMeeting, FileUpload, Post from .utils import render_to_pdf @@ -28,6 +28,8 @@ def index(request): compact_view = None fet_meeting_only = None + public_only = not request.user.is_authenticated + if request.method == "POST": if "btn_input" in request.POST: form = PostSearchForm(request.POST) @@ -53,12 +55,15 @@ def index(request): request, "Es kann nicht nur nach einem Monat gesucht werden." ) - posts = deque( - Post.objects.get_date_filtered_list(year, month, fet_meeting_only) + posts = Post.objects.date_filtered_list( + public_only, + year, + month, + fet_meeting_only, ) else: form = PostSearchForm() - posts = deque(Post.objects.get_date_sorted_list()) + posts = Post.objects.date_sorted_list(public_only) if posts: taglist = map(lambda post: post.tags, posts) @@ -75,20 +80,26 @@ def index(request): def calendar(request): - "Kalender Ansicht ICS zur Verknüpfung mit Outlook" - events = deque(Post.objects.get_all_posts_with_date()) + """ + ICS-calendar for outlook, google calender,... + """ + # publish all events independent of authenticated user + events = Event.all_events.published(False) + + context = { + "events": events, + } return render( - request, - "posts/fet_calendar.ics", - {"events": events}, - content_type="text/calendar", + request, "posts/fet_calendar.ics", context, content_type="text/calendar" ) def tags(request, tag=""): - posts = deque(Post.objects.get_visible_articles().filter(tags__name=tag)) - featured_post = Post.objects.get_visible_articles().filter(slug=tag).first() + public_only = not request.user.is_authenticated + + posts = Post.objects.published(public_only).filter(tags__name=tag) + featured_post = Post.objects.published(public_only).filter(slug=tag).first() job_members = JobMember.active_member.get_all_by_slug(slug=tag) @@ -110,14 +121,14 @@ def tags(request, tag=""): return render(request, "posts/tag.html", context) -def __get_post_object(id=None): +def __get_post_object(id=None, public=True): post = None try: if id.isdigit() or id is int: - post = Post.objects.get(id=int(id)) + post = Post.objects.published(public).get(id=int(id)) elif id != "" and id is not None: - post = Post.objects.get(slug=id) + post = Post.objects.published(public).get(slug=id) except Exception: logger.info("Wrong id '{}'".format(id)) raise Http404("wrong post id") @@ -126,49 +137,51 @@ def __get_post_object(id=None): def show(request, id=None): - p = __get_post_object(id) + public_only = not request.user.is_authenticated + post = __get_post_object(id, public_only) - files = deque(FileUpload.objects.filter(post=p)) + # files + files = FileUpload.objects.filter(post=post) - post_author = Member.all_members.filter(username=p.author).first() - author_image = None + # author author = None - + author_image = None + post_author = Member.all_members.filter(username=post.author).first() if post_author: - author_image = post_author.image["avatar"].url author = post_author + author_image = post_author.image["avatar"].url + # etherpad links for agenda and protocol ep_agenda_link = "#" ep_protocol_link = "#" # set filename for pdf, not a nice solution filename_agenda = None filename_protocol = None - if p.has_agenda: - ep_agenda_link = get_pad_link(p.agenda_key) + if post.has_agenda: + ep_agenda_link = get_pad_link(post.agenda_key) if ep_agenda_link != "#": - filename_agenda = p.slug + "-agenda.pdf" + filename_agenda = post.slug + "-agenda.pdf" - if p.has_protocol: - ep_protocol_link = get_pad_link(p.protocol_key) + if post.has_protocol: + ep_protocol_link = get_pad_link(post.protocol_key) if ep_protocol_link != "#": - filename_protocol = p.slug + "-protokoll.pdf" - - related_posts = p.tags.similar_objects() + filename_protocol = post.slug + "-protokoll.pdf" + related_posts = post.tags.similar_objects() # list of non 'is_hidden' posts for related_posts for obj in related_posts: - if obj.is_hidden: + if not obj.published: related_posts.remove(obj) context = { - "post": p, + "post": post, "files": files, "author": author, "author_image": author_image, - "next": __get_next_dict(p), + "next": __next(post, public_only), "related_posts": related_posts[0:6], "ep_agenda_link": ep_agenda_link, "ep_protocol_link": ep_protocol_link, @@ -215,34 +228,33 @@ def show_pdf(request, html, filename): def show_pdf_agenda(request, id): - p = __get_post_object(id) - html = p.agenda_html + post = __get_post_object(id) + html = post.agenda_html - return show_pdf(request, html, p.slug + "-agenda") + return show_pdf(request, html, post.slug + "-agenda") @authenticated_user def show_pdf_protocol(request, id): - p = __get_post_object(id) - html = p.protocol_html + post = __get_post_object(id) + html = post.protocol_html - return show_pdf(request, html, p.slug + "-protokoll") + return show_pdf(request, html, post.slug + "-protokoll") -def __get_next_dict(post=None): +def __next(post=None, public=True): """ Helper function for getting next post """ - # TODO: Docstring posts = None d = post.slug if post: # TODO: bad implementation but it works!! if post.post_type == "N" or post.post_type == "E": - posts = Post.articles.get_visible_articles() + posts = Post.articles.date_sorted_list(public) elif post.post_type == "F": - posts = FetMeeting.objects.get_queryset().order_by("-event_start") + posts = FetMeeting.objects.published(public) if posts: for k, v in enumerate(posts):