From 1e189f7b2b0f41a22744f9a83d1bcea623274760 Mon Sep 17 00:00:00 2001 From: imperosol Date: Sun, 18 Oct 2026 00:18:59 +0200 Subject: [PATCH] display club past news --- club/templates/club/club_news_list.jinja | 79 ++++++++++++++++++++++++ club/urls.py | 2 + club/views.py | 30 ++++++++- 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 club/templates/club/club_news_list.jinja diff --git a/club/templates/club/club_news_list.jinja b/club/templates/club/club_news_list.jinja new file mode 100644 index 00000000..2087bcc3 --- /dev/null +++ b/club/templates/club/club_news_list.jinja @@ -0,0 +1,79 @@ +{% extends "core/base.jinja" %} + +{% block content %} + {% if club.has_rights_in_club(user) %} + + {% trans %}Create news{% endtrans %} + + {% endif %} + + {% for semester_code, semester_events in events %} +

{{ semester_code }}

+ {% for event in semester_events %} +
+ {{ event.title }} +
+ + {# Events that occur weekly from the start to the end of the semester + would take a lot of space if shown by default. + Thus, if the event has more than one date, those are + hidden by a details element. + If there is only one date, it is directly displayed. #} + {% set dates = event.dates.all()|list %} + {% if dates|length == 1 %} + + - + + + {% else %} +
+ + {% trans trimmed nb_occurrences=dates|length %} + Dates ({{ nb_occurrences }} occurrences) + {% endtrans %} + +
    + {% for d in dates %} +
  • + - + +
  • + {% endfor %} +
+
+ {% endif %} + +

{% trans %}Permalink{% endtrans %}

+

{{ request.build_absolute_uri(event.get_absolute_url())|urlize }}

+ +

{% trans %}Summary{% endtrans %}

+ {% if event.summary %} + {{ event.summary|markdown }} + {% else %} +

{% trans %}No summary{% endtrans %}

+ {% endif %} + +

{% trans %}Description{% endtrans %}

+ {% if event.content %} + {{ event.content|markdown }} + {% else %} +

{% trans %}No detailed description{% endtrans %}

+ {% endif %} +
+
+ {% endfor %} +
+ {% endfor %} +{% endblock %} \ No newline at end of file diff --git a/club/urls.py b/club/urls.py index 6a08bbe5..d5b9f1a5 100644 --- a/club/urls.py +++ b/club/urls.py @@ -31,6 +31,7 @@ from club.views import ( ClubListView, ClubMailingView, ClubMembersView, + ClubNewsView, ClubOldMembersView, ClubPageEditView, ClubPageHistView, @@ -136,4 +137,5 @@ urlpatterns = [ PosterDeleteView.as_view(), name="poster_delete", ), + path("/news/", ClubNewsView.as_view(), name="news_list"), ] diff --git a/club/views.py b/club/views.py index 77e59721..4fbd7964 100644 --- a/club/views.py +++ b/club/views.py @@ -37,6 +37,7 @@ from django.contrib.messages.views import SuccessMessageMixin from django.core.exceptions import NON_FIELD_ERRORS, PermissionDenied, ValidationError from django.core.paginator import InvalidPage, Paginator from django.db.models import F, Prefetch, Q, Sum +from django.db.models.expressions import OuterRef, Subquery from django.db.models.functions import Length from django.http import Http404, StreamingHttpResponse from django.shortcuts import get_object_or_404, redirect @@ -71,7 +72,7 @@ from club.models import ( MailingSubscription, Membership, ) -from com.models import Poster +from com.models import NewsDate, Poster from com.views import ( PosterCreateBaseView, PosterDeleteBaseView, @@ -80,6 +81,7 @@ from com.views import ( ) from core.auth.mixins import CanEditMixin, PermissionOrClubBoardRequiredMixin from core.models import Page, PageRev +from core.utils import get_semester_code from core.views import BasePageEditView, DetailFormView, UseFragmentsMixin from core.views.mixins import ( AllowFragment, @@ -935,3 +937,29 @@ class PosterDeleteView(ClubTabsMixin, PosterDeleteBaseView): def get_success_url(self): return reverse_lazy("club:poster_list", kwargs={"club_id": self.club.id}) + + +class ClubNewsView(PermissionRequiredMixin, DetailView): + pk_url_kwarg = "club_id" + model = Club + permission_required = "club.view_club" + template_name = "club/club_news_list.jinja" + + def get_context_data(self, **kwargs: Any): + events = list( + self.object.news.viewable_by(self.request.user) + .annotate( + first_date=Subquery( + NewsDate.objects.filter(news_id=OuterRef("pk")) + .order_by("start_date") + .values("start_date")[:1] + ), + ) + .prefetch_related("dates") + .order_by("-first_date") + ) + return super().get_context_data(**kwargs) | { + "events": itertools.groupby( + events, key=lambda event: get_semester_code(event.first_date.date()) + ) + }