diff --git a/club/forms.py b/club/forms.py
index 80d4c058..57ab91da 100644
--- a/club/forms.py
+++ b/club/forms.py
@@ -31,20 +31,10 @@ from django.forms.models import ModelChoiceField, ModelChoiceIterator
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
-from club.models import (
- Club,
- ClubLink,
- ClubRole,
- Mailing,
- MailingSubscription,
- Membership,
-)
+from club.models import Club, ClubLink, ClubRole, Membership
from core.models import User
from core.views.forms import SelectDateTime
-from core.views.widgets.ajax_select import (
- AutoCompleteSelectMultipleUser,
- AutoCompleteSelectUser,
-)
+from core.views.widgets.ajax_select import AutoCompleteSelectUser
from counter.models import Counter, Selling
from counter.schemas import SaleFilterSchema
@@ -131,107 +121,6 @@ class ClubAdminEditForm(ClubEditForm):
fields = ["name", "parent", "is_active", *ClubEditForm.Meta.fields]
-class MailingForm(forms.Form):
- """Form handling mailing lists right."""
-
- ACTION_NEW_MAILING = 1
- ACTION_NEW_SUBSCRIPTION = 2
- ACTION_REMOVE_SUBSCRIPTION = 3
-
- subscription_users = forms.ModelMultipleChoiceField(
- label=_("Users to add"),
- help_text=_("Search users to add (one or more)."),
- required=False,
- widget=AutoCompleteSelectMultipleUser,
- queryset=User.objects.all(),
- )
-
- def __init__(self, club_id, user_id, mailings, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.fields["action"] = forms.TypedChoiceField(
- choices=(
- (self.ACTION_NEW_MAILING, _("New Mailing")),
- (self.ACTION_NEW_SUBSCRIPTION, _("Subscribe")),
- (self.ACTION_REMOVE_SUBSCRIPTION, _("Remove")),
- ),
- coerce=int,
- label=_("Action"),
- initial=1,
- required=True,
- widget=forms.HiddenInput(),
- )
-
- # Generate bulk removal forms, they are never required
- for mailing in mailings:
- self.fields["removal_" + str(mailing.id)] = forms.ModelMultipleChoiceField(
- mailing.subscriptions.all(),
- label=_("Remove"),
- required=False,
- widget=forms.CheckboxSelectMultiple,
- )
-
- # Include fields for handling mailing creation
- mailing_fields = ("email",)
- self.fields.update(forms.fields_for_model(Mailing, fields=mailing_fields))
- for field in mailing_fields:
- self.fields["mailing_" + field] = self.fields.pop(field)
- self.fields["mailing_" + field].required = False
-
- # Include fields for handling subscription creation
- subscription_fields = ("mailing", "email")
- self.fields.update(
- forms.fields_for_model(MailingSubscription, fields=subscription_fields)
- )
- for field in subscription_fields:
- self.fields["subscription_" + field] = self.fields.pop(field)
- self.fields["subscription_" + field].required = False
-
- self.fields["subscription_mailing"].queryset = Mailing.objects.filter(
- club__id=club_id, is_moderated=True
- )
-
- def check_required(self, cleaned_data, field):
- """If the given field doesn't exist or has no value, add a required error on it."""
- if not cleaned_data.get(field, None):
- self.add_error(field, _("This field is required"))
-
- def clean_subscription_users(self):
- """Convert given users into real users and check their validity."""
- cleaned_data = super().clean()
- users = []
- for user in cleaned_data["subscription_users"]:
- if not user.email:
- raise forms.ValidationError(
- _("One of the selected users doesn't have an email address"),
- code="invalid",
- )
- users.append(user)
- return users
-
- def clean(self):
- cleaned_data = super().clean()
-
- if "action" not in cleaned_data:
- # If there is no action provided, we can stop here
- raise forms.ValidationError(_("An action is required"), code="invalid")
-
- if cleaned_data["action"] == self.ACTION_NEW_MAILING:
- self.check_required(cleaned_data, "mailing_email")
-
- if cleaned_data["action"] == self.ACTION_NEW_SUBSCRIPTION:
- self.check_required(cleaned_data, "subscription_mailing")
- if not cleaned_data.get(
- "subscription_users", None
- ) and not cleaned_data.get("subscription_email", None):
- raise forms.ValidationError(
- _("You must specify at least an user or an email address"),
- code="invalid",
- )
-
- return cleaned_data
-
-
class SellingsForm(forms.Form):
begin_date = forms.DateTimeField(
label=_("Begin date"), widget=SelectDateTime, required=False
diff --git a/club/migrations/0019_remove_mailingsubscription_mailing_and_more.py b/club/migrations/0019_remove_mailingsubscription_mailing_and_more.py
new file mode 100644
index 00000000..de4046c6
--- /dev/null
+++ b/club/migrations/0019_remove_mailingsubscription_mailing_and_more.py
@@ -0,0 +1,16 @@
+# Generated by Django 5.2.17 on 2026-10-15 13:13
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+ dependencies = [("club", "0018_clubrole_linked_groups")]
+
+ operations = [
+ migrations.AlterUniqueTogether(
+ name="mailingsubscription", unique_together=None
+ ),
+ migrations.RemoveField(model_name="mailingsubscription", name="user"),
+ migrations.DeleteModel(name="Mailing"),
+ migrations.DeleteModel(name="MailingSubscription"),
+ ]
diff --git a/club/models.py b/club/models.py
index 6c2baec8..90648804 100644
--- a/club/models.py
+++ b/club/models.py
@@ -28,8 +28,7 @@ from functools import reduce
from typing import Iterable, Self
from django.conf import settings
-from django.core.exceptions import ObjectDoesNotExist, ValidationError
-from django.core.validators import RegexValidator, validate_email
+from django.core.exceptions import ValidationError
from django.db import ProgrammingError, models, transaction
from django.db.models import Exists, F, OuterRef, Q
from django.urls import reverse
@@ -41,7 +40,7 @@ from django.utils.translation import gettext_lazy as _
from ordered_model.models import OrderedModel
from core.fields import ResizedImageField
-from core.models import Group, Notification, Page, SithFile, User
+from core.models import Group, Page, SithFile, User
class ClubQuerySet(models.QuerySet):
@@ -633,169 +632,6 @@ class Membership(models.Model):
return User.groups.through.objects.bulk_create(groups, ignore_conflicts=True)
-class Mailing(models.Model):
- """A Mailing list for a club.
-
- Warning:
- Remember that mailing lists should be validated by UTBM.
- """
-
- club = models.ForeignKey(
- Club,
- verbose_name=_("Club"),
- related_name="mailings",
- null=False,
- blank=False,
- on_delete=models.CASCADE,
- )
- email = models.CharField(
- _("Email address"),
- unique=True,
- null=False,
- blank=False,
- max_length=256,
- validators=[
- RegexValidator(
- validate_email.user_regex,
- _("Enter a valid address. Only the root of the address is needed."),
- )
- ],
- )
- is_moderated = models.BooleanField(_("is moderated"), default=False)
- moderator = models.ForeignKey(
- User,
- related_name="moderated_mailings",
- verbose_name=_("moderator"),
- null=True,
- on_delete=models.CASCADE,
- )
-
- def __str__(self):
- return "%s - %s" % (self.club, self.email_full)
-
- def save(self, *args, **kwargs):
- if not self.is_moderated:
- unread_notif_subquery = Notification.objects.filter(
- user=OuterRef("pk"), type="MAILING_MODERATION", viewed=False
- )
- for user in User.objects.filter(
- ~Exists(unread_notif_subquery),
- groups__id__in=[settings.SITH_GROUP_COM_ADMIN_ID],
- ):
- Notification(
- user=user,
- url=reverse("com:mailing_admin"),
- type="MAILING_MODERATION",
- ).save(*args, **kwargs)
- super().save(*args, **kwargs)
-
- def clean(self):
- if Mailing.objects.filter(email=self.email).exists():
- raise ValidationError(_("This mailing list already exists."))
- if self.can_moderate(self.moderator):
- self.is_moderated = True
- else:
- self.moderator = None
- super().clean()
-
- @property
- def email_full(self):
- return self.email + "@" + settings.SITH_MAILING_DOMAIN
-
- def can_moderate(self, user):
- return user.is_root or user.is_com_admin
-
- def is_owned_by(self, user):
- if user.is_anonymous:
- return False
- return user.is_root or user.is_com_admin
-
- def can_view(self, user):
- return self.club.has_rights_in_club(user)
-
- def can_be_edited_by(self, user):
- return self.club.has_rights_in_club(user)
-
- def delete(self, *args, **kwargs):
- self.subscriptions.all().delete()
- super().delete()
-
- def fetch_format(self):
- destination = "".join(s.fetch_format() for s in self.subscriptions.all())
- return f"{self.email}: {destination}"
-
-
-class MailingSubscription(models.Model):
- """Link between user and mailing list."""
-
- mailing = models.ForeignKey(
- Mailing,
- verbose_name=_("Mailing"),
- related_name="subscriptions",
- null=False,
- blank=False,
- on_delete=models.CASCADE,
- )
- user = models.ForeignKey(
- User,
- verbose_name=_("User"),
- related_name="mailing_subscriptions",
- null=True,
- blank=True,
- on_delete=models.CASCADE,
- )
- email = models.EmailField(_("Email address"), blank=False, null=False)
-
- class Meta:
- unique_together = (("user", "email", "mailing"),)
-
- def __str__(self):
- return "(%s) - %s : %s" % (self.mailing, self.get_username, self.email)
-
- def clean(self):
- if not self.user and not self.email:
- raise ValidationError(_("At least user or email is required"))
- try:
- if self.user and not self.email:
- self.email = self.user.email
- if MailingSubscription.objects.filter(
- mailing=self.mailing, email=self.email
- ).exists():
- raise ValidationError(
- _("This email is already suscribed in this mailing")
- )
- except ObjectDoesNotExist:
- pass
- super().clean()
-
- def is_owned_by(self, user):
- if user.is_anonymous:
- return False
- return (
- self.mailing.club.has_rights_in_club(user)
- or user.is_root
- or self.user.is_com_admin
- )
-
- def can_be_edited_by(self, user):
- return self.user is not None and user.id == self.user.id
-
- @cached_property
- def get_email(self):
- if self.user and not self.email:
- return self.user.email
- return self.email
-
- @cached_property
- def get_username(self):
- if self.user:
- return str(self.user)
- return _("Unregistered user")
-
- def fetch_format(self):
- return self.get_email + " "
-
-
class LinkType(models.Model):
"""A link type, in order to group links and give them icons.
diff --git a/club/templates/club/club_tools.jinja b/club/templates/club/club_tools.jinja
index a69d5c26..3c4e2e6e 100644
--- a/club/templates/club/club_tools.jinja
+++ b/club/templates/club/club_tools.jinja
@@ -15,9 +15,6 @@
{% trans %}Post in the Weekmail{% endtrans %}
- {% if object.can_roles_be_edited_by(user) %}
-
- {% endif %}
{% if object.trombi %}
{% trans %}Edit Trombi{% endtrans %}
{% else %}
diff --git a/club/templates/club/mailing.jinja b/club/templates/club/mailing.jinja
deleted file mode 100644
index a7421602..00000000
--- a/club/templates/club/mailing.jinja
+++ /dev/null
@@ -1,108 +0,0 @@
-{% extends "core/base.jinja" %}
-{% from 'core/macros.jinja' import select_all_checkbox %}
-
-{% block title %}
- {% trans %}Mailing lists{% endtrans %}
-{% endblock %}
-
-{% block content %}
-
- {% trans %}Remember : mailing lists need to be moderated, if your new created list is not shown wait until moderation takes action{% endtrans %}
-
- {% if mailings_not_moderated %}
- {% trans %}Mailing lists waiting for moderation{% endtrans %}
-
- {% endif %}
-
- {% if mailings_moderated %}
- {% for mailing in mailings_moderated %}
- {% trans %}Mailing{% endtrans %} {{ mailing.email_full }}
- {%- if user.is_owner(mailing) -%}
- - {% trans %}Delete{% endtrans %}
- {%- endif -%}
-
-
- {% set form_mailing_removal = form["removal_" + mailing.id|string] %}
- {% if form_mailing_removal.field.choices %}
- {% set ms = dict(mailing.subscriptions.all() | groupby('id')) %}
-
-
- {% else %}
- {% trans %}There is no subscriber for this mailing list{% endtrans %}
- {% endif %}
- {% endfor %}
-
- {% else %}
- {% trans %}No mailing list existing for this club{% endtrans %}
- {% endif %}
-
- {{ form.non_field_errors() }}
- {% if mailings_moderated %}
- {% trans %}New member{% endtrans %}
-
- {% endif %}
-
- {% trans %}New mailing{% endtrans %}
-
-
-{% endblock %}
diff --git a/club/tests/test_mailing.py b/club/tests/test_mailing.py
deleted file mode 100644
index 2217281c..00000000
--- a/club/tests/test_mailing.py
+++ /dev/null
@@ -1,328 +0,0 @@
-from django.conf import settings
-from django.test import TestCase
-from django.urls import reverse
-from django.utils import timezone
-from django.utils.translation import gettext as _
-from model_bakery import baker
-
-from club.forms import MailingForm
-from club.models import Club, ClubRole, Mailing, Membership
-from core.models import User
-
-
-class TestMailingForm(TestCase):
- """Perform validation tests for MailingForm."""
-
- @classmethod
- def setUpTestData(cls):
- cls.skia = User.objects.get(username="skia")
- cls.rbatsbak = User.objects.get(username="rbatsbak")
- cls.krophil = User.objects.get(username="krophil")
- cls.comunity = User.objects.get(username="comunity")
- cls.root = User.objects.get(username="root")
- cls.club = Club.objects.get(id=settings.SITH_PDF_CLUB_ID)
- cls.mail_url = reverse("club:mailing", kwargs={"club_id": cls.club.id})
- Membership(
- user=cls.rbatsbak,
- club=cls.club,
- start_date=timezone.now(),
- role=baker.make(ClubRole, club=cls.club, is_board=True),
- ).save()
-
- def test_mailing_list_add_no_moderation(self):
- # Test with Communication admin
- self.client.force_login(self.comunity)
- response = self.client.post(
- self.mail_url,
- {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "foyer"},
- )
- self.assertRedirects(response, self.mail_url)
- response = self.client.get(self.mail_url)
- assert response.status_code == 200
- assert "Liste de diffusion foyer@utbm.fr" in response.text
-
- # Test with Root
- self.client.force_login(self.root)
- self.client.post(
- self.mail_url,
- {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"},
- )
- response = self.client.get(self.mail_url)
- assert response.status_code == 200
- assert "Liste de diffusion mde@utbm.fr" in response.text
-
- def test_mailing_list_add_moderation(self):
- self.client.force_login(self.rbatsbak)
- self.client.post(
- self.mail_url,
- {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"},
- )
- response = self.client.get(self.mail_url)
- assert response.status_code == 200
- content = response.text
- assert "Liste de diffusion mde@utbm.fr" not in content
- assert "Listes de diffusions en attente de modération
" in content
- assert "mde@utbm.fr" in content
-
- def test_mailing_list_forbidden(self):
- # With anonymous user
- response = self.client.get(self.mail_url)
- self.assertContains(response, "", status_code=403)
-
- # With user not in club
- self.client.force_login(self.krophil)
- response = self.client.get(self.mail_url)
- assert response.status_code == 403
-
- def test_add_new_subscription_fail_not_moderated(self):
- self.client.force_login(self.rbatsbak)
- self.client.post(
- self.mail_url,
- {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"},
- )
-
- self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_NEW_SUBSCRIPTION,
- "subscription_users": self.skia.id,
- "subscription_mailing": Mailing.objects.get(email="mde").id,
- },
- )
- response = self.client.get(self.mail_url)
- assert response.status_code == 200
- assert "skia@git.an" not in response.text
-
- def test_add_new_subscription_success(self):
- # Prepare mailing list
- self.client.force_login(self.comunity)
- self.client.post(
- self.mail_url,
- {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"},
- )
-
- # Add single user
- self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_NEW_SUBSCRIPTION,
- "subscription_users": self.skia.id,
- "subscription_mailing": Mailing.objects.get(email="mde").id,
- },
- )
- response = self.client.get(self.mail_url)
- assert response.status_code == 200
- assert "skia@git.an" in response.text
-
- # Add multiple users
- self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_NEW_SUBSCRIPTION,
- "subscription_users": (self.comunity.id, self.rbatsbak.id),
- "subscription_mailing": Mailing.objects.get(email="mde").id,
- },
- )
- response = self.client.get(self.mail_url)
- assert response.status_code == 200
- content = response.text
- assert "richard@git.an" in content
- assert "comunity@git.an" in content
- assert "skia@git.an" in content
-
- # Add arbitrary email
- self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_NEW_SUBSCRIPTION,
- "subscription_email": "arbitrary@git.an",
- "subscription_mailing": Mailing.objects.get(email="mde").id,
- },
- )
- response = self.client.get(self.mail_url)
- assert response.status_code == 200
- content = response.text
- assert "richard@git.an" in content
- assert "comunity@git.an" in content
- assert "skia@git.an" in content
- assert "arbitrary@git.an" in content
-
- # Add user and arbitrary email
- self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_NEW_SUBSCRIPTION,
- "subscription_email": "more.arbitrary@git.an",
- "subscription_users": self.krophil.id,
- "subscription_mailing": Mailing.objects.get(email="mde").id,
- },
- )
- response = self.client.get(self.mail_url)
- assert response.status_code == 200
- content = response.text
- assert "richard@git.an" in content
- assert "comunity@git.an" in content
- assert "skia@git.an" in content
- assert "arbitrary@git.an" in content
- assert "more.arbitrary@git.an" in content
- assert "krophil@git.an" in content
-
- def test_add_new_subscription_fail_form_errors(self):
- # Prepare mailing list
- self.client.force_login(self.comunity)
- self.client.post(
- self.mail_url,
- {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"},
- )
-
- # Neither email or email is specified
- response = self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_NEW_SUBSCRIPTION,
- "subscription_mailing": Mailing.objects.get(email="mde").id,
- },
- )
- assert response.status_code
- self.assertInHTML(
- _("You must specify at least an user or an email address"),
- response.text,
- )
-
- # No mailing specified
- response = self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_NEW_SUBSCRIPTION,
- "subscription_users": self.krophil.id,
- },
- )
- assert response.status_code == 200
- assert _("This field is required") in response.text
-
- # One of the selected users doesn't exist
- response = self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_NEW_SUBSCRIPTION,
- "subscription_users": [789],
- "subscription_mailing": Mailing.objects.get(email="mde").id,
- },
- )
- assert response.status_code == 200
- self.assertInHTML(
- _("You must specify at least an user or an email address"),
- response.text,
- )
-
- # An user has no email address
- self.krophil.email = ""
- self.krophil.save()
-
- response = self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_NEW_SUBSCRIPTION,
- "subscription_users": self.krophil.id,
- "subscription_mailing": Mailing.objects.get(email="mde").id,
- },
- )
- assert response.status_code == 200
- self.assertInHTML(
- _("One of the selected users doesn't have an email address"),
- response.text,
- )
-
- self.krophil.email = "krophil@git.an"
- self.krophil.save()
-
- # An user is added twice
-
- self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_NEW_SUBSCRIPTION,
- "subscription_users": self.krophil.id,
- "subscription_mailing": Mailing.objects.get(email="mde").id,
- },
- )
-
- response = self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_NEW_SUBSCRIPTION,
- "subscription_users": self.krophil.id,
- "subscription_mailing": Mailing.objects.get(email="mde").id,
- },
- )
- assert response.status_code == 200
- self.assertInHTML(
- _("This email is already suscribed in this mailing"),
- response.text,
- )
-
- def test_remove_subscription_success(self):
- # Prepare mailing list
- self.client.force_login(self.comunity)
- self.client.post(
- self.mail_url,
- {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"},
- )
- mde = Mailing.objects.get(email="mde")
- self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_NEW_SUBSCRIPTION,
- "subscription_users": (
- self.comunity.id,
- self.rbatsbak.id,
- self.krophil.id,
- ),
- "subscription_mailing": mde.id,
- },
- )
-
- response = self.client.get(self.mail_url)
- assert response.status_code == 200
- content = response.text
-
- assert "comunity@git.an" in content
- assert "richard@git.an" in content
- assert "krophil@git.an" in content
-
- # Delete one user
- self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_REMOVE_SUBSCRIPTION,
- "removal_%d" % mde.id: mde.subscriptions.get(user=self.krophil).id,
- },
- )
- response = self.client.get(self.mail_url)
- assert response.status_code == 200
- content = response.text
-
- assert "comunity@git.an" in content
- assert "richard@git.an" in content
- assert "krophil@git.an" not in content
-
- # Delete multiple users
- self.client.post(
- self.mail_url,
- {
- "action": MailingForm.ACTION_REMOVE_SUBSCRIPTION,
- "removal_%d" % mde.id: [
- user.id
- for user in mde.subscriptions.filter(
- user__in=[self.rbatsbak, self.comunity]
- ).all()
- ],
- },
- )
- response = self.client.get(self.mail_url)
- assert response.status_code == 200
- content = response.text
-
- assert "comunity@git.an" not in content
- assert "richard@git.an" not in content
- assert "krophil@git.an" not in content
diff --git a/club/urls.py b/club/urls.py
index 6a08bbe5..3195b1ae 100644
--- a/club/urls.py
+++ b/club/urls.py
@@ -29,7 +29,6 @@ from club.views import (
ClubCreateView,
ClubEditView,
ClubListView,
- ClubMailingView,
ClubMembersView,
ClubOldMembersView,
ClubPageEditView,
@@ -43,9 +42,6 @@ from club.views import (
ClubSellingView,
ClubToolsView,
ClubView,
- MailingAutoGenerationView,
- MailingDeleteView,
- MailingSubscriptionDeleteView,
MembershipDeleteView,
MembershipSetOldView,
PosterCreateView,
@@ -96,22 +92,6 @@ urlpatterns = [
"/sellings/csv/", ClubSellingCSVView.as_view(), name="sellings_csv"
),
path("/tools/", ClubToolsView.as_view(), name="tools"),
- path("/mailing/", ClubMailingView.as_view(), name="mailing"),
- path(
- "/mailing/generate/",
- MailingAutoGenerationView.as_view(),
- name="mailing_generate",
- ),
- path(
- "/mailing/delete/",
- MailingDeleteView.as_view(),
- name="mailing_delete",
- ),
- path(
- "/mailing/delete/subscription/",
- MailingSubscriptionDeleteView.as_view(),
- name="mailing_subscription_delete",
- ),
path(
"membership//set_old/",
MembershipSetOldView.as_view(),
diff --git a/club/views.py b/club/views.py
index 6f2c7716..c9f4f28e 100644
--- a/club/views.py
+++ b/club/views.py
@@ -34,7 +34,6 @@ from django.contrib.auth.mixins import (
UserPassesTestMixin,
)
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.functions import Length
@@ -59,7 +58,6 @@ from club.forms import (
ClubRoleFormSet,
ClubSearchForm,
JoinClubForm,
- MailingForm,
SellingsForm,
)
from club.models import (
@@ -67,8 +65,6 @@ from club.models import (
ClubLink,
ClubRole,
LinkType,
- Mailing,
- MailingSubscription,
Membership,
)
from com.models import Poster
@@ -181,13 +177,6 @@ class ClubTabsMixin(TabedViewMixin):
"slug": "sellings",
"name": _("Sellings"),
},
- {
- "url": reverse(
- "club:mailing", kwargs={"club_id": self.object.id}
- ),
- "slug": "mailing",
- "name": _("Mailing list"),
- },
{
"url": reverse(
"club:poster_list", kwargs={"club_id": self.object.id}
@@ -742,166 +731,6 @@ class MembershipDeleteView(PermissionRequiredMixin, DeleteView):
return reverse_lazy("core:user_clubs", kwargs={"user_id": self.object.user_id})
-class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView):
- """A list of mailing for a given club."""
-
- model = Club
- form_class = MailingForm
- pk_url_kwarg = "club_id"
- template_name = "club/mailing.jinja"
- current_tab = "mailing"
-
- def get_form_kwargs(self):
- kwargs = super().get_form_kwargs()
- kwargs["club_id"] = self.object.id
- kwargs["user_id"] = self.request.user.id
- kwargs["mailings"] = self.object.mailings.all()
- return kwargs
-
- def get_context_data(self, **kwargs):
- kwargs = super().get_context_data(**kwargs)
- mailings = list(self.object.mailings.all())
- kwargs["club"] = self.object
- kwargs["user"] = self.request.user
- kwargs["mailings"] = mailings
- kwargs["mailings_moderated"] = [m for m in mailings if m.is_moderated]
- kwargs["mailings_not_moderated"] = [m for m in mailings if not m.is_moderated]
- kwargs["form_actions"] = {
- "NEW_MALING": self.form_class.ACTION_NEW_MAILING,
- "NEW_SUBSCRIPTION": self.form_class.ACTION_NEW_SUBSCRIPTION,
- "REMOVE_SUBSCRIPTION": self.form_class.ACTION_REMOVE_SUBSCRIPTION,
- }
- return kwargs
-
- def add_new_mailing(self, cleaned_data) -> ValidationError | None:
- """Create a new mailing list from the form."""
- mailing = Mailing(
- club=self.object,
- email=cleaned_data["mailing_email"],
- moderator=self.request.user,
- is_moderated=False,
- )
- try:
- mailing.clean()
- except ValidationError as validation_error:
- return validation_error
- mailing.save()
- return None
-
- def add_new_subscription(self, cleaned_data) -> ValidationError | None:
- """Add mailing subscriptions for each user given and/or for the specified email in form."""
- users_to_save = []
-
- for user in cleaned_data["subscription_users"]:
- sub = MailingSubscription(
- mailing=cleaned_data["subscription_mailing"], user=user
- )
- try:
- sub.clean()
- except ValidationError as validation_error:
- return validation_error
-
- sub.save()
- users_to_save.append(sub)
-
- if cleaned_data["subscription_email"]:
- sub = MailingSubscription(
- mailing=cleaned_data["subscription_mailing"],
- email=cleaned_data["subscription_email"],
- )
-
- try:
- sub.clean()
- except ValidationError as validation_error:
- return validation_error
- sub.save()
-
- # Save users after we are sure there is no error
- for user in users_to_save:
- user.save()
-
- return None
-
- def remove_subscription(self, cleaned_data):
- """Remove specified users from a mailing list."""
- fields = [
- val for key, val in cleaned_data.items() if key.startswith("removal_")
- ]
- for field in fields:
- for sub in field:
- sub.delete()
-
- def form_valid(self, form):
- resp = super().form_valid(form)
-
- cleaned_data = form.clean()
- error = None
-
- if cleaned_data["action"] == self.form_class.ACTION_NEW_MAILING:
- error = self.add_new_mailing(cleaned_data)
-
- if cleaned_data["action"] == self.form_class.ACTION_NEW_SUBSCRIPTION:
- error = self.add_new_subscription(cleaned_data)
-
- if cleaned_data["action"] == self.form_class.ACTION_REMOVE_SUBSCRIPTION:
- self.remove_subscription(cleaned_data)
-
- if error:
- form.add_error(NON_FIELD_ERRORS, error)
- return self.form_invalid(form)
-
- return resp
-
- def get_success_url(self, **kwargs):
- return reverse("club:mailing", kwargs={"club_id": self.object.id})
-
-
-class MailingDeleteView(CanEditMixin, DeleteView):
- model = Mailing
- template_name = "core/delete_confirm.jinja"
- pk_url_kwarg = "mailing_id"
- redirect_page = None
-
- def dispatch(self, request, *args, **kwargs):
- self.club_id = self.get_object().club.id
- return super().dispatch(request, *args, **kwargs)
-
- def get_success_url(self, **kwargs):
- if self.redirect_page:
- return reverse_lazy(self.redirect_page)
- else:
- return reverse_lazy("club:mailing", kwargs={"club_id": self.club_id})
-
-
-class MailingSubscriptionDeleteView(CanEditMixin, DeleteView):
- model = MailingSubscription
- template_name = "core/delete_confirm.jinja"
- pk_url_kwarg = "mailing_subscription_id"
-
- def dispatch(self, request, *args, **kwargs):
- self.club_id = self.get_object().mailing.club.id
- return super().dispatch(request, *args, **kwargs)
-
- def get_success_url(self, **kwargs):
- return reverse_lazy("club:mailing", kwargs={"club_id": self.club_id})
-
-
-class MailingAutoGenerationView(View):
- def dispatch(self, request, *args, **kwargs):
- self.mailing = get_object_or_404(Mailing, pk=kwargs["mailing_id"])
- if not request.user.can_edit(self.mailing):
- raise PermissionDenied
- return super().dispatch(request, *args, **kwargs)
-
- def get(self, request, *args, **kwargs):
- club = self.mailing.club
- self.mailing.subscriptions.all().delete()
- members = club.members.ongoing().filter(role__is_board=True)
- for member in members.all():
- MailingSubscription(user=member.user, mailing=self.mailing).save()
- return redirect("club:mailing", club_id=club.id)
-
-
class PosterListView(
PermissionOrClubBoardRequiredMixin, ClubTabsMixin, PosterListBaseView
):
diff --git a/com/models.py b/com/models.py
index 6a9100b5..3f3e332a 100644
--- a/com/models.py
+++ b/com/models.py
@@ -259,10 +259,7 @@ class Weekmail(models.Model):
return f"Weekmail {self.id} (sent: {self.sent}) - {self.title}"
def send(self):
- """Send the weekmail to all users with the receive weekmail option opt-in.
-
- Also send the weekmail to the mailing list in settings.SITH_COM_EMAIL.
- """
+ """Send the weekmail to all users with the receive weekmail option opt-in."""
dest = [
i[0]
for i in Preferences.objects.filter(receive_weekmail=True).values_list(
diff --git a/com/templates/com/mailing_admin.jinja b/com/templates/com/mailing_admin.jinja
deleted file mode 100644
index 3096e435..00000000
--- a/com/templates/com/mailing_admin.jinja
+++ /dev/null
@@ -1,45 +0,0 @@
-{% extends "core/base.jinja" %}
-
-{% block title %}
- {% trans %}Mailing lists administration{% endtrans %}
-{% endblock %}
-
-{% macro display_mailings(list) %}
-
-
-{% endmacro %}
-
-{% block content %}
- {% trans %}This page lists all mailing lists{% endtrans %}
-
- {% if has_unmoderated %}
- {% trans %}Not moderated mailing lists{% endtrans %}
- {{ display_mailings(unmoderated) }}
- {% endif %}
-
- {% trans %}Moderated mailing lists{% endtrans %}
- {% if has_moderated %}
- {{ display_mailings(moderated) }}
- {% else %}
- {% trans %}No mailing list existing{% endtrans %}
- {% endif %}
-
-{% endblock %}
-
-
-
diff --git a/com/urls.py b/com/urls.py
index 51861316..d94b0f50 100644
--- a/com/urls.py
+++ b/com/urls.py
@@ -15,12 +15,9 @@
from django.urls import path
-from club.views import MailingDeleteView
from com.views import (
AlertMsgEditView,
InfoMsgEditView,
- MailingListAdminView,
- MailingModerateView,
NewsAdminListView,
NewsCreateView,
NewsDeleteView,
@@ -82,17 +79,6 @@ urlpatterns = [
"news//moderate/", NewsModerateView.as_view(), name="news_moderate"
),
path("news//", NewsDetailView.as_view(), name="news_detail"),
- path("mailings/", MailingListAdminView.as_view(), name="mailing_admin"),
- path(
- "mailings//moderate/",
- MailingModerateView.as_view(),
- name="mailing_moderate",
- ),
- path(
- "mailings//delete/",
- MailingDeleteView.as_view(redirect_page="com:mailing_admin"),
- name="mailing_delete",
- ),
path("poster/", PosterListView.as_view(), name="poster_list"),
path("poster/create/", PosterCreateView.as_view(), name="poster_create"),
path("poster//edit/", PosterEditView.as_view(), name="poster_edit"),
diff --git a/com/views.py b/com/views.py
index 82075aa8..9f845370 100644
--- a/com/views.py
+++ b/com/views.py
@@ -30,11 +30,9 @@ from urllib.parse import urlparse
from dateutil.relativedelta import relativedelta
from django.conf import settings
from django.contrib import messages
-from django.contrib.auth.mixins import (
- PermissionRequiredMixin,
-)
+from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.syndication.views import Feed
-from django.core.exceptions import PermissionDenied, ValidationError
+from django.core.exceptions import ValidationError
from django.db.models import Exists, Max, OuterRef, Value
from django.forms.models import modelform_factory
from django.http import HttpResponseRedirect
@@ -46,7 +44,7 @@ from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView, TemplateView, View
from django.views.generic.edit import CreateView, DeleteView, UpdateView
-from club.models import Club, Mailing, Membership
+from club.models import Club, Membership
from com.forms import NewsDateForm, NewsForm, PosterForm
from com.ics_calendar import IcsCalendar
from com.models import News, NewsDate, Poster, Screen, Sith, Weekmail, WeekmailArticle
@@ -86,11 +84,6 @@ class ComTabsMixin(TabedViewMixin):
"slug": "alert",
"name": _("Alert message"),
},
- {
- "url": reverse("com:mailing_admin"),
- "slug": "mailings",
- "name": _("Mailing lists administration"),
- },
{
"url": reverse("com:poster_list"),
"slug": "posters",
@@ -533,37 +526,6 @@ class WeekmailArticleDeleteView(CanEditPropMixin, DeleteView):
pk_url_kwarg = "article_id"
-class MailingListAdminView(ComTabsMixin, ListView):
- template_name = "com/mailing_admin.jinja"
- model = Mailing
- current_tab = "mailings"
-
- def dispatch(self, request, *args, **kwargs):
- if not (request.user.is_com_admin or request.user.is_root):
- raise PermissionDenied
- return super().dispatch(request, *args, **kwargs)
-
- def get_context_data(self, **kwargs):
- kwargs = super().get_context_data(**kwargs)
- kwargs["moderated"] = self.get_queryset().filter(is_moderated=True).all()
- kwargs["unmoderated"] = self.get_queryset().filter(is_moderated=False).all()
- kwargs["has_moderated"] = len(kwargs["moderated"]) > 0
- kwargs["has_unmoderated"] = len(kwargs["unmoderated"]) > 0
- return kwargs
-
-
-class MailingModerateView(View):
- def get(self, request, *args, **kwargs):
- mailing = get_object_or_404(Mailing, pk=kwargs["mailing_id"])
- if mailing.can_moderate(request.user):
- mailing.is_moderated = True
- mailing.moderator = request.user
- mailing.save()
- return redirect("com:mailing_admin")
-
- raise PermissionDenied
-
-
class PosterListBaseView(ListView):
"""List communication posters."""
diff --git a/core/api.py b/core/api.py
index d46548f5..075ae5b1 100644
--- a/core/api.py
+++ b/core/api.py
@@ -1,18 +1,15 @@
from typing import Annotated, Literal
from annotated_types import Ge, Le, MinLen
-from django.conf import settings
from django.db.models import F
from ninja import File, Query
from ninja.security import SessionAuth
from ninja_extra import ControllerBase, api_controller, paginate, route
-from ninja_extra.exceptions import PermissionDenied
from ninja_extra.pagination import PageNumberPaginationExtra
from ninja_extra.schemas import PaginatedResponseSchema
from api.auth import ApiKeyAuth
from api.permissions import CanAccessLookup, CanView, HasPerm
-from club.models import Mailing
from core.models import Group, QuickUploadImage, SithFile, User
from core.schemas import (
FamilyGodfatherSchema,
@@ -48,19 +45,6 @@ class UploadController(ControllerBase):
return image
-@api_controller("/mailings")
-class MailingListController(ControllerBase):
- @route.get("", response=str)
- def fetch_mailing_lists(self, key: str):
- if key != settings.SITH_MAILING_FETCH_KEY:
- raise PermissionDenied
- mailings = Mailing.objects.filter(
- is_moderated=True, club__is_active=True
- ).prefetch_related("subscriptions")
- data = "\n".join(m.fetch_format() for m in mailings)
- return data
-
-
@api_controller("/user")
class UserController(ControllerBase):
@route.get("", response=list[UserProfileSchema])
diff --git a/core/templates/core/user_clubs.jinja b/core/templates/core/user_clubs.jinja
index afc6748e..bd352abe 100644
--- a/core/templates/core/user_clubs.jinja
+++ b/core/templates/core/user_clubs.jinja
@@ -79,15 +79,5 @@
{% endfor %}
-
- {% if
- profile.mailing_subscriptions.exists()
- and (profile.id == user.id or user.is_root or user.is_com_admin)
- %}
- {% trans %}Subscribed mailing lists{% endtrans %}
- {% for sub in profile.mailing_subscriptions.all() %}
- {{ sub.mailing.email }} {% trans %}Unsubscribe{% endtrans %}
- {% endfor %}
-{% endif %}
{% endblock %}
diff --git a/core/templates/core/user_tools.jinja b/core/templates/core/user_tools.jinja
index a9fb76b6..9206eca3 100644
--- a/core/templates/core/user_tools.jinja
+++ b/core/templates/core/user_tools.jinja
@@ -133,7 +133,6 @@
{% trans %}Edit alert message{% endtrans %}
{% trans %}Edit information message{% endtrans %}
{% trans %}Moderate files{% endtrans %}
- {% trans %}Mailing lists administration{% endtrans %}
{% trans %}Posters{% endtrans %}
{% trans %}Screens{% endtrans %}
{% endif %}
diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index eadaed9e..a7095881 100644
--- a/locale/fr/LC_MESSAGES/django.po
+++ b/locale/fr/LC_MESSAGES/django.po
@@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-10-09 21:44+0200\n"
+"POT-Creation-Date: 2026-10-15 15:20+0200\n"
"PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Maréchal \n"
@@ -192,46 +192,6 @@ msgstr ""
"arrivée durant l'interaction avec l'application tierce. Veuillez contacter "
"les responsables de cette dernière."
-#: club/forms.py
-msgid "Users to add"
-msgstr "Utilisateurs à ajouter"
-
-#: club/forms.py core/views/group.py
-msgid "Search users to add (one or more)."
-msgstr "Recherche les utilisateurs à ajouter (un ou plus)."
-
-#: club/forms.py
-msgid "New Mailing"
-msgstr "Nouvelle mailing liste"
-
-#: club/forms.py
-msgid "Subscribe"
-msgstr "S'abonner"
-
-#: club/forms.py
-msgid "Remove"
-msgstr "Retirer"
-
-#: club/forms.py counter/forms.py pedagogy/templates/pedagogy/moderation.jinja
-msgid "Action"
-msgstr "Action"
-
-#: club/forms.py club/tests/test_mailing.py
-msgid "This field is required"
-msgstr "Ce champ est obligatoire"
-
-#: club/forms.py club/tests/test_mailing.py
-msgid "One of the selected users doesn't have an email address"
-msgstr "Un des utilisateurs sélectionnés n'a pas d'adresse email"
-
-#: club/forms.py
-msgid "An action is required"
-msgstr "Une action est requise"
-
-#: club/forms.py club/tests/test_mailing.py
-msgid "You must specify at least an user or an email address"
-msgstr "vous devez spécifier au moins un utilisateur ou une adresse email"
-
#: club/forms.py counter/forms.py
msgid "Begin date"
msgstr "Date de début"
@@ -414,60 +374,6 @@ msgstr "rôle"
msgid "past member"
msgstr "ancien membre"
-#: club/models.py com/templates/com/mailing_admin.jinja
-#: com/templates/com/news_admin_list.jinja com/templates/com/weekmail.jinja
-#: core/templates/core/user_clubs.jinja
-#: counter/templates/counter/invoices_call.jinja
-#: trombi/templates/trombi/edit_profile.jinja
-#: trombi/templates/trombi/export.jinja
-#: trombi/templates/trombi/user_profile.jinja
-msgid "Club"
-msgstr "Club"
-
-#: club/models.py
-msgid "Email address"
-msgstr "Adresse email"
-
-#: club/models.py
-msgid "Enter a valid address. Only the root of the address is needed."
-msgstr ""
-"Entrez une adresse valide. Seule la racine de l'adresse est nécessaire."
-
-#: club/models.py com/models.py core/models.py
-msgid "is moderated"
-msgstr "est modéré"
-
-#: club/models.py com/models.py
-msgid "moderator"
-msgstr "modérateur"
-
-#: club/models.py
-msgid "This mailing list already exists."
-msgstr "Cette liste de diffusion existe déjà."
-
-#: club/models.py club/templates/club/mailing.jinja
-msgid "Mailing"
-msgstr "Liste de diffusion"
-
-#: club/models.py club/templates/club/club_members.jinja
-#: club/templates/club/club_old_members.jinja club/templates/club/mailing.jinja
-#: counter/templates/counter/cash_summary_list.jinja
-#: counter/templates/counter/stats.jinja
-msgid "User"
-msgstr "Utilisateur"
-
-#: club/models.py
-msgid "At least user or email is required"
-msgstr "Au moins un utilisateur ou un email est nécessaire"
-
-#: club/models.py club/tests/test_mailing.py
-msgid "This email is already suscribed in this mailing"
-msgstr "Cet email est déjà abonné à cette mailing"
-
-#: club/models.py
-msgid "Unregistered user"
-msgstr "Utilisateur non enregistré"
-
#: club/models.py
msgid "The base url that links with this type must respect"
msgstr "L'url de base que tous les liens de ce type doivent respecter"
@@ -554,6 +460,13 @@ msgstr "Membres du club"
msgid "Manage roles"
msgstr "Gérer les rôles"
+#: club/templates/club/club_members.jinja
+#: club/templates/club/club_old_members.jinja
+#: counter/templates/counter/cash_summary_list.jinja
+#: counter/templates/counter/stats.jinja
+msgid "User"
+msgstr "Utilisateur"
+
#: club/templates/club/club_members.jinja
#: club/templates/club/club_old_members.jinja
#: core/templates/core/user_clubs.jinja
@@ -817,8 +730,7 @@ msgstr "Total"
msgid "Payment method"
msgstr "Méthode de paiement"
-#: club/templates/club/club_sellings.jinja club/templates/club/mailing.jinja
-#: com/templates/com/macros.jinja com/templates/com/mailing_admin.jinja
+#: club/templates/club/club_sellings.jinja com/templates/com/macros.jinja
#: com/templates/com/news_admin_list.jinja com/templates/com/poster_edit.jinja
#: com/templates/com/screen_edit.jinja com/templates/com/weekmail.jinja
#: core/templates/core/file_detail.jinja
@@ -944,60 +856,6 @@ msgstr "Ajouter"
msgid "Join"
msgstr "Rejoindre"
-#: club/templates/club/mailing.jinja
-msgid "Mailing lists"
-msgstr "Mailing listes"
-
-#: club/templates/club/mailing.jinja
-msgid ""
-"Remember : mailing lists need to be moderated, if your new created list is "
-"not shown wait until moderation takes action"
-msgstr ""
-"Rappelez vous : les mailing listes doivent être modérées, si votre liste "
-"nouvellement créée n'est pas affichée, attendez jusqu'à ce qu'un modérateur "
-"prenne une décision"
-
-#: club/templates/club/mailing.jinja
-msgid "Mailing lists waiting for moderation"
-msgstr "Listes de diffusions en attente de modération"
-
-#: club/templates/club/mailing.jinja
-msgid "Generate mailing list"
-msgstr "Générer la liste de diffusion"
-
-#: club/templates/club/mailing.jinja com/templates/com/mailing_admin.jinja
-msgid "Email"
-msgstr "Email"
-
-#: club/templates/club/mailing.jinja
-msgid "Remove from mailing list"
-msgstr "Supprimer de la liste de diffusion"
-
-#: club/templates/club/mailing.jinja
-msgid "There is no subscriber for this mailing list"
-msgstr "Il n'y a pas d'abonnés dans cette liste de diffusion"
-
-#: club/templates/club/mailing.jinja
-msgid "No mailing list existing for this club"
-msgstr "Aucune mailing liste n'existe pour ce club"
-
-#: club/templates/club/mailing.jinja
-#: subscription/templates/subscription/subscription.jinja
-msgid "New member"
-msgstr "Nouveau membre"
-
-#: club/templates/club/mailing.jinja
-msgid "Add to mailing list"
-msgstr "Ajouter à la mailing liste"
-
-#: club/templates/club/mailing.jinja
-msgid "New mailing"
-msgstr "Nouvelle liste de diffusion"
-
-#: club/templates/club/mailing.jinja
-msgid "Create mailing list"
-msgstr "Créer une liste de diffusion"
-
#: club/templates/club/pagerev_edit.jinja core/templates/core/page/edit.jinja
msgid "Edit page"
msgstr "Éditer la page"
@@ -1043,10 +901,6 @@ msgstr "Éditer la page de club"
msgid "Sellings"
msgstr "Vente"
-#: club/views.py
-msgid "Mailing list"
-msgstr "Listes de diffusion"
-
#: club/views.py
msgid "You are now a member of this club."
msgstr "Vous êtes maintenant membre de ce club."
@@ -1177,6 +1031,10 @@ msgstr "auteur"
msgid "is published"
msgstr "est publié"
+#: com/models.py
+msgid "moderator"
+msgstr "modérateur"
+
#: com/models.py
msgid "news"
msgstr "nouvelle"
@@ -1237,6 +1095,10 @@ msgstr "fichier"
msgid "display time"
msgstr "temps d'affichage"
+#: com/models.py core/models.py
+msgid "is moderated"
+msgstr "est modéré"
+
#: com/models.py
msgid "Begin date should be before end date"
msgstr "La date de début doit être avant celle de fin"
@@ -1272,46 +1134,6 @@ msgstr "Nouvelle publiée"
msgid "News deleted"
msgstr "Nouvelle supprimée"
-#: com/templates/com/mailing_admin.jinja com/views.py
-#: core/templates/core/user_tools.jinja
-msgid "Mailing lists administration"
-msgstr "Administration des mailing listes"
-
-#: com/templates/com/mailing_admin.jinja
-#: com/templates/com/news_admin_list.jinja com/templates/com/weekmail.jinja
-#: counter/templates/counter/refilling_list.jinja
-msgid "Actions"
-msgstr "Actions"
-
-#: com/templates/com/mailing_admin.jinja com/templates/com/poster_list.jinja
-#: core/templates/core/file_detail.jinja
-#: core/templates/core/file_moderation.jinja
-#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
-#: sas/templates/sas/moderation.jinja sas/templates/sas/picture.jinja
-msgid "Moderate"
-msgstr "Modérer"
-
-#: com/templates/com/mailing_admin.jinja
-#, python-format
-msgid "Moderated by %(user)s"
-msgstr "Modéré par %(user)s"
-
-#: com/templates/com/mailing_admin.jinja
-msgid "This page lists all mailing lists"
-msgstr "Cette page liste toutes les listes de diffusion"
-
-#: com/templates/com/mailing_admin.jinja
-msgid "Not moderated mailing lists"
-msgstr "Listes de diffusion non modérées"
-
-#: com/templates/com/mailing_admin.jinja
-msgid "Moderated mailing lists"
-msgstr "Modérer les listes de diffusion"
-
-#: com/templates/com/mailing_admin.jinja
-msgid "No mailing list existing"
-msgstr "Aucune liste de diffusion existante"
-
#: com/templates/com/news_admin_list.jinja
msgid "News admin"
msgstr "Administration des nouvelles"
@@ -1344,6 +1166,15 @@ msgstr "Titre"
msgid "Summary"
msgstr "Résumé"
+#: com/templates/com/news_admin_list.jinja com/templates/com/weekmail.jinja
+#: core/templates/core/user_clubs.jinja
+#: counter/templates/counter/invoices_call.jinja
+#: trombi/templates/trombi/edit_profile.jinja
+#: trombi/templates/trombi/export.jinja
+#: trombi/templates/trombi/user_profile.jinja
+msgid "Club"
+msgstr "Club"
+
#: com/templates/com/news_admin_list.jinja com/templates/com/weekmail.jinja
#: forum/templates/forum/forum.jinja sas/models.py
msgid "Author"
@@ -1358,6 +1189,11 @@ msgstr "Modérateur"
msgid "Dates"
msgstr "Dates"
+#: com/templates/com/news_admin_list.jinja com/templates/com/weekmail.jinja
+#: counter/templates/counter/refilling_list.jinja
+msgid "Actions"
+msgstr "Actions"
+
#: com/templates/com/news_admin_list.jinja core/templates/core/file.jinja
#: core/templates/core/page/base.jinja
msgid "View"
@@ -1518,6 +1354,13 @@ msgstr "Créer"
msgid "Click to expand"
msgstr "Cliquez pour agrandir"
+#: com/templates/com/poster_list.jinja core/templates/core/file_detail.jinja
+#: core/templates/core/file_moderation.jinja
+#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
+#: sas/templates/sas/moderation.jinja sas/templates/sas/picture.jinja
+msgid "Moderate"
+msgstr "Modérer"
+
#: com/templates/com/poster_list.jinja
msgid "No posters"
msgstr "Aucune affiche"
@@ -2828,14 +2671,6 @@ msgstr "Clubs actuels : "
msgid "Old club(s) :"
msgstr "Anciens clubs :"
-#: core/templates/core/user_clubs.jinja
-msgid "Subscribed mailing lists"
-msgstr "Mailing listes abonnées"
-
-#: core/templates/core/user_clubs.jinja
-msgid "Unsubscribe"
-msgstr "Se désabonner"
-
#: core/templates/core/user_detail.jinja
#, python-format
msgid "%(user_name)s's profile"
@@ -3317,6 +3152,10 @@ msgstr "%s est déjà votre fillot/fillote"
msgid "Users to add to group"
msgstr "Utilisateurs à ajouter au groupe"
+#: core/views/group.py
+msgid "Search users to add (one or more)."
+msgstr "Recherche les utilisateurs à ajouter (un ou plus)."
+
#: core/views/group.py
msgid "Users to remove from group"
msgstr "Utilisateurs à retirer du groupe"
@@ -3416,6 +3255,10 @@ msgstr ""
"temps, mais les utilisateurs suivants ont été définis comme les deux : "
"%(users)s"
+#: counter/forms.py pedagogy/templates/pedagogy/moderation.jinja
+msgid "Action"
+msgstr "Action"
+
#: counter/forms.py
msgid "Date and time of action"
msgstr "Date et heure de l'action"
@@ -5862,10 +5705,6 @@ msgstr "Cursus alternant (-20%)"
msgid "A new poster needs to be moderated"
msgstr "Une nouvelle affiche a besoin d'être modérée"
-#: sith/settings.py
-msgid "A new mailing list needs to be moderated"
-msgstr "Une nouvelle mailing list a besoin d'être modérée"
-
#: sith/settings.py
msgid "A new pedagogy comment has been signaled for moderation"
msgstr ""
@@ -5994,6 +5833,10 @@ msgstr "Toutes les cotisations"
msgid "Existing member"
msgstr "Membre existant"
+#: subscription/templates/subscription/subscription.jinja
+msgid "New member"
+msgstr "Nouveau membre"
+
#: subscription/views.py
msgid "the groups that can create subscriptions"
msgstr "les groupes pouvant créer des cotisations"
diff --git a/sith/settings.py b/sith/settings.py
index 1b81a5c5..ad43323a 100644
--- a/sith/settings.py
+++ b/sith/settings.py
@@ -621,7 +621,6 @@ with open(
SITH_NOTIFICATIONS = [
("POSTER_MODERATION", _("A new poster needs to be moderated")),
- ("MAILING_MODERATION", _("A new mailing list needs to be moderated")),
(
"PEDAGOGY_MODERATION",
_("A new pedagogy comment has been signaled for moderation"),