clubs: add bulk deletion on mailing lists

This commit is contained in:
Antoine Bartuccio 2019-05-01 22:52:22 +02:00
parent 24fb714c5e
commit 1d07195881
Signed by: klmp200
GPG Key ID: E7245548C53F904B
6 changed files with 209 additions and 144 deletions

View File

@ -53,6 +53,7 @@ class MailingForm(forms.Form):
ACTION_NEW_MAILING = 1 ACTION_NEW_MAILING = 1
ACTION_NEW_SUBSCRIPTION = 2 ACTION_NEW_SUBSCRIPTION = 2
ACTION_REMOVE_SUBSCRIPTION = 3
subscription_users = AutoCompleteSelectMultipleField( subscription_users = AutoCompleteSelectMultipleField(
"users", "users",
@ -61,13 +62,14 @@ class MailingForm(forms.Form):
required=False, required=False,
) )
def __init__(self, club_id, user_id, *args, **kwargs): def __init__(self, club_id, user_id, mailings, *args, **kwargs):
super(MailingForm, self).__init__(*args, **kwargs) super(MailingForm, self).__init__(*args, **kwargs)
self.fields["action"] = forms.TypedChoiceField( self.fields["action"] = forms.TypedChoiceField(
( (
(self.ACTION_NEW_MAILING, _("New Mailing")), (self.ACTION_NEW_MAILING, _("New Mailing")),
(self.ACTION_NEW_SUBSCRIPTION, _("Subscribe")), (self.ACTION_NEW_SUBSCRIPTION, _("Subscribe")),
(self.ACTION_REMOVE_SUBSCRIPTION, _("Remove")),
), ),
coerce=int, coerce=int,
label=_("Action"), label=_("Action"),
@ -76,6 +78,15 @@ class MailingForm(forms.Form):
widget=forms.HiddenInput(), 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 # Include fields for handling mailing creation
mailing_fields = ("email", "club", "moderator") mailing_fields = ("email", "club", "moderator")
self.fields.update(forms.fields_for_model(Mailing, fields=mailing_fields)) self.fields.update(forms.fields_for_model(Mailing, fields=mailing_fields))
@ -133,8 +144,6 @@ class MailingForm(forms.Form):
def clean(self): def clean(self):
cleaned_data = super(MailingForm, self).clean() cleaned_data = super(MailingForm, self).clean()
print(cleaned_data)
if not "action" in cleaned_data: if not "action" in cleaned_data:
# If there is no action provided, we can stop here # If there is no action provided, we can stop here
raise forms.ValidationError(_("An action is required"), code="invalid") raise forms.ValidationError(_("An action is required"), code="invalid")

View File

@ -446,18 +446,20 @@ class MailingSubscription(models.Model):
def can_be_edited_by(self, user): def can_be_edited_by(self, user):
return self.user is not None and user.id == self.user.id return self.user is not None and user.id == self.user.id
@property @cached_property
def get_email(self): def get_email(self):
if self.user and not self.email: if self.user and not self.email:
return self.user.email return self.user.email
return self.email return self.email
@cached_property
def get_username(self):
if self.user:
return str(self.user)
return _("Unregistered user")
def fetch_format(self): def fetch_format(self):
return self.get_email + " " return self.get_email + " "
def __str__(self): def __str__(self):
if self.user: return "(%s) - %s : %s" % (self.mailing, self.get_username, self.email)
user = str(self.user)
else:
user = _("Unregistered user")
return "(%s) - %s : %s" % (self.mailing, user, self.email)

View File

@ -1,4 +1,5 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% from 'core/macros.jinja' import select_all_checkbox %}
{% block title %} {% block title %}
{% trans %}Mailing lists{% endtrans %} {% trans %}Mailing lists{% endtrans %}
@ -10,7 +11,6 @@
<b>{% trans %}Remember : mailing lists need to be moderated, if your new created list is not shown wait until moderation takes action{% endtrans %}</b> <b>{% trans %}Remember : mailing lists need to be moderated, if your new created list is not shown wait until moderation takes action{% endtrans %}</b>
{% for mailing in mailings %} {% for mailing in mailings %}
{% if mailing.is_moderated %}
<h2>{% trans %}Mailing{% endtrans %} {{ mailing.email_full }} <h2>{% trans %}Mailing{% endtrans %} {{ mailing.email_full }}
{%- if user.is_owner(mailing) -%} {%- if user.is_owner(mailing) -%}
<a href="{{ url('club:mailing_delete', mailing_id=mailing.id) }}"> - {% trans %}Delete{% endtrans %}</a> <a href="{{ url('club:mailing_delete', mailing_id=mailing.id) }}"> - {% trans %}Delete{% endtrans %}</a>
@ -19,27 +19,38 @@
<form method="GET" action="{{ url('club:mailing_generate', mailing_id=mailing.id) }}" style="display:inline-block;"> <form method="GET" action="{{ url('club:mailing_generate', mailing_id=mailing.id) }}" style="display:inline-block;">
<input type="submit" name="generateMalingList" value="{% trans %}Generate mailing list{% endtrans %}"> <input type="submit" name="generateMalingList" value="{% trans %}Generate mailing list{% endtrans %}">
</form> </form>
<form method="GET" action="{{ url('club:mailing_clean', mailing_id=mailing.id) }}" style="display:inline-block;"> {% set form_mailing_removal = form["removal_" + mailing.id|string] %}
<input type="submit" name="cleanMailingList" value="{% trans %}Clean mailing list{% endtrans %}"> {% if form_mailing_removal.field.choices %}
</form> {% set ms = dict(mailing.subscriptions.all() | groupby('id')) %}
<hr> <form action="{{ url('club:mailing', club_id=club.id) }}" id="{{ form_mailing_removal.auto_id }}" method="post" enctype="multipart/form-data">
<p style="margin-bottom: 1em;">{{ select_all_checkbox(form_mailing_removal.auto_id) }}</p>
{% csrf_token %}
<input hidden type="number" name="{{ form.action.name }}" value="{{ form_actions.REMOVE_SUBSCRIPTION }}" />
<table> <table>
<thead>
<tr> <tr>
<th>{% trans %}User{% endtrans %}</th> <td>{% trans %}User{% endtrans %}</td>
<th colspan="2">{% trans %}Email{%endtrans%}</th> <td>{% trans %}Email{% endtrans %}</td>
<td>{% trans %}Delete{% endtrans %}</td>
</tr> </tr>
{% for subscriber in mailing.subscriptions.all() %} </thead>
<tbody>
{% for widget in form_mailing_removal.subwidgets %}
{% set user = ms[widget.data.value][0] %}
<tr> <tr>
{% if subscriber.user %} <td>{{ user.get_username }}</td>
<td>{{ subscriber.user }}</td> <td>{{ user.get_email }}</td>
{% else %} <td>{{ widget.tag() }}</td>
<td>{% trans %}Unregistered user{% endtrans %}</td>
{% endif %}
<td>{{ subscriber.get_email }}</td>
<td><a href="{{ url('club:mailing_subscription_delete', mailing_subscription_id=subscriber.id) }}">{% trans %}Delete{% endtrans %}</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody>
</table> </table>
{{ form_mailing_removal.errors }}
<p><input type="submit" value="{% trans %}Remove from mailing list{% endtrans %}" /></p>
</form>
{% else %}
<p><b>{% trans %}There is no subscriber for this mailing list{% endtrans %}</b></p>
{% endif %} {% endif %}
{% endfor %} {% endfor %}

View File

@ -70,11 +70,6 @@ urlpatterns = [
MailingAutoGenerationView.as_view(), MailingAutoGenerationView.as_view(),
name="mailing_generate", name="mailing_generate",
), ),
url(
r"^(?P<mailing_id>[0-9]+)/mailing/clean$",
MailingAutoCleanView.as_view(),
name="mailing_clean",
),
url( url(
r"^(?P<mailing_id>[0-9]+)/mailing/delete$", r"^(?P<mailing_id>[0-9]+)/mailing/delete$",
MailingDeleteView.as_view(), MailingDeleteView.as_view(),

View File

@ -513,23 +513,29 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView):
template_name = "club/mailing.jinja" template_name = "club/mailing.jinja"
current_tab = "mailing" current_tab = "mailing"
def get_form_kwargs(self, *args, **kwargs): def get_form_kwargs(self):
kwargs = super(ClubMailingView, self).get_form_kwargs(*args, **kwargs) kwargs = super(ClubMailingView, self).get_form_kwargs()
kwargs["club_id"] = self.get_object().id kwargs["club_id"] = self.get_object().id
kwargs["user_id"] = self.request.user.id kwargs["user_id"] = self.request.user.id
kwargs["mailings"] = self.mailings
return kwargs return kwargs
def dispatch(self, request, *args, **kwargs):
self.mailings = Mailing.objects.filter(club_id=self.get_object().id).all()
return super(ClubMailingView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs = super(ClubMailingView, self).get_context_data(**kwargs) kwargs = super(ClubMailingView, self).get_context_data(**kwargs)
kwargs["club"] = self.get_object() kwargs["club"] = self.get_object()
kwargs["user"] = self.request.user kwargs["user"] = self.request.user
kwargs["mailings"] = Mailing.objects.filter(club_id=self.get_object().id).all() kwargs["mailings"] = self.mailings
kwargs["mailings_moderated"] = ( kwargs["mailings_moderated"] = (
kwargs["mailings"].exclude(is_moderated=False).all() kwargs["mailings"].exclude(is_moderated=False).all()
) )
kwargs["form_actions"] = { kwargs["form_actions"] = {
"NEW_MALING": self.form_class.ACTION_NEW_MAILING, "NEW_MALING": self.form_class.ACTION_NEW_MAILING,
"NEW_SUBSCRIPTION": self.form_class.ACTION_NEW_SUBSCRIPTION, "NEW_SUBSCRIPTION": self.form_class.ACTION_NEW_SUBSCRIPTION,
"REMOVE_SUBSCRIPTION": self.form_class.ACTION_REMOVE_SUBSCRIPTION,
} }
return kwargs return kwargs
@ -565,6 +571,19 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView):
sub.clean() sub.clean()
sub.save() sub.save()
def remove_subscription(self, cleaned_data):
"""
Remove specified users from a mailing list
"""
fields = [
cleaned_data[key]
for key in cleaned_data.keys()
if key.startswith("removal_")
]
for field in fields:
for sub in field:
sub.delete()
def form_valid(self, form): def form_valid(self, form):
resp = super(ClubMailingView, self).form_valid(form) resp = super(ClubMailingView, self).form_valid(form)
@ -576,6 +595,9 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView):
if cleaned_data["action"] == self.form_class.ACTION_NEW_SUBSCRIPTION: if cleaned_data["action"] == self.form_class.ACTION_NEW_SUBSCRIPTION:
self.add_new_subscription(cleaned_data) self.add_new_subscription(cleaned_data)
if cleaned_data["action"] == self.form_class.ACTION_REMOVE_SUBSCRIPTION:
self.remove_subscription(cleaned_data)
return resp return resp
def get_success_url(self, **kwargs): def get_success_url(self, **kwargs):
@ -634,18 +656,6 @@ class MailingAutoGenerationView(View):
return redirect("club:mailing", club_id=club.id) return redirect("club:mailing", club_id=club.id)
class MailingAutoCleanView(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(MailingAutoCleanView, self).dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
self.mailing.subscriptions.all().delete()
return redirect("club:mailing", club_id=self.mailing.club.id)
class PosterListView(ClubTabsMixin, PosterListBaseView, CanViewMixin): class PosterListView(ClubTabsMixin, PosterListBaseView, CanViewMixin):
"""List communication posters""" """List communication posters"""

View File

@ -6,7 +6,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-04-28 15:00+0200\n" "POT-Creation-Date: 2019-05-01 22:45+0200\n"
"PO-Revision-Date: 2016-07-18\n" "PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Skia <skia@libskia.so>\n" "Last-Translator: Skia <skia@libskia.so>\n"
"Language-Team: AE info <ae.info@utbm.fr>\n" "Language-Team: AE info <ae.info@utbm.fr>\n"
@ -177,7 +177,7 @@ msgstr "type de cible"
#: accounting/models.py:313 club/models.py:413 #: accounting/models.py:313 club/models.py:413
#: club/templates/club/club_members.jinja:16 #: club/templates/club/club_members.jinja:16
#: club/templates/club/club_old_members.jinja:8 #: club/templates/club/club_old_members.jinja:8
#: club/templates/club/mailing.jinja:28 club/views.py:112 #: club/templates/club/mailing.jinja:32
#: counter/templates/counter/cash_summary_list.jinja:32 #: counter/templates/counter/cash_summary_list.jinja:32
#: counter/templates/counter/stats.jinja:15 #: counter/templates/counter/stats.jinja:15
#: counter/templates/counter/stats.jinja:52 #: counter/templates/counter/stats.jinja:52
@ -345,7 +345,7 @@ msgstr "Compte en banque : "
#: accounting/templates/accounting/club_account_details.jinja:60 #: accounting/templates/accounting/club_account_details.jinja:60
#: accounting/templates/accounting/label_list.jinja:26 #: accounting/templates/accounting/label_list.jinja:26
#: club/templates/club/club_sellings.jinja:50 #: club/templates/club/club_sellings.jinja:50
#: club/templates/club/mailing.jinja:16 club/templates/club/mailing.jinja:39 #: club/templates/club/mailing.jinja:16 club/templates/club/mailing.jinja:34
#: com/templates/com/mailing_admin.jinja:19 #: com/templates/com/mailing_admin.jinja:19
#: com/templates/com/news_admin_list.jinja:41 #: com/templates/com/news_admin_list.jinja:41
#: com/templates/com/news_admin_list.jinja:70 #: com/templates/com/news_admin_list.jinja:70
@ -386,7 +386,7 @@ msgid "Delete"
msgstr "Supprimer" msgstr "Supprimer"
#: accounting/templates/accounting/bank_account_details.jinja:18 #: accounting/templates/accounting/bank_account_details.jinja:18
#: club/views.py:129 core/views/user.py:205 sas/templates/sas/picture.jinja:86 #: club/views.py:78 core/views/user.py:205 sas/templates/sas/picture.jinja:86
msgid "Infos" msgid "Infos"
msgstr "Infos" msgstr "Infos"
@ -405,7 +405,7 @@ msgstr "Nouveau compte club"
#: accounting/templates/accounting/bank_account_details.jinja:27 #: accounting/templates/accounting/bank_account_details.jinja:27
#: accounting/templates/accounting/bank_account_list.jinja:22 #: accounting/templates/accounting/bank_account_list.jinja:22
#: accounting/templates/accounting/club_account_details.jinja:58 #: accounting/templates/accounting/club_account_details.jinja:58
#: accounting/templates/accounting/journal_details.jinja:89 club/views.py:175 #: accounting/templates/accounting/journal_details.jinja:89 club/views.py:124
#: com/templates/com/news_admin_list.jinja:39 #: com/templates/com/news_admin_list.jinja:39
#: com/templates/com/news_admin_list.jinja:68 #: com/templates/com/news_admin_list.jinja:68
#: com/templates/com/news_admin_list.jinja:115 #: com/templates/com/news_admin_list.jinja:115
@ -893,6 +893,101 @@ msgstr "Opérations sans étiquette"
msgid "Refound this account" msgid "Refound this account"
msgstr "Rembourser ce compte" msgstr "Rembourser ce compte"
#: club/forms.py:60 club/forms.py:197
msgid "Users to add"
msgstr "Utilisateurs à ajouter"
#: club/forms.py:61 club/forms.py:198 core/views/group.py:63
msgid "Search users to add (one or more)."
msgstr "Recherche les utilisateurs à ajouter (un ou plus)."
#: club/forms.py:70
#, fuzzy
#| msgid "New mailing"
msgid "New Mailing"
msgstr "Nouvelle mailing liste"
#: club/forms.py:71
#, fuzzy
#| msgid "Unsubscribe"
msgid "Subscribe"
msgstr "Se désabonner"
#: club/forms.py:72 club/forms.py:85 com/templates/com/news_admin_list.jinja:40
#: com/templates/com/news_admin_list.jinja:116
#: com/templates/com/news_admin_list.jinja:198
#: com/templates/com/news_admin_list.jinja:274
msgid "Remove"
msgstr "Retirer"
#: club/forms.py:75 launderette/views.py:228
msgid "Action"
msgstr "Action"
#: club/forms.py:122
#, fuzzy
#| msgid "This field is required."
msgid "This field is required"
msgstr "Ce champ est obligatoire."
#: club/forms.py:134 club/forms.py:259
msgid "One of the selected users doesn't exist"
msgstr "Un des utilisateurs sélectionné n'existe pas"
#: club/forms.py:138
#, fuzzy
#| msgid "One of the selected users doesn't exist"
msgid "One of the selected users doesn't have an email address"
msgstr "Un des utilisateurs sélectionné n'existe pas"
#: club/forms.py:149
#, fuzzy
#| msgid "This field is required."
msgid "An action is required"
msgstr "Ce champ est obligatoire."
#: club/forms.py:162
msgid "You must specify at least an user or an email address"
msgstr ""
#: club/forms.py:172 counter/views.py:1481
msgid "Begin date"
msgstr "Date de début"
#: club/forms.py:178 com/views.py:85 com/views.py:221 counter/views.py:1487
#: election/views.py:190 subscription/views.py:52
msgid "End date"
msgstr "Date de fin"
#: club/forms.py:183 club/templates/club/club_sellings.jinja:21
#: core/templates/core/user_account_detail.jinja:18
#: core/templates/core/user_account_detail.jinja:51
#: counter/templates/counter/cash_summary_list.jinja:33 counter/views.py:168
msgid "Counter"
msgstr "Comptoir"
#: club/forms.py:241 club/templates/club/club_members.jinja:21
#: club/templates/club/club_members.jinja:46
#: core/templates/core/user_clubs.jinja:29
msgid "Mark as old"
msgstr "Marquer comme ancien"
#: club/forms.py:263
msgid "User must be subscriber to take part to a club"
msgstr "L'utilisateur doit être cotisant pour faire partie d'un club"
#: club/forms.py:267 core/views/group.py:82
msgid "You can not add the same user twice"
msgstr "Vous ne pouvez pas ajouter deux fois le même utilisateur"
#: club/forms.py:288
msgid "You should specify a role"
msgstr "Vous devez choisir un rôle"
#: club/forms.py:299 sas/views.py:129 sas/views.py:195 sas/views.py:286
msgid "You do not have the permission to do that"
msgstr "Vous n'avez pas la permission de faire cela"
#: club/models.py:51 #: club/models.py:51
msgid "unix name" msgid "unix name"
msgstr "nom unix" msgstr "nom unix"
@ -988,9 +1083,9 @@ msgstr "Au moins un utilisateur ou un email est nécessaire"
msgid "This email is already suscribed in this mailing" msgid "This email is already suscribed in this mailing"
msgstr "Cet email est déjà abonné à cette mailing" msgstr "Cet email est déjà abonné à cette mailing"
#: club/models.py:462 club/templates/club/mailing.jinja:36 #: club/models.py:459
msgid "Unregistered user" msgid "Unregistered user"
msgstr "Désabonner un utilisateur" msgstr "Utilisateur non enregistré"
#: club/templates/club/club_list.jinja:4 club/templates/club/club_list.jinja:37 #: club/templates/club/club_list.jinja:4 club/templates/club/club_list.jinja:37
msgid "Club list" msgid "Club list"
@ -1037,12 +1132,6 @@ msgstr "Description"
msgid "Since" msgid "Since"
msgstr "Depuis" msgstr "Depuis"
#: club/templates/club/club_members.jinja:21
#: club/templates/club/club_members.jinja:46 club/views.py:363
#: core/templates/core/user_clubs.jinja:29
msgid "Mark as old"
msgstr "Marquer comme ancien"
#: club/templates/club/club_members.jinja:50 #: club/templates/club/club_members.jinja:50
msgid "There are no members in this club." msgid "There are no members in this club."
msgstr "Il n'y a pas de membres dans ce club." msgstr "Il n'y a pas de membres dans ce club."
@ -1067,8 +1156,8 @@ msgstr "Du"
msgid "To" msgid "To"
msgstr "Au" msgstr "Au"
#: club/templates/club/club_sellings.jinja:5 club/views.py:195 #: club/templates/club/club_sellings.jinja:5 club/views.py:144
#: club/views.py:563 counter/templates/counter/counter_main.jinja:19 #: club/views.py:378 counter/templates/counter/counter_main.jinja:19
#: counter/templates/counter/last_ops.jinja:35 #: counter/templates/counter/last_ops.jinja:35
msgid "Sellings" msgid "Sellings"
msgstr "Ventes" msgstr "Ventes"
@ -1094,13 +1183,6 @@ msgstr "unités"
msgid "Benefit: " msgid "Benefit: "
msgstr "Bénéfice : " msgstr "Bénéfice : "
#: club/templates/club/club_sellings.jinja:21 club/views.py:502
#: core/templates/core/user_account_detail.jinja:18
#: core/templates/core/user_account_detail.jinja:51
#: counter/templates/counter/cash_summary_list.jinja:33 counter/views.py:168
msgid "Counter"
msgstr "Comptoir"
#: club/templates/club/club_sellings.jinja:22 #: club/templates/club/club_sellings.jinja:22
#: core/templates/core/user_account_detail.jinja:19 #: core/templates/core/user_account_detail.jinja:19
#: core/templates/core/user_account_detail.jinja:52 #: core/templates/core/user_account_detail.jinja:52
@ -1189,11 +1271,11 @@ msgstr "Comptabilité : "
msgid "Manage launderettes" msgid "Manage launderettes"
msgstr "Gestion des laveries" msgstr "Gestion des laveries"
#: club/templates/club/mailing.jinja:4 #: club/templates/club/mailing.jinja:5
msgid "Mailing lists" msgid "Mailing lists"
msgstr "Mailing listes" msgstr "Mailing listes"
#: club/templates/club/mailing.jinja:10 #: club/templates/club/mailing.jinja:11
msgid "" msgid ""
"Remember : mailing lists need to be moderated, if your new created list is " "Remember : mailing lists need to be moderated, if your new created list is "
"not shown wait until moderation takes action" "not shown wait until moderation takes action"
@ -1206,34 +1288,38 @@ msgstr ""
msgid "Generate mailing list" msgid "Generate mailing list"
msgstr "Générer la liste de diffusion" msgstr "Générer la liste de diffusion"
#: club/templates/club/mailing.jinja:23 #: club/templates/club/mailing.jinja:33
msgid "Clean mailing list"
msgstr "Néttoyer la liste de diffusion"
#: club/templates/club/mailing.jinja:29
#: com/templates/com/mailing_admin.jinja:10 #: com/templates/com/mailing_admin.jinja:10
msgid "Email" msgid "Email"
msgstr "Email" msgstr "Email"
#: club/templates/club/mailing.jinja:47 #: club/templates/club/mailing.jinja:49
msgid "Remove from mailing list"
msgstr "Supprimer de la liste de diffusion"
#: club/templates/club/mailing.jinja:53
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:58
msgid "No mailing list existing for this club" msgid "No mailing list existing for this club"
msgstr "Aucune mailing liste n'existe pour ce club" msgstr "Aucune mailing liste n'existe pour ce club"
#: club/templates/club/mailing.jinja:51 #: club/templates/club/mailing.jinja:63
msgid "New member" msgid "New member"
msgstr "Nouveau membre" msgstr "Nouveau membre"
#: club/templates/club/mailing.jinja:55 #: club/templates/club/mailing.jinja:83
msgid "Add to mailing list" msgid "Add to mailing list"
msgstr "Ajouter à la mailing liste" msgstr "Ajouter à la mailing liste"
#: club/templates/club/mailing.jinja:59 #: club/templates/club/mailing.jinja:87
msgid "New mailing" msgid "New mailing"
msgstr "Nouvelle mailing liste" msgstr "Nouvelle liste de diffusion"
#: club/templates/club/mailing.jinja:63 #: club/templates/club/mailing.jinja:100
msgid "Create mailing list" msgid "Create mailing list"
msgstr "Créer une mailing liste" msgstr "Créer une liste de diffusion"
#: club/templates/club/page_history.jinja:8 #: club/templates/club/page_history.jinja:8
msgid "No page existing for this club" msgid "No page existing for this club"
@ -1243,79 +1329,42 @@ msgstr "Aucune page n'existe pour ce club"
msgid "Club stats" msgid "Club stats"
msgstr "Statistiques du club" msgstr "Statistiques du club"
#: club/views.py:139 #: club/views.py:88
msgid "Members" msgid "Members"
msgstr "Membres" msgstr "Membres"
#: club/views.py:148 #: club/views.py:97
msgid "Old members" msgid "Old members"
msgstr "Anciens membres" msgstr "Anciens membres"
#: club/views.py:158 core/templates/core/page.jinja:33 #: club/views.py:107 core/templates/core/page.jinja:33
msgid "History" msgid "History"
msgstr "Historique" msgstr "Historique"
#: club/views.py:166 core/templates/core/base.jinja:121 core/views/user.py:228 #: club/views.py:115 core/templates/core/base.jinja:121 core/views/user.py:228
#: sas/templates/sas/picture.jinja:95 trombi/views.py:60 #: sas/templates/sas/picture.jinja:95 trombi/views.py:60
msgid "Tools" msgid "Tools"
msgstr "Outils" msgstr "Outils"
#: club/views.py:186 #: club/views.py:135
msgid "Edit club page" msgid "Edit club page"
msgstr "Éditer la page de club" msgstr "Éditer la page de club"
#: club/views.py:202 #: club/views.py:151
msgid "Mailing list" msgid "Mailing list"
msgstr "Listes de diffusion" msgstr "Listes de diffusion"
#: club/views.py:211 com/views.py:141 #: club/views.py:160 com/views.py:141
msgid "Posters list" msgid "Posters list"
msgstr "Liste d'affiches" msgstr "Liste d'affiches"
#: club/views.py:221 counter/templates/counter/counter_list.jinja:21 #: club/views.py:170 counter/templates/counter/counter_list.jinja:21
#: counter/templates/counter/counter_list.jinja:43 #: counter/templates/counter/counter_list.jinja:43
#: counter/templates/counter/counter_list.jinja:59 #: counter/templates/counter/counter_list.jinja:59
msgid "Props" msgid "Props"
msgstr "Propriétés" msgstr "Propriétés"
#: club/views.py:319 #: club/views.py:335 core/templates/core/user_stats.jinja:27
msgid "Users to add"
msgstr "Utilisateurs à ajouter"
#: club/views.py:320 core/views/group.py:63
msgid "Search users to add (one or more)."
msgstr "Recherche les utilisateurs à ajouter (un ou plus)."
#: club/views.py:381
msgid "One of the selected users doesn't exist"
msgstr "Un des utilisateurs sélectionné n'existe pas"
#: club/views.py:385
msgid "User must be subscriber to take part to a club"
msgstr "L'utilisateur doit être cotisant pour faire partie d'un club"
#: club/views.py:389 core/views/group.py:82
msgid "You can not add the same user twice"
msgstr "Vous ne pouvez pas ajouter deux fois le même utilisateur"
#: club/views.py:410
msgid "You should specify a role"
msgstr "Vous devez choisir un rôle"
#: club/views.py:421 sas/views.py:129 sas/views.py:195 sas/views.py:286
msgid "You do not have the permission to do that"
msgstr "Vous n'avez pas la permission de faire cela"
#: club/views.py:491 counter/views.py:1481
msgid "Begin date"
msgstr "Date de début"
#: club/views.py:497 com/views.py:85 com/views.py:221 counter/views.py:1487
#: election/views.py:190 subscription/views.py:52
msgid "End date"
msgstr "Date de fin"
#: club/views.py:520 core/templates/core/user_stats.jinja:27
#: counter/views.py:1635 #: counter/views.py:1635
msgid "Product" msgid "Product"
msgstr "Produit" msgstr "Produit"
@ -1547,13 +1596,6 @@ msgstr "Auteur"
msgid "Moderator" msgid "Moderator"
msgstr "Modérateur" msgstr "Modérateur"
#: com/templates/com/news_admin_list.jinja:40
#: com/templates/com/news_admin_list.jinja:116
#: com/templates/com/news_admin_list.jinja:198
#: com/templates/com/news_admin_list.jinja:274
msgid "Remove"
msgstr "Retirer"
#: com/templates/com/news_admin_list.jinja:47 #: com/templates/com/news_admin_list.jinja:47
msgid "Notices to moderate" msgid "Notices to moderate"
msgstr "Informations à modérer" msgstr "Informations à modérer"
@ -4612,10 +4654,6 @@ msgstr "Éditer la page de présentation"
msgid "Book launderette slot" msgid "Book launderette slot"
msgstr "Réserver un créneau de laverie" msgstr "Réserver un créneau de laverie"
#: launderette/views.py:228
msgid "Action"
msgstr "Action"
#: launderette/views.py:240 #: launderette/views.py:240
msgid "Tokens, separated by spaces" msgid "Tokens, separated by spaces"
msgstr "Jetons, séparés par des espaces" msgstr "Jetons, séparés par des espaces"