Add atom/rss news feed

This commit is contained in:
Antoine Bartuccio 2025-01-19 18:14:07 +01:00
parent c7ae70972f
commit dd2cd0a18d
7 changed files with 73 additions and 6 deletions

View File

@ -36,6 +36,11 @@
&:not(:first-of-type) { &:not(:first-of-type) {
margin: 2em 0 1em 0; margin: 2em 0 1em 0;
} }
.feed {
float: right;
color: #f26522;
}
} }
@media screen and (max-width: $small-devices) { @media screen and (max-width: $small-devices) {

View File

@ -8,6 +8,9 @@
{% block additional_css %} {% block additional_css %}
<link rel="stylesheet" href="{{ static('com/css/news-list.scss') }}"> <link rel="stylesheet" href="{{ static('com/css/news-list.scss') }}">
<link rel="stylesheet" href="{{ static('com/components/ics-calendar.scss') }}"> <link rel="stylesheet" href="{{ static('com/components/ics-calendar.scss') }}">
{# Atom feed discovery, not really css but also goes there #}
<link rel="alternate" type="application/rss+xml" title="{% trans %}News feed{% endtrans %}" href="{{ url("com:news_feed") }}">
{% endblock %} {% endblock %}
{% block additional_js %} {% block additional_js %}
@ -19,7 +22,10 @@
<div id="news"> <div id="news">
<div id="left_column" class="news_column"> <div id="left_column" class="news_column">
{% set events_dates = NewsDate.objects.filter(end_date__gte=timezone.now(), start_date__lte=timezone.now()+timedelta(days=5), news__is_moderated=True).datetimes('start_date', 'day') %} {% set events_dates = NewsDate.objects.filter(end_date__gte=timezone.now(), start_date__lte=timezone.now()+timedelta(days=5), news__is_moderated=True).datetimes('start_date', 'day') %}
<h3>{% trans %}Events today and the next few days{% endtrans %}</h3> <h3>
{% trans %}Events today and the next few days{% endtrans %}
<a target="#" href="{{ url("com:news_feed") }}"><i class="fa fa-rss feed"></i></a>
</h3>
{% if user.is_authenticated and (user.is_com_admin or user.memberships.board().ongoing().exists()) %} {% if user.is_authenticated and (user.is_com_admin or user.memberships.board().ongoing().exists()) %}
<a class="btn btn-blue margin-bottom" href="{{ url("com:news_new") }}"> <a class="btn btn-blue margin-bottom" href="{{ url("com:news_new") }}">
<i class="fa fa-plus"></i> <i class="fa fa-plus"></i>
@ -73,7 +79,10 @@
</div> </div>
{% endif %} {% endif %}
<h3>{% trans %}All coming events{% endtrans %}</h3> <h3>
{% trans %}All coming events{% endtrans %}
<a target="#" href="{{ url("com:news_feed") }}"><i class="fa fa-rss feed"></i></a>
</h3>
<ics-calendar locale="{{ get_language() }}"></ics-calendar> <ics-calendar locale="{{ get_language() }}"></ics-calendar>
</div> </div>

View File

@ -319,3 +319,11 @@ class TestNewsCreation(TestCase):
self.valid_payload, self.valid_payload,
) )
mocked.assert_called() mocked.assert_called()
@pytest.mark.django_db
def test_feed(client):
"""Smoke test that checks that the atom feed is working"""
resp = client.get(reverse("com:news_feed"))
assert resp.status_code == 200
assert resp.headers["Content-Type"] == "application/rss+xml; charset=utf-8"

View File

@ -25,6 +25,7 @@ from com.views import (
NewsCreateView, NewsCreateView,
NewsDeleteView, NewsDeleteView,
NewsDetailView, NewsDetailView,
NewsFeed,
NewsListView, NewsListView,
NewsModerateView, NewsModerateView,
NewsUpdateView, NewsUpdateView,
@ -73,6 +74,7 @@ urlpatterns = [
name="weekmail_article_edit", name="weekmail_article_edit",
), ),
path("news/", NewsListView.as_view(), name="news_list"), path("news/", NewsListView.as_view(), name="news_list"),
path("news/feed/", NewsFeed(), name="news_feed"),
path("news/admin/", NewsAdminListView.as_view(), name="news_admin_list"), path("news/admin/", NewsAdminListView.as_view(), name="news_admin_list"),
path("news/create/", NewsCreateView.as_view(), name="news_new"), path("news/create/", NewsCreateView.as_view(), name="news_new"),
path("news/<int:news_id>/edit/", NewsUpdateView.as_view(), name="news_edit"), path("news/<int:news_id>/edit/", NewsUpdateView.as_view(), name="news_edit"),

View File

@ -26,8 +26,10 @@ from datetime import timedelta
from smtplib import SMTPRecipientsRefused from smtplib import SMTPRecipientsRefused
from typing import Any from typing import Any
from dateutil.relativedelta import relativedelta
from django.conf import settings from django.conf import settings
from django.contrib.auth.mixins import AccessMixin, PermissionRequiredMixin from django.contrib.auth.mixins import AccessMixin, PermissionRequiredMixin
from django.contrib.syndication.views import Feed
from django.core.exceptions import PermissionDenied, ValidationError from django.core.exceptions import PermissionDenied, ValidationError
from django.db.models import Max from django.db.models import Max
from django.forms.models import modelform_factory from django.forms.models import modelform_factory
@ -268,6 +270,34 @@ class NewsDetailView(CanViewMixin, DetailView):
return super().get_context_data(**kwargs) | {"date": self.object.dates.first()} return super().get_context_data(**kwargs) | {"date": self.object.dates.first()}
class NewsFeed(Feed):
title = _("News")
link = reverse_lazy("com:news_list")
description = _("All incoming events")
def items(self):
return (
NewsDate.objects.filter(
news__is_moderated=True,
end_date__gte=timezone.now() - (relativedelta(months=6)),
)
.prefetch_related("news")
.order_by("-start_date")
)
def item_title(self, item: NewsDate):
return item.news.title
def item_description(self, item: NewsDate):
return item.news.summary
def item_link(self, item: NewsDate):
return item.news.get_absolute_url()
def item_author_name(self, item: NewsDate):
return item.news.author.get_display_name()
# Weekmail # Weekmail

View File

@ -27,7 +27,7 @@ from typing import ClassVar, NamedTuple
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.contrib.sites.models import Site from django.contrib.sites.shortcuts import get_current_site
from django.core.management import call_command from django.core.management import call_command
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.db import connection from django.db import connection
@ -92,7 +92,12 @@ class Command(BaseCommand):
raise Exception("Never call this command in prod. Never.") raise Exception("Never call this command in prod. Never.")
Sith.objects.create(weekmail_destinations="etudiants@git.an personnel@git.an") Sith.objects.create(weekmail_destinations="etudiants@git.an personnel@git.an")
Site.objects.create(domain=settings.SITH_URL, name=settings.SITH_NAME)
site = get_current_site(None)
site.domain = settings.SITH_URL
site.name = settings.SITH_NAME
site.save()
groups = self._create_groups() groups = self._create_groups()
self._create_ban_groups() self._create_ban_groups()

View File

@ -6,7 +6,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-10 14:52+0100\n" "POT-Creation-Date: 2025-01-19 18:12+0100\n"
"PO-Revision-Date: 2016-07-18\n" "PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Maréchal <thomas.girod@utbm.fr\n" "Last-Translator: Maréchal <thomas.girod@utbm.fr\n"
"Language-Team: AE info <ae.info@utbm.fr>\n" "Language-Team: AE info <ae.info@utbm.fr>\n"
@ -1447,7 +1447,7 @@ msgid "News admin"
msgstr "Administration des nouvelles" msgstr "Administration des nouvelles"
#: com/templates/com/news_admin_list.jinja com/templates/com/news_detail.jinja #: com/templates/com/news_admin_list.jinja com/templates/com/news_detail.jinja
#: com/templates/com/news_list.jinja #: com/templates/com/news_list.jinja com/views.py
msgid "News" msgid "News"
msgstr "Nouvelles" msgstr "Nouvelles"
@ -1525,6 +1525,10 @@ msgstr "Éditer (sera soumise de nouveau à la modération)"
msgid "Edit news" msgid "Edit news"
msgstr "Éditer la nouvelle" msgstr "Éditer la nouvelle"
#: com/templates/com/news_list.jinja
msgid "News feed"
msgstr "Flux d'actualités"
#: com/templates/com/news_list.jinja #: com/templates/com/news_list.jinja
msgid "Events today and the next few days" msgid "Events today and the next few days"
msgstr "Événements aujourd'hui et dans les prochains jours" msgstr "Événements aujourd'hui et dans les prochains jours"
@ -1767,6 +1771,10 @@ msgstr "Message d'alerte"
msgid "Screens list" msgid "Screens list"
msgstr "Liste d'écrans" msgstr "Liste d'écrans"
#: com/views.py
msgid "All incoming events"
msgstr "Tous les événements à venir"
#: com/views.py #: com/views.py
msgid "Delete and save to regenerate" msgid "Delete and save to regenerate"
msgstr "Supprimer et sauver pour régénérer" msgstr "Supprimer et sauver pour régénérer"