Improve news list display

This commit is contained in:
imperosol 2025-01-20 17:27:00 +01:00
parent 3a06cefea8
commit 185fb70dda
5 changed files with 116 additions and 176 deletions

View File

@ -172,6 +172,22 @@ def news_notification_callback(notif):
notif.viewed = True notif.viewed = True
class NewsDateQuerySet(models.QuerySet):
def viewable_by(self, user: User) -> Self:
"""Filter the event dates that the given user can view.
- If the can view non moderated news, he can view all news dates
- else, he can view the dates of news that are either
authored by him or moderated.
"""
if user.has_perm("com.view_unmoderated_news"):
return self
q_filter = Q(news__is_moderated=True)
if user.is_authenticated:
q_filter |= Q(news__author_id=user.id)
return self.filter(q_filter)
class NewsDate(models.Model): class NewsDate(models.Model):
"""A date associated with news. """A date associated with news.
@ -187,6 +203,8 @@ class NewsDate(models.Model):
start_date = models.DateTimeField(_("start_date")) start_date = models.DateTimeField(_("start_date"))
end_date = models.DateTimeField(_("end_date")) end_date = models.DateTimeField(_("end_date"))
objects = NewsDateQuerySet.as_manager()
class Meta: class Meta:
verbose_name = _("news date") verbose_name = _("news date")
verbose_name_plural = _("news dates") verbose_name_plural = _("news dates")

View File

@ -172,54 +172,22 @@
.news_event { .news_event {
display: block; display: block;
padding: 0.4em; padding: 1em;
&:not(:last-child) { header {
border-bottom: 1px solid grey; img {
} height: 75px;
div {
margin: 0.2em;
} }
.header_content {
display: flex;
flex-direction: column;
justify-content: center;
gap: .2rem;
h4 { h4 {
margin-top: 1em; margin-top: 0;
text-transform: uppercase; text-transform: uppercase;
} }
.club_logo {
float: left;
min-width: 7em;
max-width: 9em;
margin: 0;
margin-right: 1em;
margin-top: 0.8em;
img {
max-height: 6em;
max-width: 8em;
display: block;
margin: 0 auto;
}
}
.news_date {
font-size: 100%;
}
.news_content {
clear: left;
.button_bar {
text-align: right;
.fb {
color: $faceblue;
}
.twitter {
color: $twitblue;
}
} }
} }
} }
@ -228,70 +196,6 @@
/* END EVENTS TODAY AND NEXT FEW DAYS */ /* END EVENTS TODAY AND NEXT FEW DAYS */
/* COMING SOON */
.news_coming_soon {
display: list-item;
list-style-type: square;
list-style-position: inside;
margin-left: 1em;
padding-left: 0;
a {
font-weight: bold;
text-transform: uppercase;
}
.news_date {
font-size: 0.9em;
}
}
/* END COMING SOON */
/* NOTICES */
.news_notice {
margin: 0 0 1em 1em;
padding: 0.4em;
padding-left: 1em;
background: $secondary-neutral-light-color;
box-shadow: $shadow-color 0 0 2px;
border-radius: 18px 5px 18px 5px;
h4 {
margin: 0;
}
.news_content {
margin-left: 1em;
}
}
/* END NOTICES */
/* CALLS */
.news_call {
margin: 0 0 1em 1em;
padding: 0.4em;
padding-left: 1em;
background: $secondary-neutral-light-color;
border: 1px solid grey;
box-shadow: $shadow-color 1px 1px 1px;
h4 {
margin: 0;
}
.news_date {
font-size: 0.9em;
}
.news_content {
margin-left: 1em;
}
}
/* END CALLS */
.news_empty { .news_empty {
margin-left: 1em; margin-left: 1em;
} }

View File

@ -1,5 +1,4 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% from 'core/macros.jinja' import tweet_quick, fb_quick %}
{% block title %} {% block title %}
{% trans %}News{% endtrans %} {% trans %}News{% endtrans %}
@ -18,10 +17,8 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<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') %}
<h3> <h3>
{% trans %}Events today and the next few days{% endtrans %} {% trans %}Events today and the next few days{% endtrans %}
<a target="#" href="{{ url("com:news_feed") }}"><i class="fa fa-rss feed"></i></a> <a target="#" href="{{ url("com:news_feed") }}"><i class="fa fa-rss feed"></i></a>
@ -33,51 +30,58 @@
</a> </a>
{% endif %} {% endif %}
{% if user.is_com_admin %} {% if user.is_com_admin %}
<a class="btn btn-blue" href="{{ url('com:news_admin_list') }}">{% trans %}Administrate news{% endtrans %}</a> <a class="btn btn-blue" href="{{ url('com:news_admin_list') }}">
{% trans %}Administrate news{% endtrans %}
</a>
<br> <br>
{% endif %} {% endif %}
{% if events_dates %} {% for day, dates_group in news_dates %}
{% for d in events_dates %}
<div class="news_events_group"> <div class="news_events_group">
<div class="news_events_group_date"> <div class="news_events_group_date">
<div> <div>
<div>{{ d|localtime|date('D') }}</div> <div>{{ day|date('D') }}</div>
<div class="day">{{ d|localtime|date('d') }}</div> <div class="day">{{ day|date('d') }}</div>
<div>{{ d|localtime|date('b') }}</div> <div>{{ day|date('b') }}</div>
</div> </div>
</div> </div>
<div class="news_events_group_items"> <div class="news_events_group_items">
{% for news in object_list.filter(dates__start_date__gte=d,dates__start_date__lte=d+timedelta(days=1)).exclude(dates__end_date__lt=timezone.now()).order_by('dates__start_date') %} {% for date in dates_group %}
<section class="news_event"> <article class="news_event">
<div class="club_logo"> <header class="row gap">
{% if news.club.logo %} {% if date.news.club.logo %}
<img src="{{ news.club.logo.url }}" alt="{{ news.club }}" /> <img src="{{ date.news.club.logo.url }}" alt="{{ date.news.club }}"/>
{% else %} {% else %}
<img src="{{ static("com/img/news.png") }}" alt="{{ news.club }}" /> <img src="{{ static("com/img/news.png") }}" alt="{{ date.news.club }}"/>
{% endif %} {% endif %}
</div> <div class="header_content">
<h4> <a href="{{ url('com:news_detail', news_id=news.id) }}">{{ news.title }}</a></h4> <h4>
<div><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></div> <a href="{{ url('com:news_detail', news_id=date.news_id) }}">
{{ date.news.title }}
</a>
</h4>
<a href="{{ date.news.club.get_absolute_url() }}">{{ date.news.club }}</a>
<div class="news_date"> <div class="news_date">
<span>{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> - <time datetime="{{ date.start_date.isoformat(timespec="seconds") }}">
<span>{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span> {{ date.start_date|localtime|time(DATETIME_FORMAT) }}
</div> </time> -
<div class="news_content">{{ news.summary|markdown }} <time datetime="{{ date.end_date.isoformat(timespec="seconds") }}">
<div class="button_bar"> {{ date.end_date|localtime|time(DATETIME_FORMAT) }}
{{ fb_quick(news) }} </time>
{{ tweet_quick(news) }}
</div> </div>
</div> </div>
</section> </header>
<div class="news_content markdown">
{{ date.news.summary|markdown }}
</div>
</article>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
{% endfor %}
{% else %} {% else %}
<div class="news_empty"> <div class="news_empty">
<em>{% trans %}Nothing to come...{% endtrans %}</em> <em>{% trans %}Nothing to come...{% endtrans %}</em>
</div> </div>
{% endif %} {% endfor %}
<h3> <h3>
{% trans %}All coming events{% endtrans %} {% trans %}All coming events{% endtrans %}
@ -110,18 +114,26 @@
<ul> <ul>
<li> <li>
<i class="fa-brands fa-discord fa-xl"></i> <i class="fa-brands fa-discord fa-xl"></i>
<a rel="nofollow" target="#" href="https://discord.gg/QvTm3XJrHR">{% trans %}Discord AE{% endtrans %}</a> <a rel="nofollow" target="#" href="https://discord.gg/QvTm3XJrHR">
{% trans %}Discord AE{% endtrans %}
</a>
{% if user.was_subscribed %} {% if user.was_subscribed %}
- <a rel="nofollow" target="#" href="https://discord.gg/u6EuMfyGaJ">{% trans %}Dev Team{% endtrans %}</a> - <a rel="nofollow" target="#" href="https://discord.gg/u6EuMfyGaJ">
{% trans %}Dev Team{% endtrans %}
</a>
{% endif %} {% endif %}
</li> </li>
<li> <li>
<i class="fa-brands fa-facebook fa-xl"></i> <i class="fa-brands fa-facebook fa-xl"></i>
<a rel="nofollow" target="#" href="https://www.facebook.com/@AEUTBM/">{% trans %}Facebook{% endtrans %}</a> <a rel="nofollow" target="#" href="https://www.facebook.com/@AEUTBM/">
Facebook
</a>
</li> </li>
<li> <li>
<i class="fa-brands fa-square-instagram fa-xl"></i> <i class="fa-brands fa-square-instagram fa-xl"></i>
<a rel="nofollow" target="#" href="https://www.instagram.com/ae_utbm">{% trans %}Instagram{% endtrans %}</a> <a rel="nofollow" target="#" href="https://www.instagram.com/ae_utbm">
Instagram
</a>
</li> </li>
</ul> </ul>
</div> </div>
@ -130,7 +142,7 @@
<div id="birthdays"> <div id="birthdays">
<h3>{% trans %}Birthdays{% endtrans %}</h3> <h3>{% trans %}Birthdays{% endtrans %}</h3>
<div id="birthdays_content"> <div id="birthdays_content">
{%- if user.was_subscribed -%} {%- if user.has_perm("core.view_user") -%}
<ul class="birthdays_year"> <ul class="birthdays_year">
{%- for year, users in birthdays -%} {%- for year, users in birthdays -%}
<li> <li>
@ -143,8 +155,13 @@
</li> </li>
{%- endfor -%} {%- endfor -%}
</ul> </ul>
{%- else -%} {%- elif not user.was_subscribed -%}
{# The user cannot view birthdays, because he never subscribed #}
<p>{% trans %}You need to subscribe to access this content{% endtrans %}</p> <p>{% trans %}You need to subscribe to access this content{% endtrans %}</p>
{%- else -%}
{# There is another reason why user cannot view birthdays (maybe he is banned)
but we cannot know exactly what is this reason #}
<p>{% trans %}You cannot access this content{% endtrans %}</p>
{%- endif -%} {%- endif -%}
</div> </div>
</div> </div>

View File

@ -37,9 +37,9 @@ from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.utils import timezone from django.utils import timezone
from django.utils.timezone import localdate from django.utils.timezone import localdate, now
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView, View from django.views.generic import DetailView, ListView, TemplateView, View
from django.views.generic.edit import CreateView, DeleteView, UpdateView from django.views.generic.edit import CreateView, DeleteView, UpdateView
from club.models import Club, Mailing from club.models import Club, Mailing
@ -236,28 +236,37 @@ class NewsAdminListView(PermissionRequiredMixin, ListView):
permission_required = ["com.moderate_news", "com.delete_news"] permission_required = ["com.moderate_news", "com.delete_news"]
class NewsListView(ListView): class NewsListView(TemplateView):
model = News
template_name = "com/news_list.jinja" template_name = "com/news_list.jinja"
queryset = News.objects.filter(is_moderated=True)
def get_queryset(self): def get_birthdays(self):
return super().get_queryset().viewable_by(self.request.user) if not self.request.user.has_perm("core.view_user"):
return []
def get_context_data(self, **kwargs): return itertools.groupby(
kwargs = super().get_context_data(**kwargs)
kwargs["NewsDate"] = NewsDate
kwargs["timedelta"] = timedelta
kwargs["birthdays"] = itertools.groupby(
User.objects.filter( User.objects.filter(
date_of_birth__month=localdate().month, date_of_birth__month=localdate().month,
date_of_birth__day=localdate().day, date_of_birth__day=localdate().day,
is_subscriber_viewable=True,
) )
.filter(role__in=["STUDENT", "FORMER STUDENT"]) .filter(role__in=["STUDENT", "FORMER STUDENT"])
.order_by("-date_of_birth"), .order_by("-date_of_birth"),
key=lambda u: u.date_of_birth.year, key=lambda u: u.date_of_birth.year,
) )
return kwargs
def get_news_dates(self):
return itertools.groupby(
NewsDate.objects.viewable_by(self.request.user)
.filter(end_date__gt=now(), start_date__lt=now() + timedelta(days=6))
.order_by("start_date")
.select_related("news", "news__club"),
key=lambda d: d.start_date.date(),
)
def get_context_data(self, **kwargs):
return super().get_context_data(**kwargs) | {
"news_dates": self.get_news_dates(),
"birthdays": self.get_birthdays(),
}
class NewsDetailView(CanViewMixin, DetailView): class NewsDetailView(CanViewMixin, DetailView):

View File

@ -39,14 +39,6 @@
<a rel="nofollow" target="#" class="share_button twitter" href="https://twitter.com/intent/tweet?text={{ news.get_full_url() }}">{% trans %}Tweet{% endtrans %}</a> <a rel="nofollow" target="#" class="share_button twitter" href="https://twitter.com/intent/tweet?text={{ news.get_full_url() }}">{% trans %}Tweet{% endtrans %}</a>
{%- endmacro %} {%- endmacro %}
{% macro fb_quick(news) -%}
<a rel="nofollow" target="#" href="https://www.facebook.com/sharer/sharer.php?u={{ news.get_full_url() }}" class="fb fa-brands fa-facebook fa-2x"></a>
{%- endmacro %}
{% macro tweet_quick(news) -%}
<a rel="nofollow" target="#" href="https://twitter.com/intent/tweet?text={{ news.get_full_url() }}" class="twitter fa-brands fa-twitter-square fa-2x"></a>
{%- endmacro %}
{% macro user_mini_profile(user) %} {% macro user_mini_profile(user) %}
<div class="user_mini_profile"> <div class="user_mini_profile">
<div class="user_mini_profile_infos"> <div class="user_mini_profile_infos">