From feaf6b73b7354ea56c6c6caa2612f85deefa0f23 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Thu, 17 Aug 2017 00:07:19 +0200 Subject: [PATCH 01/18] Begin mailing list system --- .../0009_mailing_mailingsubscription.py | 33 +++++ club/models.py | 34 +++++ club/templates/club/mailing.jinja | 56 +++++++++ club/urls.py | 4 + club/views.py | 119 +++++++++++++++++- 5 files changed, 243 insertions(+), 3 deletions(-) create mode 100644 club/migrations/0009_mailing_mailingsubscription.py create mode 100644 club/templates/club/mailing.jinja diff --git a/club/migrations/0009_mailing_mailingsubscription.py b/club/migrations/0009_mailing_mailingsubscription.py new file mode 100644 index 00000000..a87fceeb --- /dev/null +++ b/club/migrations/0009_mailing_mailingsubscription.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('club', '0008_auto_20170515_2214'), + ] + + operations = [ + migrations.CreateModel( + name='Mailing', + fields=[ + ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), + ('email', models.EmailField(verbose_name='Email address', unique=True, max_length=254)), + ('club', models.ForeignKey(verbose_name='Club', related_name='mailings', to='club.Club')), + ], + ), + migrations.CreateModel( + name='MailingSubscription', + fields=[ + ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), + ('email', models.EmailField(verbose_name='Email address', max_length=254, unique=True)), + ('mailing', models.ForeignKey(verbose_name='Mailing', related_name='subscriptions', to='club.Mailing')), + ('user', models.ForeignKey(null=True, verbose_name='User', related_name='mailing_subscriptions', to=settings.AUTH_USER_MODEL, blank=True)), + ], + ), + ] diff --git a/club/models.py b/club/models.py index cbec4872..5a652e20 100644 --- a/club/models.py +++ b/club/models.py @@ -2,6 +2,7 @@ # # Copyright 2016,2017 # - Skia +# - Sli # # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, # http://ae.utbm.fr. @@ -220,3 +221,36 @@ class Membership(models.Model): def get_absolute_url(self): return reverse('club:club_members', kwargs={'club_id': self.club.id}) + + +class Mailing(models.Model): + """ + This class correspond to a mailing list + + """ + club = models.ForeignKey(Club, verbose_name=_('Club'), related_name="mailings", null=False, blank=False) + email = models.EmailField(_('Email address'), unique=True) + + def is_owned_by(self, user): + return self.club.has_rights_in_club(user) or user.is_root + + def can_be_edited_by(self, user): + return self.is_owned_by(user) + + def __str__(self): + return "%s - %s" % (self.club, self.email) + + +class MailingSubscription(models.Model): + """ + This class make the link between user and mailing list + """ + mailing = models.ForeignKey(Mailing, verbose_name=_('Mailing'), related_name="subscriptions", null=False, blank=False) + user = models.ForeignKey(User, verbose_name=_('User'), related_name="mailing_subscriptions", null=True, blank=True) + email = models.EmailField(_('Email address'), unique=True) + + def is_owned_by(self, user): + return self.mailing.club.has_rights_in_club(user) or user.is_root + + def can_be_edited_by(self, user): + return self.is_owned_by(user) or (user is not None and user.id == self.user.id) diff --git a/club/templates/club/mailing.jinja b/club/templates/club/mailing.jinja new file mode 100644 index 00000000..26721097 --- /dev/null +++ b/club/templates/club/mailing.jinja @@ -0,0 +1,56 @@ +{% extends "core/base.jinja" %} + +{% block title %} +{% trans %}Mailing lists{% endtrans %} +{% endblock %} + +{% block content %} + {% if has_objects %} + + {% for mailing in object_list %} +

{% trans %}Mailing{% endtrans %} {{ mailing.email }}

+ + + + + + {% for subscriber in mailing.subscriptions.all() %} + + {% if subscriber.user %} + + {% else %} + + {% endif %} + + + {% endfor %} +
{% trans %}User{% endtrans %}{% trans %}Mail{%endtrans%}
{{ subscriber.user }}{% trans %}Unregistered user{% endtrans %}{{ subscriber.email }}
+ {% endfor %} + + {% else %} +

{% trans %}No mailing list existing for this club{% endtrans %}

+ {% endif %} + + {% if club.has_rights_in_club(user) %} + + {% if has_objects %} +

{% trans %}New member{% endtrans %}

+
+ {% csrf_token %} + {{ new_member.as_p() }} +

+
+ {% endif %} + +

{% trans %}New mailing{% endtrans %}

+
+ {% csrf_token %} + {{ new_mailing.as_p() }} +

+
+ {% endif %} + +{% endblock %} + + + diff --git a/club/urls.py b/club/urls.py index 95f7768e..6b233a6e 100644 --- a/club/urls.py +++ b/club/urls.py @@ -2,6 +2,7 @@ # # Copyright 2016,2017 # - Skia +# - Sli # # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, # http://ae.utbm.fr. @@ -38,5 +39,8 @@ urlpatterns = [ url(r'^(?P[0-9]+)/sellings/csv$', ClubSellingCSVView.as_view(), name='sellings_csv'), url(r'^(?P[0-9]+)/prop$', ClubEditPropView.as_view(), name='club_prop'), url(r'^(?P[0-9]+)/tools$', ClubToolsView.as_view(), name='tools'), + url(r'^(?P[0-9]+)/mailing$', ClubMailingView.as_view(action=MailingFormType.DISPLAY), name='mailing'), + url(r'^(?P[0-9]+)/mailing/new/mailing$', ClubMailingView.as_view(action=MailingFormType.MAILING), name='mailing_create'), + url(r'^(?P[0-9]+)/mailing/new/subscription$', ClubMailingView.as_view(action=MailingFormType.MEMBER), name='mailing_subscription_create'), url(r'^membership/(?P[0-9]+)/set_old$', MembershipSetOldView.as_view(), name='membership_set_old'), ] diff --git a/club/views.py b/club/views.py index e608d6ac..9eeb9abd 100644 --- a/club/views.py +++ b/club/views.py @@ -2,6 +2,7 @@ # # Copyright 2016,2017 # - Skia +# - Sli # # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, # http://ae.utbm.fr. @@ -23,21 +24,53 @@ # from django import forms +from enum import Enum from django.views.generic import ListView, DetailView, TemplateView +from django.views.generic.edit import DeleteView, FormView +from django.views.generic.detail import SingleObjectMixin from django.views.generic.edit import UpdateView, CreateView from django.http import HttpResponseRedirect, HttpResponse -from django.core.urlresolvers import reverse +from django.core.urlresolvers import reverse, reverse_lazy from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext as _t from ajax_select.fields import AutoCompleteSelectField +from django.shortcuts import get_object_or_404 -from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin +from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin, CanCreateMixin from core.views.forms import SelectDate, SelectDateTime -from club.models import Club, Membership +from club.models import Club, Membership, Mailing, MailingSubscription from sith.settings import SITH_MAXIMUM_FREE_ROLE from counter.models import Selling, Counter +# Custom forms + + +class MailingForm(forms.ModelForm): + class Meta: + model = Mailing + fields = ('email', 'club') + + def __init__(self, *args, **kwargs): + club_id = kwargs.pop('club_id', None) + super(MailingForm, self).__init__(*args, **kwargs) + if club_id: + self.fields['club'].queryset = Club.objects.filter(id=club_id) + + +class MailingSubscriptionForm(forms.ModelForm): + class Meta: + model = MailingSubscription + fields = ('mailing', 'user', 'email') + + def __init__(self, *args, **kwargs): + club_id = kwargs.pop('club_id', None) + super(MailingSubscriptionForm, self).__init__(*args, **kwargs) + if club_id: + self.fields['mailing'].queryset = Mailing.objects.filter(club__id=club_id) + + user = AutoCompleteSelectField('users', label=_('User'), help_text=None, required=False) + class ClubTabsMixin(TabedViewMixin): def get_tabs_title(self): @@ -61,6 +94,11 @@ class ClubTabsMixin(TabedViewMixin): 'slug': 'elderlies', 'name': _("Old members"), }) + tab_list.append({ + 'url': reverse('club:mailing', kwargs={'club_id': self.object.id}), + 'slug': 'mailing', + 'name': _("Mailing list"), + }) if self.request.user.can_edit(self.object): tab_list.append({ 'url': reverse('club:tools', kwargs={'club_id': self.object.id}), @@ -338,3 +376,78 @@ class ClubStatView(TemplateView): kwargs = super(ClubStatView, self).get_context_data(**kwargs) kwargs['club_list'] = Club.objects.all() return kwargs + + +class MailingFormType(Enum): + DISPLAY = 0 + MEMBER = 1 + MAILING = 2 + + +class ClubMailingView(CanViewMixin, ListView): + """ + A list of mailing for a given club + """ + action = None + model = Mailing + template_name = "club/mailing.jinja" + + def dispatch(self, request, *args, **kwargs): + self.club = get_object_or_404(Club, pk=kwargs['club_id']) + self.user = request.user + self.member_form = MailingSubscriptionForm(club_id=self.club.id) + self.mailing_form = MailingForm(club_id=self.club.id) + return super(ClubMailingView, self).dispatch(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + res = super(ClubMailingView, self).get(request, *args, **kwargs) + if self.action != MailingFormType.DISPLAY: + if self.action == MailingFormType.MAILING: + form = MailingForm + string = 'new_mailing' + elif self.action == MailingFormType.MEMBER: + form = MailingSubscriptionForm + string = 'new_member' + return MailingGenericCreateView.as_view(list_view=self, form_class=form, form_kwarg_string=string)(request, *args, **kwargs) + return res + + def get_queryset(self): + return Mailing.objects.filter(club_id=self.club.id).all() + + def get_context_data(self, **kwargs): + kwargs = super(ClubMailingView, self).get_context_data(**kwargs) + kwargs['new_member'] = self.member_form + kwargs['new_mailing'] = self.mailing_form + kwargs['club'] = self.club + kwargs['user'] = self.user + kwargs['has_objects'] = len(kwargs['object_list']) > 0 + return kwargs + + +class MailingGenericCreateView(CanCreateMixin, CreateView, SingleObjectMixin): + """ + Create a new mailing list + """ + model = Mailing + list_view = None + form_class = None + form_kwarg_string = None + + def get_context_data(self, **kwargs): + view_kwargs = self.list_view.get_context_data(**kwargs) + for key, data in super(MailingGenericCreateView, self).get_context_data(**kwargs).items(): + view_kwargs[key] = data + view_kwargs[self.form_kwarg_string] = view_kwargs['form'] + return view_kwargs + + def get_form_kwargs(self): + kwargs = super(MailingGenericCreateView, self).get_form_kwargs() + kwargs['club_id'] = self.list_view.club.id + return kwargs + + def dispatch(self, request, *args, **kwargs): + self.template_name = self.list_view.template_name + return super(MailingGenericCreateView, self).dispatch(request, *args, **kwargs) + + def get_success_url(self, **kwargs): + return reverse_lazy('club:mailing', kwargs={'club_id': self.list_view.club.id}) From 9cb88a878d8e53b4a4f1d2898233db2bcbe4fe85 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Thu, 17 Aug 2017 20:55:20 +0200 Subject: [PATCH 02/18] Even better mailing --- club/migrations/0010_auto_20170817_1537.py | 23 ++++++ club/models.py | 34 +++++++-- club/templates/club/mailing.jinja | 16 ++--- club/urls.py | 2 + club/views.py | 72 ++++++++++++++++--- core/templates/core/user_clubs.jinja | 7 ++ core/templates/core/user_tools.jinja | 1 + counter/migrations/0014_auto_20170817_1537.py | 19 +++++ .../templates/rootplace/mailing_lists.jinja | 30 ++++++++ rootplace/urls.py | 1 + rootplace/views.py | 20 ++++++ 11 files changed, 202 insertions(+), 23 deletions(-) create mode 100644 club/migrations/0010_auto_20170817_1537.py create mode 100644 counter/migrations/0014_auto_20170817_1537.py create mode 100644 rootplace/templates/rootplace/mailing_lists.jinja diff --git a/club/migrations/0010_auto_20170817_1537.py b/club/migrations/0010_auto_20170817_1537.py new file mode 100644 index 00000000..24949949 --- /dev/null +++ b/club/migrations/0010_auto_20170817_1537.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('club', '0009_mailing_mailingsubscription'), + ] + + operations = [ + migrations.AlterField( + model_name='mailingsubscription', + name='email', + field=models.EmailField(verbose_name='Email address', max_length=254), + ), + migrations.AlterUniqueTogether( + name='mailingsubscription', + unique_together=set([('user', 'email', 'mailing')]), + ), + ] diff --git a/club/models.py b/club/models.py index 5a652e20..9484e4e2 100644 --- a/club/models.py +++ b/club/models.py @@ -226,16 +226,21 @@ class Membership(models.Model): class Mailing(models.Model): """ This class correspond to a mailing list - + Remember that mailing lists should be validated by UTBM """ club = models.ForeignKey(Club, verbose_name=_('Club'), related_name="mailings", null=False, blank=False) email = models.EmailField(_('Email address'), unique=True) def is_owned_by(self, user): - return self.club.has_rights_in_club(user) or user.is_root + return user.is_in_group(self) or user.is_root or user.is_board_member - def can_be_edited_by(self, user): - return self.is_owned_by(user) + def can_view(self, user): + return self.club.has_rights_in_club(user) + + def delete(self): + for sub in self.subscriptions.all(): + sub.delete() + super(Mailing, self).delete() def __str__(self): return "%s - %s" % (self.club, self.email) @@ -243,14 +248,31 @@ class Mailing(models.Model): class MailingSubscription(models.Model): """ - This class make the link between user and mailing list + This class makes the link between user and mailing list """ mailing = models.ForeignKey(Mailing, verbose_name=_('Mailing'), related_name="subscriptions", null=False, blank=False) user = models.ForeignKey(User, verbose_name=_('User'), related_name="mailing_subscriptions", null=True, blank=True) - email = models.EmailField(_('Email address'), unique=True) + email = models.EmailField(_('Email address'), blank=False, null=False) + + class Meta: + unique_together = (('user', 'email', 'mailing'),) + + def clean(self): + if not self.user and not self.email: + raise ValidationError(_("At least user or email is required")) + if self.user and not self.email: + self.email = self.user.email + super(MailingSubscription, self).clean() def is_owned_by(self, user): return self.mailing.club.has_rights_in_club(user) or user.is_root def can_be_edited_by(self, user): return self.is_owned_by(user) or (user is not None and user.id == self.user.id) + + def __str__(self): + if self.user: + user = str(self.user) + else: + user = _("Unregistered user") + return "(%s) - %s : %s" % (self.mailing, user, self.email) diff --git a/club/templates/club/mailing.jinja b/club/templates/club/mailing.jinja index 26721097..47f11884 100644 --- a/club/templates/club/mailing.jinja +++ b/club/templates/club/mailing.jinja @@ -8,11 +8,16 @@ {% if has_objects %} {% for mailing in object_list %} -

{% trans %}Mailing{% endtrans %} {{ mailing.email }}

+

{% trans %}Mailing{% endtrans %} {{ mailing.email }} + {%- if user.is_owner(mailing) -%} + {% trans %}Delete{% endtrans %} + {%- endif -%} +

+
- + {% for subscriber in mailing.subscriptions.all() %} @@ -22,6 +27,7 @@ {% endif %} + {% endfor %}
{% trans %}User{% endtrans %}{% trans %}Mail{%endtrans%}{% trans %}Email{%endtrans%}
{% trans %}Unregistered user{% endtrans %}{{ subscriber.email }}{% trans %}Delete{% endtrans %}
@@ -31,8 +37,6 @@

{% trans %}No mailing list existing for this club{% endtrans %}

{% endif %} - {% if club.has_rights_in_club(user) %} - {% if has_objects %}

{% trans %}New member{% endtrans %}

@@ -48,9 +52,5 @@ {{ new_mailing.as_p() }}

- {% endif %} {% endblock %} - - - diff --git a/club/urls.py b/club/urls.py index 6b233a6e..42074a5c 100644 --- a/club/urls.py +++ b/club/urls.py @@ -42,5 +42,7 @@ urlpatterns = [ url(r'^(?P[0-9]+)/mailing$', ClubMailingView.as_view(action=MailingFormType.DISPLAY), name='mailing'), url(r'^(?P[0-9]+)/mailing/new/mailing$', ClubMailingView.as_view(action=MailingFormType.MAILING), name='mailing_create'), url(r'^(?P[0-9]+)/mailing/new/subscription$', ClubMailingView.as_view(action=MailingFormType.MEMBER), name='mailing_subscription_create'), + url(r'^(?P[0-9]+)/mailing/delete$', MailingDeleteView.as_view(), name='mailing_delete'), + url(r'^(?P[0-9]+)/mailing/delete/subscription$', MailingSubscriptionDeleteView.as_view(), name='mailing_subscription_delete'), url(r'^membership/(?P[0-9]+)/set_old$', MembershipSetOldView.as_view(), name='membership_set_old'), ] diff --git a/club/views.py b/club/views.py index 9eeb9abd..6a3b35a0 100644 --- a/club/views.py +++ b/club/views.py @@ -35,6 +35,7 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext as _t from ajax_select.fields import AutoCompleteSelectField +from django.core.exceptions import PermissionDenied from django.shortcuts import get_object_or_404 from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin, CanCreateMixin @@ -56,6 +57,8 @@ class MailingForm(forms.ModelForm): super(MailingForm, self).__init__(*args, **kwargs) if club_id: self.fields['club'].queryset = Club.objects.filter(id=club_id) + self.fields['club'].initial = club_id + self.fields['club'].widget = forms.HiddenInput() class MailingSubscriptionForm(forms.ModelForm): @@ -66,9 +69,22 @@ class MailingSubscriptionForm(forms.ModelForm): def __init__(self, *args, **kwargs): club_id = kwargs.pop('club_id', None) super(MailingSubscriptionForm, self).__init__(*args, **kwargs) + self.fields['email'].required = False if club_id: self.fields['mailing'].queryset = Mailing.objects.filter(club__id=club_id) + def clean(self): + cleaned_data = super(MailingSubscriptionForm, self).clean() + user = cleaned_data.get('user', None) + email = cleaned_data.get('email', None) + mailing = cleaned_data.get('mailing') + if not user and not email: + raise forms.ValidationError(_("At least user or email should be filled")) + if user and not email: + email = user.email + if user and MailingSubscription.objects.filter(mailing=mailing, email=email).exists(): + raise forms.ValidationError(_("This email is already suscribed in this mailing")) + user = AutoCompleteSelectField('users', label=_('User'), help_text=None, required=False) @@ -94,11 +110,6 @@ class ClubTabsMixin(TabedViewMixin): 'slug': 'elderlies', 'name': _("Old members"), }) - tab_list.append({ - 'url': reverse('club:mailing', kwargs={'club_id': self.object.id}), - 'slug': 'mailing', - 'name': _("Mailing list"), - }) if self.request.user.can_edit(self.object): tab_list.append({ 'url': reverse('club:tools', kwargs={'club_id': self.object.id}), @@ -115,6 +126,11 @@ class ClubTabsMixin(TabedViewMixin): 'slug': 'sellings', 'name': _("Sellings"), }) + tab_list.append({ + 'url': reverse('club:mailing', kwargs={'club_id': self.object.id}), + 'slug': 'mailing', + 'name': _("Mailing list"), + }) if self.request.user.is_owner(self.object): tab_list.append({ 'url': reverse('club:club_prop', kwargs={'club_id': self.object.id}), @@ -384,17 +400,24 @@ class MailingFormType(Enum): MAILING = 2 -class ClubMailingView(CanViewMixin, ListView): +class ClubMailingView(ClubTabsMixin, ListView): """ A list of mailing for a given club """ action = None model = Mailing template_name = "club/mailing.jinja" + current_tab = 'mailing' + + def authorized(self): + return self.club.has_rights_in_club(self.user) or self.user.is_root or self.user.is_board_member def dispatch(self, request, *args, **kwargs): self.club = get_object_or_404(Club, pk=kwargs['club_id']) self.user = request.user + self.object = self.club + if not self.authorized(): + raise PermissionDenied self.member_form = MailingSubscriptionForm(club_id=self.club.id) self.mailing_form = MailingForm(club_id=self.club.id) return super(ClubMailingView, self).dispatch(request, *args, **kwargs) @@ -405,10 +428,12 @@ class ClubMailingView(CanViewMixin, ListView): if self.action == MailingFormType.MAILING: form = MailingForm string = 'new_mailing' + model = Mailing elif self.action == MailingFormType.MEMBER: form = MailingSubscriptionForm string = 'new_member' - return MailingGenericCreateView.as_view(list_view=self, form_class=form, form_kwarg_string=string)(request, *args, **kwargs) + model = MailingSubscription + return MailingGenericCreateView.as_view(model=model, list_view=self, form_class=form, form_kwarg_string=string)(request, *args, **kwargs) return res def get_queryset(self): @@ -424,11 +449,10 @@ class ClubMailingView(CanViewMixin, ListView): return kwargs -class MailingGenericCreateView(CanCreateMixin, CreateView, SingleObjectMixin): +class MailingGenericCreateView(CreateView, SingleObjectMixin): """ Create a new mailing list """ - model = Mailing list_view = None form_class = None form_kwarg_string = None @@ -446,8 +470,38 @@ class MailingGenericCreateView(CanCreateMixin, CreateView, SingleObjectMixin): return kwargs def dispatch(self, request, *args, **kwargs): + if not self.list_view.authorized(): + raise PermissionDenied self.template_name = self.list_view.template_name return super(MailingGenericCreateView, self).dispatch(request, *args, **kwargs) def get_success_url(self, **kwargs): return reverse_lazy('club:mailing', kwargs={'club_id': self.list_view.club.id}) + + +class MailingDeleteView(CanEditMixin, DeleteView): + + model = Mailing + template_name = 'core/delete_confirm.jinja' + pk_url_kwarg = "mailing_id" + + def dispatch(self, request, *args, **kwargs): + self.club_id = self.get_object().club.id + return super(MailingDeleteView, self).dispatch(request, *args, **kwargs) + + def get_success_url(self, **kwargs): + 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(MailingSubscriptionDeleteView, self).dispatch(request, *args, **kwargs) + + def get_success_url(self, **kwargs): + return reverse_lazy('club:mailing', kwargs={'club_id': self.club_id}) diff --git a/core/templates/core/user_clubs.jinja b/core/templates/core/user_clubs.jinja index 0739c5e6..9d138695 100644 --- a/core/templates/core/user_clubs.jinja +++ b/core/templates/core/user_clubs.jinja @@ -58,5 +58,12 @@ {% endfor %} + +{% if user.mailing_subscriptions.exists() %} +

{% trans %}Subscribed mailing lists{% endtrans %}

+ {% for sub in user.mailing_subscriptions.all() %} +

{{ sub }} {% trans %}Unsuscribe{% endtrans %}

+ {% endfor %} +{% endif %} {% endblock %} diff --git a/core/templates/core/user_tools.jinja b/core/templates/core/user_tools.jinja index 4033f702..3f7b0804 100644 --- a/core/templates/core/user_tools.jinja +++ b/core/templates/core/user_tools.jinja @@ -13,6 +13,7 @@ {% if user.is_root %}
  • {% trans %}Groups{% endtrans %}
  • {% trans %}Merge users{% endtrans %}
  • +
  • {% trans %}Mailing lists administration{% endtrans %}
  • {% endif %} {% if user.can_create_subscription or user.is_root %}
  • {% trans %}Subscriptions{% endtrans %}
  • diff --git a/counter/migrations/0014_auto_20170817_1537.py b/counter/migrations/0014_auto_20170817_1537.py new file mode 100644 index 00000000..8e4e3df5 --- /dev/null +++ b/counter/migrations/0014_auto_20170817_1537.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('counter', '0013_customer_recorded_products'), + ] + + operations = [ + migrations.AlterField( + model_name='customer', + name='recorded_products', + field=models.IntegerField(verbose_name='recorded product', default=0), + ), + ] diff --git a/rootplace/templates/rootplace/mailing_lists.jinja b/rootplace/templates/rootplace/mailing_lists.jinja new file mode 100644 index 00000000..16fabf24 --- /dev/null +++ b/rootplace/templates/rootplace/mailing_lists.jinja @@ -0,0 +1,30 @@ +{% extends "core/base.jinja" %} + +{% block title %} +{% trans %}Mailing lists administration{% endtrans %} +{% endblock %} + +{% block content %} +

    {% trans %}This page list all existing mailing lists{% endtrans %}

    + {% if has_objects %} + + + + + + {% for mailing in object_list %} + + + + + {% endfor %} +
    {% trans %}Email{% endtrans %}{% trans %}Club{%endtrans%}
    {{ mailing.email }}{{ mailing.club }} {% trans %}Delete{% endtrans %}
    + + {% else %} +

    {% trans %}No mailing existing{% endtrans %}

    + {% endif %} + +{% endblock %} + + + diff --git a/rootplace/urls.py b/rootplace/urls.py index 6ab433e3..732efe1c 100644 --- a/rootplace/urls.py +++ b/rootplace/urls.py @@ -28,4 +28,5 @@ from rootplace.views import * urlpatterns = [ url(r'^merge$', MergeUsersView.as_view(), name='merge'), + url(r'^mailings$', MailingListAdminView.as_view(), name='mailings') ] diff --git a/rootplace/views.py b/rootplace/views.py index 7a9cb64e..7aef0366 100644 --- a/rootplace/views.py +++ b/rootplace/views.py @@ -2,6 +2,7 @@ # # Copyright 2016,2017 # - Skia +# - Sli # # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, # http://ae.utbm.fr. @@ -27,6 +28,7 @@ from django.utils.translation import ugettext as _ from django.views.generic.edit import FormView from django.core.urlresolvers import reverse from django import forms +from django.views.generic import ListView from django.core.exceptions import PermissionDenied from ajax_select.fields import AutoCompleteSelectField @@ -34,6 +36,8 @@ from ajax_select.fields import AutoCompleteSelectField from core.views import CanViewMixin from core.models import User from counter.models import Customer +from club.models import Mailing + def merge_users(u1, u2): u1.nick_name = u1.nick_name or u2.nick_name @@ -86,10 +90,12 @@ def merge_users(u1, u2): u2.delete() return u1 + class MergeForm(forms.Form): user1 = AutoCompleteSelectField('users', label=_("User that will be kept"), help_text=None, required=True) user2 = AutoCompleteSelectField('users', label=_("User that will be deleted"), help_text=None, required=True) + class MergeUsersView(FormView): template_name = "rootplace/merge.jinja" form_class = MergeForm @@ -107,3 +113,17 @@ class MergeUsersView(FormView): def get_success_url(self): return reverse('core:user_profile', kwargs={'user_id': self.final_user.id}) + +class MailingListAdminView(ListView): + template_name = "rootplace/mailing_lists.jinja" + model = Mailing + + def dispatch(self, request, *args, **kwargs): + if not request.user.is_root: + raise PermissionDenied + return super(MailingListAdminView, self).dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + kwargs = super(MailingListAdminView, self).get_context_data(**kwargs) + kwargs['has_objects'] = len(kwargs['object_list']) > 0 + return kwargs From 8c9f02a142b6272724dc9d8b58c714c612a15223 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Thu, 17 Aug 2017 21:46:13 +0200 Subject: [PATCH 03/18] Add fetch function for DSI --- club/models.py | 17 +++++++++++++++++ club/templates/club/mailing.jinja | 2 +- club/templates/club/mailing_output.jinja | 3 +++ club/urls.py | 1 + club/views.py | 14 ++++++++++++++ sith/settings.py | 5 +++++ sith/urls.py | 3 +++ 7 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 club/templates/club/mailing_output.jinja diff --git a/club/models.py b/club/models.py index 9484e4e2..90df31a3 100644 --- a/club/models.py +++ b/club/models.py @@ -231,6 +231,11 @@ class Mailing(models.Model): club = models.ForeignKey(Club, verbose_name=_('Club'), related_name="mailings", null=False, blank=False) email = models.EmailField(_('Email address'), unique=True) + def clean(self): + if '@' + settings.SITH_MAILING_ALLOWED_DOMAIN not in self.email: + raise ValidationError(_('Unothorized mailing domain')) + super(Mailing, self).clean() + def is_owned_by(self, user): return user.is_in_group(self) or user.is_root or user.is_board_member @@ -242,6 +247,15 @@ class Mailing(models.Model): sub.delete() super(Mailing, self).delete() + def base_mail(self): + return self.email.split('@')[0] + + def fetch_format(self): + resp = self.base_mail() + ': ' + for sub in self.subscriptions.all(): + resp += sub.fetch_format() + return resp + def __str__(self): return "%s - %s" % (self.club, self.email) @@ -270,6 +284,9 @@ class MailingSubscription(models.Model): def can_be_edited_by(self, user): return self.is_owned_by(user) or (user is not None and user.id == self.user.id) + def fetch_format(self): + return self.email + ' ' + def __str__(self): if self.user: user = str(self.user) diff --git a/club/templates/club/mailing.jinja b/club/templates/club/mailing.jinja index 47f11884..66e57864 100644 --- a/club/templates/club/mailing.jinja +++ b/club/templates/club/mailing.jinja @@ -10,7 +10,7 @@ {% for mailing in object_list %}

    {% trans %}Mailing{% endtrans %} {{ mailing.email }} {%- if user.is_owner(mailing) -%} - {% trans %}Delete{% endtrans %} + - {% trans %}Delete{% endtrans %} {%- endif -%}


    diff --git a/club/templates/club/mailing_output.jinja b/club/templates/club/mailing_output.jinja new file mode 100644 index 00000000..8a7133a7 --- /dev/null +++ b/club/templates/club/mailing_output.jinja @@ -0,0 +1,3 @@ +{%- for mailing in object_list -%} +{{ mailing.fetch_format() }} +{%- endfor -%} \ No newline at end of file diff --git a/club/urls.py b/club/urls.py index 42074a5c..bfd178a0 100644 --- a/club/urls.py +++ b/club/urls.py @@ -44,5 +44,6 @@ urlpatterns = [ url(r'^(?P[0-9]+)/mailing/new/subscription$', ClubMailingView.as_view(action=MailingFormType.MEMBER), name='mailing_subscription_create'), url(r'^(?P[0-9]+)/mailing/delete$', MailingDeleteView.as_view(), name='mailing_delete'), url(r'^(?P[0-9]+)/mailing/delete/subscription$', MailingSubscriptionDeleteView.as_view(), name='mailing_subscription_delete'), + url(r'^mailing/fetch$', MailingFetchView.as_view(), name='mailing_fetch'), url(r'^membership/(?P[0-9]+)/set_old$', MembershipSetOldView.as_view(), name='membership_set_old'), ] diff --git a/club/views.py b/club/views.py index 6a3b35a0..a283279c 100644 --- a/club/views.py +++ b/club/views.py @@ -44,6 +44,8 @@ from club.models import Club, Membership, Mailing, MailingSubscription from sith.settings import SITH_MAXIMUM_FREE_ROLE from counter.models import Selling, Counter +from django.conf import settings + # Custom forms @@ -505,3 +507,15 @@ class MailingSubscriptionDeleteView(CanEditMixin, DeleteView): def get_success_url(self, **kwargs): return reverse_lazy('club:mailing', kwargs={'club_id': self.club_id}) + + +class MailingFetchView(ListView): + + model = Mailing + template_name = 'club/mailing_output.jinja' + + def dispatch(self, request, *args, **kwargs): + key = request.GET.get('key', '') + if key != settings.SITH_MAILING_FETCH_KEY: + raise PermissionDenied + return super(MailingFetchView, self).dispatch(request, *args, **kwargs) diff --git a/sith/settings.py b/sith/settings.py index ff08d42d..3f492281 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -586,3 +586,8 @@ if DEBUG: SASS_INCLUDE_FOLDERS = [ 'core/static/', ] + +# Mailing related settings + +SITH_MAILING_ALLOWED_DOMAIN = 'utbm.fr' +SITH_MAILING_FETCH_KEY = 'IloveMails' diff --git a/sith/urls.py b/sith/urls.py index 2b744c24..e21a53cb 100644 --- a/sith/urls.py +++ b/sith/urls.py @@ -43,6 +43,7 @@ from django.conf.urls.static import static from django.conf import settings from django.views.i18n import javascript_catalog from ajax_select import urls as ajax_select_urls +from club.views import MailingFetchView js_info_dict = { 'packages': ('sith',), @@ -72,6 +73,8 @@ urlpatterns = [ url(r'^ajax_select/', include(ajax_select_urls)), url(r'^i18n/', include('django.conf.urls.i18n')), url(r'^jsi18n/$', javascript_catalog, js_info_dict, name='javascript-catalog'), + # This url is for legacy use + url(r'^mailing.php$', MailingFetchView.as_view(), name='mailing_fetch_legacy'), ] if settings.DEBUG: From e82e338e766f93481b6a9ab4f0f6782afb02fce8 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Fri, 18 Aug 2017 12:40:36 +0200 Subject: [PATCH 04/18] Fix mailing settings position --- sith/settings.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sith/settings.py b/sith/settings.py index 3f492281..0e3c7a1f 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -560,6 +560,11 @@ SITH_QUICK_NOTIF = { 'qn_weekmail_send_success': _("You successfully sent the Weekmail"), } +# Mailing related settings + +SITH_MAILING_ALLOWED_DOMAIN = 'utbm.fr' +SITH_MAILING_FETCH_KEY = 'IloveMails' + try: from .settings_custom import * print("Custom settings imported") @@ -586,8 +591,3 @@ if DEBUG: SASS_INCLUDE_FOLDERS = [ 'core/static/', ] - -# Mailing related settings - -SITH_MAILING_ALLOWED_DOMAIN = 'utbm.fr' -SITH_MAILING_FETCH_KEY = 'IloveMails' From 3a6f7009fd51aa92c665a248989de37ed06812a5 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Fri, 18 Aug 2017 23:09:01 +0200 Subject: [PATCH 05/18] Fix display rights in user profile for mailing --- core/templates/core/user_clubs.jinja | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/templates/core/user_clubs.jinja b/core/templates/core/user_clubs.jinja index 9d138695..222a3eb7 100644 --- a/core/templates/core/user_clubs.jinja +++ b/core/templates/core/user_clubs.jinja @@ -59,9 +59,9 @@ -{% if user.mailing_subscriptions.exists() %} +{% if profile.mailing_subscriptions.exists() and (profile.id == user.id or user.is_root) %}

    {% trans %}Subscribed mailing lists{% endtrans %}

    - {% for sub in user.mailing_subscriptions.all() %} + {% for sub in profile.mailing_subscriptions.all() %}

    {{ sub }} {% trans %}Unsuscribe{% endtrans %}

    {% endfor %} {% endif %} From 69e997d587b017c7584959030ba300c2704467ad Mon Sep 17 00:00:00 2001 From: klmp200 Date: Sat, 19 Aug 2017 01:19:31 +0200 Subject: [PATCH 06/18] Refactoring mailings --- api/urls.py | 1 + api/views/club.py | 20 +++++++++- club/models.py | 2 + club/templates/club/mailing.jinja | 4 +- club/templates/club/mailing_output.jinja | 3 -- club/urls.py | 7 ++-- club/views.py | 47 ++++-------------------- sith/urls.py | 3 -- 8 files changed, 34 insertions(+), 53 deletions(-) delete mode 100644 club/templates/club/mailing_output.jinja diff --git a/api/urls.py b/api/urls.py index 299d04a6..1289668f 100644 --- a/api/urls.py +++ b/api/urls.py @@ -48,5 +48,6 @@ urlpatterns = [ url(r'^', include(router.urls)), url(r'^login/', include('rest_framework.urls', namespace='rest_framework')), url(r'^markdown$', RenderMarkdown, name='api_markdown'), + url(r'^mailings$', FetchMailingLists, name='mailings_fetch') ] diff --git a/api/views/club.py b/api/views/club.py index fae04fc3..ece79602 100644 --- a/api/views/club.py +++ b/api/views/club.py @@ -22,9 +22,15 @@ # # +from rest_framework.response import Response from rest_framework import serializers +from rest_framework.decorators import api_view, renderer_classes +from rest_framework.renderers import StaticHTMLRenderer -from club.models import Club +from django.conf import settings +from django.core.exceptions import PermissionDenied + +from club.models import Club, Mailing from api.views import RightModelViewSet @@ -43,3 +49,15 @@ class ClubViewSet(RightModelViewSet): serializer_class = ClubSerializer queryset = Club.objects.all() + + +@api_view(['GET']) +@renderer_classes((StaticHTMLRenderer,)) +def FetchMailingLists(request): + key = request.GET.get('key', '') + if key != settings.SITH_MAILING_FETCH_KEY: + raise PermissionDenied + data = '' + for mailing in Mailing.objects.all(): + data += mailing.fetch_format() + return Response(data) diff --git a/club/models.py b/club/models.py index 90df31a3..7cac6154 100644 --- a/club/models.py +++ b/club/models.py @@ -276,6 +276,8 @@ class MailingSubscription(models.Model): raise ValidationError(_("At least user or email is required")) 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")) super(MailingSubscription, self).clean() def is_owned_by(self, user): diff --git a/club/templates/club/mailing.jinja b/club/templates/club/mailing.jinja index 66e57864..101e630e 100644 --- a/club/templates/club/mailing.jinja +++ b/club/templates/club/mailing.jinja @@ -41,7 +41,7 @@

    {% trans %}New member{% endtrans %}

    {% csrf_token %} - {{ new_member.as_p() }} + {{ add_member.as_p() }}

    {% endif %} @@ -49,7 +49,7 @@

    {% trans %}New mailing{% endtrans %}

    {% csrf_token %} - {{ new_mailing.as_p() }} + {{ add_mailing.as_p() }}

    diff --git a/club/templates/club/mailing_output.jinja b/club/templates/club/mailing_output.jinja deleted file mode 100644 index 8a7133a7..00000000 --- a/club/templates/club/mailing_output.jinja +++ /dev/null @@ -1,3 +0,0 @@ -{%- for mailing in object_list -%} -{{ mailing.fetch_format() }} -{%- endfor -%} \ No newline at end of file diff --git a/club/urls.py b/club/urls.py index bfd178a0..96195b11 100644 --- a/club/urls.py +++ b/club/urls.py @@ -39,11 +39,10 @@ urlpatterns = [ url(r'^(?P[0-9]+)/sellings/csv$', ClubSellingCSVView.as_view(), name='sellings_csv'), url(r'^(?P[0-9]+)/prop$', ClubEditPropView.as_view(), name='club_prop'), url(r'^(?P[0-9]+)/tools$', ClubToolsView.as_view(), name='tools'), - url(r'^(?P[0-9]+)/mailing$', ClubMailingView.as_view(action=MailingFormType.DISPLAY), name='mailing'), - url(r'^(?P[0-9]+)/mailing/new/mailing$', ClubMailingView.as_view(action=MailingFormType.MAILING), name='mailing_create'), - url(r'^(?P[0-9]+)/mailing/new/subscription$', ClubMailingView.as_view(action=MailingFormType.MEMBER), name='mailing_subscription_create'), + url(r'^(?P[0-9]+)/mailing$', ClubMailingView.as_view(action="display"), name='mailing'), + url(r'^(?P[0-9]+)/mailing/new/mailing$', ClubMailingView.as_view(action="add_mailing"), name='mailing_create'), + url(r'^(?P[0-9]+)/mailing/new/subscription$', ClubMailingView.as_view(action="add_member"), name='mailing_subscription_create'), url(r'^(?P[0-9]+)/mailing/delete$', MailingDeleteView.as_view(), name='mailing_delete'), url(r'^(?P[0-9]+)/mailing/delete/subscription$', MailingSubscriptionDeleteView.as_view(), name='mailing_subscription_delete'), - url(r'^mailing/fetch$', MailingFetchView.as_view(), name='mailing_fetch'), url(r'^membership/(?P[0-9]+)/set_old$', MembershipSetOldView.as_view(), name='membership_set_old'), ] diff --git a/club/views.py b/club/views.py index a283279c..f372679e 100644 --- a/club/views.py +++ b/club/views.py @@ -75,18 +75,6 @@ class MailingSubscriptionForm(forms.ModelForm): if club_id: self.fields['mailing'].queryset = Mailing.objects.filter(club__id=club_id) - def clean(self): - cleaned_data = super(MailingSubscriptionForm, self).clean() - user = cleaned_data.get('user', None) - email = cleaned_data.get('email', None) - mailing = cleaned_data.get('mailing') - if not user and not email: - raise forms.ValidationError(_("At least user or email should be filled")) - if user and not email: - email = user.email - if user and MailingSubscription.objects.filter(mailing=mailing, email=email).exists(): - raise forms.ValidationError(_("This email is already suscribed in this mailing")) - user = AutoCompleteSelectField('users', label=_('User'), help_text=None, required=False) @@ -396,12 +384,6 @@ class ClubStatView(TemplateView): return kwargs -class MailingFormType(Enum): - DISPLAY = 0 - MEMBER = 1 - MAILING = 2 - - class ClubMailingView(ClubTabsMixin, ListView): """ A list of mailing for a given club @@ -426,16 +408,14 @@ class ClubMailingView(ClubTabsMixin, ListView): def post(self, request, *args, **kwargs): res = super(ClubMailingView, self).get(request, *args, **kwargs) - if self.action != MailingFormType.DISPLAY: - if self.action == MailingFormType.MAILING: + if self.action != "display": + if self.action == "add_mailing": form = MailingForm - string = 'new_mailing' model = Mailing - elif self.action == MailingFormType.MEMBER: + elif self.action == "add_member": form = MailingSubscriptionForm - string = 'new_member' model = MailingSubscription - return MailingGenericCreateView.as_view(model=model, list_view=self, form_class=form, form_kwarg_string=string)(request, *args, **kwargs) + return MailingGenericCreateView.as_view(model=model, list_view=self, form_class=form)(request, *args, **kwargs) return res def get_queryset(self): @@ -443,8 +423,8 @@ class ClubMailingView(ClubTabsMixin, ListView): def get_context_data(self, **kwargs): kwargs = super(ClubMailingView, self).get_context_data(**kwargs) - kwargs['new_member'] = self.member_form - kwargs['new_mailing'] = self.mailing_form + kwargs['add_member'] = self.member_form + kwargs['add_mailing'] = self.mailing_form kwargs['club'] = self.club kwargs['user'] = self.user kwargs['has_objects'] = len(kwargs['object_list']) > 0 @@ -457,13 +437,12 @@ class MailingGenericCreateView(CreateView, SingleObjectMixin): """ list_view = None form_class = None - form_kwarg_string = None def get_context_data(self, **kwargs): view_kwargs = self.list_view.get_context_data(**kwargs) for key, data in super(MailingGenericCreateView, self).get_context_data(**kwargs).items(): view_kwargs[key] = data - view_kwargs[self.form_kwarg_string] = view_kwargs['form'] + view_kwargs[self.list_view.action] = view_kwargs['form'] return view_kwargs def get_form_kwargs(self): @@ -507,15 +486,3 @@ class MailingSubscriptionDeleteView(CanEditMixin, DeleteView): def get_success_url(self, **kwargs): return reverse_lazy('club:mailing', kwargs={'club_id': self.club_id}) - - -class MailingFetchView(ListView): - - model = Mailing - template_name = 'club/mailing_output.jinja' - - def dispatch(self, request, *args, **kwargs): - key = request.GET.get('key', '') - if key != settings.SITH_MAILING_FETCH_KEY: - raise PermissionDenied - return super(MailingFetchView, self).dispatch(request, *args, **kwargs) diff --git a/sith/urls.py b/sith/urls.py index e21a53cb..2b744c24 100644 --- a/sith/urls.py +++ b/sith/urls.py @@ -43,7 +43,6 @@ from django.conf.urls.static import static from django.conf import settings from django.views.i18n import javascript_catalog from ajax_select import urls as ajax_select_urls -from club.views import MailingFetchView js_info_dict = { 'packages': ('sith',), @@ -73,8 +72,6 @@ urlpatterns = [ url(r'^ajax_select/', include(ajax_select_urls)), url(r'^i18n/', include('django.conf.urls.i18n')), url(r'^jsi18n/$', javascript_catalog, js_info_dict, name='javascript-catalog'), - # This url is for legacy use - url(r'^mailing.php$', MailingFetchView.as_view(), name='mailing_fetch_legacy'), ] if settings.DEBUG: From 76efb91e407aee38760cab5141096a110efbd337 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Sat, 19 Aug 2017 16:13:53 +0200 Subject: [PATCH 07/18] Move mailing list admin to com --- club/models.py | 6 ++--- club/templates/club/mailing.jinja | 2 ++ club/views.py | 7 +++--- .../templates/com/mailing_admin.jinja | 4 +-- com/urls.py | 1 + com/views.py | 25 ++++++++++++++++++- core/templates/core/user_clubs.jinja | 4 +-- core/templates/core/user_tools.jinja | 2 +- rootplace/urls.py | 1 - rootplace/views.py | 19 -------------- 10 files changed, 38 insertions(+), 33 deletions(-) rename rootplace/templates/rootplace/mailing_lists.jinja => com/templates/com/mailing_admin.jinja (68%) diff --git a/club/models.py b/club/models.py index 7cac6154..e8018fd4 100644 --- a/club/models.py +++ b/club/models.py @@ -237,7 +237,7 @@ class Mailing(models.Model): super(Mailing, self).clean() def is_owned_by(self, user): - return user.is_in_group(self) or user.is_root or user.is_board_member + return user.is_in_group(self) or user.is_root or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) def can_view(self, user): return self.club.has_rights_in_club(user) @@ -281,10 +281,10 @@ class MailingSubscription(models.Model): super(MailingSubscription, self).clean() def is_owned_by(self, user): - return self.mailing.club.has_rights_in_club(user) or user.is_root + return self.mailing.club.has_rights_in_club(user) or user.is_root or self.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) def can_be_edited_by(self, user): - return self.is_owned_by(user) or (user is not None and user.id == self.user.id) + return (user is not None and user.id == self.user.id) def fetch_format(self): return self.email + ' ' diff --git a/club/templates/club/mailing.jinja b/club/templates/club/mailing.jinja index 101e630e..6e51cf15 100644 --- a/club/templates/club/mailing.jinja +++ b/club/templates/club/mailing.jinja @@ -7,6 +7,8 @@ {% block content %} {% if has_objects %} + {% trans %}Remember : mailing lists need to be validated by the school to work, please inform us about any new mailing list created{% endtrans %} + {% for mailing in object_list %}

    {% trans %}Mailing{% endtrans %} {{ mailing.email }} {%- if user.is_owner(mailing) -%} diff --git a/club/views.py b/club/views.py index f372679e..0f3bc29a 100644 --- a/club/views.py +++ b/club/views.py @@ -24,9 +24,8 @@ # from django import forms -from enum import Enum from django.views.generic import ListView, DetailView, TemplateView -from django.views.generic.edit import DeleteView, FormView +from django.views.generic.edit import DeleteView from django.views.generic.detail import SingleObjectMixin from django.views.generic.edit import UpdateView, CreateView from django.http import HttpResponseRedirect, HttpResponse @@ -38,7 +37,7 @@ from ajax_select.fields import AutoCompleteSelectField from django.core.exceptions import PermissionDenied from django.shortcuts import get_object_or_404 -from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin, CanCreateMixin +from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin from core.views.forms import SelectDate, SelectDateTime from club.models import Club, Membership, Mailing, MailingSubscription from sith.settings import SITH_MAXIMUM_FREE_ROLE @@ -394,7 +393,7 @@ class ClubMailingView(ClubTabsMixin, ListView): current_tab = 'mailing' def authorized(self): - return self.club.has_rights_in_club(self.user) or self.user.is_root or self.user.is_board_member + return self.club.has_rights_in_club(self.user) or self.user.is_root or self.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) def dispatch(self, request, *args, **kwargs): self.club = get_object_or_404(Club, pk=kwargs['club_id']) diff --git a/rootplace/templates/rootplace/mailing_lists.jinja b/com/templates/com/mailing_admin.jinja similarity index 68% rename from rootplace/templates/rootplace/mailing_lists.jinja rename to com/templates/com/mailing_admin.jinja index 16fabf24..195b2c31 100644 --- a/rootplace/templates/rootplace/mailing_lists.jinja +++ b/com/templates/com/mailing_admin.jinja @@ -15,13 +15,13 @@ {% for mailing in object_list %} {{ mailing.email }} - {{ mailing.club }} {% trans %}Delete{% endtrans %} + {{ mailing.club }} {% trans %}Delete{% endtrans %} {% endfor %} {% else %} -

    {% trans %}No mailing existing{% endtrans %}

    +

    {% trans %}No mailing list existing{% endtrans %}

    {% endif %} {% endblock %} diff --git a/com/urls.py b/com/urls.py index 4daf16b1..89f0d92c 100644 --- a/com/urls.py +++ b/com/urls.py @@ -42,5 +42,6 @@ urlpatterns = [ url(r'^news/(?P[0-9]+)/moderate$', NewsModerateView.as_view(), name='news_moderate'), url(r'^news/(?P[0-9]+)/edit$', NewsEditView.as_view(), name='news_edit'), url(r'^news/(?P[0-9]+)$', NewsDetailView.as_view(), name='news_detail'), + url(r'^mailings$', MailingListAdminView.as_view(), name='mailing_admin'), ] diff --git a/com/views.py b/com/views.py index 8f675ef5..eb08f7e9 100644 --- a/com/views.py +++ b/com/views.py @@ -2,6 +2,7 @@ # # Copyright 2016,2017 # - Skia +# - Sli # # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, # http://ae.utbm.fr. @@ -34,6 +35,7 @@ from django.utils import timezone from django.conf import settings from django.db.models import Max from django.forms.models import modelform_factory +from django.core.exceptions import PermissionDenied from django import forms from datetime import timedelta @@ -42,7 +44,7 @@ from com.models import Sith, News, NewsDate, Weekmail, WeekmailArticle from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin, CanCreateMixin, QuickNotifMixin from core.views.forms import SelectDateTime from core.models import Notification, RealGroup -from club.models import Club +from club.models import Club, Mailing # Sith object @@ -81,6 +83,11 @@ class ComTabsMixin(TabedViewMixin): 'slug': 'alert', 'name': _("Alert message"), }) + tab_list.append({ + 'url': reverse('com:mailing_admin'), + 'slug': 'mailings', + 'name': _("Mailing lists administration"), + }) return tab_list @@ -414,3 +421,19 @@ class WeekmailArticleDeleteView(CanEditPropMixin, DeleteView): template_name = 'core/delete_confirm.jinja' success_url = reverse_lazy('com:weekmail') 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_in_group(settings.SITH_GROUP_COM_ADMIN_ID): + raise PermissionDenied + return super(MailingListAdminView, self).dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + kwargs = super(MailingListAdminView, self).get_context_data(**kwargs) + kwargs['has_objects'] = len(kwargs['object_list']) > 0 + return kwargs diff --git a/core/templates/core/user_clubs.jinja b/core/templates/core/user_clubs.jinja index 222a3eb7..17462120 100644 --- a/core/templates/core/user_clubs.jinja +++ b/core/templates/core/user_clubs.jinja @@ -59,10 +59,10 @@ -{% if profile.mailing_subscriptions.exists() and (profile.id == user.id or user.is_root) %} +{% if profile.mailing_subscriptions.exists() and (profile.id == user.id or user.is_root or self.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)) %}

    {% trans %}Subscribed mailing lists{% endtrans %}

    {% for sub in profile.mailing_subscriptions.all() %} -

    {{ sub }} {% trans %}Unsuscribe{% endtrans %}

    +

    {{ sub.mailing.email }} {% trans %}Unsuscribe{% endtrans %}

    {% endfor %} {% endif %} {% endblock %} diff --git a/core/templates/core/user_tools.jinja b/core/templates/core/user_tools.jinja index 3f7b0804..699b52f4 100644 --- a/core/templates/core/user_tools.jinja +++ b/core/templates/core/user_tools.jinja @@ -13,7 +13,6 @@ {% if user.is_root %}
  • {% trans %}Groups{% endtrans %}
  • {% trans %}Merge users{% endtrans %}
  • -
  • {% trans %}Mailing lists administration{% endtrans %}
  • {% endif %} {% if user.can_create_subscription or user.is_root %}
  • {% trans %}Subscriptions{% endtrans %}
  • @@ -88,6 +87,7 @@
  • {% trans %}Edit alert message{% endtrans %}
  • {% trans %}Edit information message{% endtrans %}
  • {% trans %}Moderate files{% endtrans %}
  • +
  • {% trans %}Mailing lists administration{% endtrans %}
  • {% endif %} {% if user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) %}
  • {% trans %}Moderate pictures{% endtrans %}
  • diff --git a/rootplace/urls.py b/rootplace/urls.py index 732efe1c..6ab433e3 100644 --- a/rootplace/urls.py +++ b/rootplace/urls.py @@ -28,5 +28,4 @@ from rootplace.views import * urlpatterns = [ url(r'^merge$', MergeUsersView.as_view(), name='merge'), - url(r'^mailings$', MailingListAdminView.as_view(), name='mailings') ] diff --git a/rootplace/views.py b/rootplace/views.py index 7aef0366..a03ab3ae 100644 --- a/rootplace/views.py +++ b/rootplace/views.py @@ -23,20 +23,16 @@ # # -from django.shortcuts import render from django.utils.translation import ugettext as _ from django.views.generic.edit import FormView from django.core.urlresolvers import reverse from django import forms -from django.views.generic import ListView from django.core.exceptions import PermissionDenied from ajax_select.fields import AutoCompleteSelectField -from core.views import CanViewMixin from core.models import User from counter.models import Customer -from club.models import Mailing def merge_users(u1, u2): @@ -112,18 +108,3 @@ class MergeUsersView(FormView): def get_success_url(self): return reverse('core:user_profile', kwargs={'user_id': self.final_user.id}) - - -class MailingListAdminView(ListView): - template_name = "rootplace/mailing_lists.jinja" - model = Mailing - - def dispatch(self, request, *args, **kwargs): - if not request.user.is_root: - raise PermissionDenied - return super(MailingListAdminView, self).dispatch(request, *args, **kwargs) - - def get_context_data(self, **kwargs): - kwargs = super(MailingListAdminView, self).get_context_data(**kwargs) - kwargs['has_objects'] = len(kwargs['object_list']) > 0 - return kwargs From 72d968e9a5fb44e4b70ea60395938cb6021026de Mon Sep 17 00:00:00 2001 From: klmp200 Date: Sat, 19 Aug 2017 17:06:43 +0200 Subject: [PATCH 08/18] Mailing migrations --- migrate.py | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/migrate.py b/migrate.py index ad310a1a..005e17b9 100644 --- a/migrate.py +++ b/migrate.py @@ -46,7 +46,7 @@ from django.core.files import File from core.models import User, SithFile from core.utils import doku_to_markdown, bbcode_to_markdown -from club.models import Club, Membership +from club.models import Club, Membership, Mailing, MailingSubscription from counter.models import Customer, Counter, Selling, Refilling, Product, ProductType, Permanency, Eticket from subscription.models import Subscription from eboutic.models import Invoice, InvoiceItem @@ -1332,6 +1332,37 @@ def migrate_forum(): print("Forum migrated at %s" % datetime.datetime.now()) print("Running time: %s" % (datetime.datetime.now()-start)) + +def migrate_mailings(): + cur = db.cursor(MySQLdb.cursors.SSDictCursor) + mailing_db = cur.execute(""" + SELECT * FROM mailing + """) + mailing_sub_db = cur.execute(""" + SELECT * FROM mailing_membres + """) + + for mailing in mailing_db: + club = Club.objects.filter(id=mailing['id_asso_parent']) + if club.exists(): + print(mailing) + club = club.first() + if mailing['nom']: + mailing['nom'] = '.' + mailing['nom'] + Mailing(id=mailing['id_mailing'], club=club, email=str(club.unix_name + mailing['nom'] + '@utbm.fr')).save() + print("-------------------") + for mailing_sub in mailing_sub_db: + mailing = Mailing.objects.filter(id=mailing_sub['id_mailing']) + if mailing.exists(): + print(mailing_sub) + mailing = mailing.first() + if mailing_sub['id_user'] and User.objects.filter(id=mailing_sub['id_user']).exists(): + user = User.objects.get(id=mailing_sub['id_user']) + MailingSubscription(mailing=mailing, user=user, email=user.email).save() + elif mailing_sub['email']: + MailingSubscription(mailing=mailing, email=mailing_sub['email']).save() + + def main(): print("Start at %s" % start) # Core @@ -1351,11 +1382,12 @@ def main(): # migrate_sas() # reset_index('core', 'sas') # reset_sas_moderators() - migrate_forum() - reset_index('forum') + # migrate_forum() + # reset_index('forum') end = datetime.datetime.now() print("End at %s" % end) - print("Running time: %s" % (end-start)) + print("Running time: %s" % (end - start)) + if __name__ == "__main__": main() From 51992e1c30254d0df0c6de5a845e3d4af07202be Mon Sep 17 00:00:00 2001 From: klmp200 Date: Sat, 19 Aug 2017 17:17:16 +0200 Subject: [PATCH 09/18] Mailing migration --- migrate.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/migrate.py b/migrate.py index 005e17b9..18202b40 100644 --- a/migrate.py +++ b/migrate.py @@ -1335,6 +1335,13 @@ def migrate_forum(): def migrate_mailings(): cur = db.cursor(MySQLdb.cursors.SSDictCursor) + + print("Delete all mailings") + + Mailing.objects.all().delete() + + print("Migrating old database") + mailing_db = cur.execute(""" SELECT * FROM mailing """) @@ -1384,6 +1391,7 @@ def main(): # reset_sas_moderators() # migrate_forum() # reset_index('forum') + migrate_mailings() end = datetime.datetime.now() print("End at %s" % end) print("Running time: %s" % (end - start)) From cc8991a9382de66a921135fe58e53067ba97189d Mon Sep 17 00:00:00 2001 From: klmp200 Date: Sat, 19 Aug 2017 17:22:33 +0200 Subject: [PATCH 10/18] Fix migration for mailing --- migrate.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/migrate.py b/migrate.py index 18202b40..8f63561c 100644 --- a/migrate.py +++ b/migrate.py @@ -1342,14 +1342,11 @@ def migrate_mailings(): print("Migrating old database") - mailing_db = cur.execute(""" + cur.execute(""" SELECT * FROM mailing """) - mailing_sub_db = cur.execute(""" - SELECT * FROM mailing_membres - """) - for mailing in mailing_db: + for mailing in cur: club = Club.objects.filter(id=mailing['id_asso_parent']) if club.exists(): print(mailing) @@ -1358,7 +1355,12 @@ def migrate_mailings(): mailing['nom'] = '.' + mailing['nom'] Mailing(id=mailing['id_mailing'], club=club, email=str(club.unix_name + mailing['nom'] + '@utbm.fr')).save() print("-------------------") - for mailing_sub in mailing_sub_db: + + cur.execute(""" + SELECT * FROM mailing_membres + """) + + for mailing_sub in cur: mailing = Mailing.objects.filter(id=mailing_sub['id_mailing']) if mailing.exists(): print(mailing_sub) From 9e5159152a81a36f59970ec2331798445f6113a2 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Sat, 19 Aug 2017 17:27:01 +0200 Subject: [PATCH 11/18] Little right fix --- com/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com/views.py b/com/views.py index eb08f7e9..a005ab8f 100644 --- a/com/views.py +++ b/com/views.py @@ -429,7 +429,7 @@ class MailingListAdminView(ComTabsMixin, ListView): current_tab = "mailings" def dispatch(self, request, *args, **kwargs): - if not request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID): + if not request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or request.user.is_root: raise PermissionDenied return super(MailingListAdminView, self).dispatch(request, *args, **kwargs) From ce9e17ea24a58681ab61d56db6667fc7d79f3d33 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Mon, 21 Aug 2017 14:19:49 +0200 Subject: [PATCH 12/18] Some mailing list fixs --- com/templates/com/mailing_admin.jinja | 2 +- core/templates/core/user_clubs.jinja | 2 +- migrate.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/com/templates/com/mailing_admin.jinja b/com/templates/com/mailing_admin.jinja index 195b2c31..b0c7be95 100644 --- a/com/templates/com/mailing_admin.jinja +++ b/com/templates/com/mailing_admin.jinja @@ -5,7 +5,7 @@ {% endblock %} {% block content %} -

    {% trans %}This page list all existing mailing lists{% endtrans %}

    +

    {% trans %}This page lists all existing mailing lists{% endtrans %}

    {% if has_objects %} diff --git a/core/templates/core/user_clubs.jinja b/core/templates/core/user_clubs.jinja index 17462120..93cd0958 100644 --- a/core/templates/core/user_clubs.jinja +++ b/core/templates/core/user_clubs.jinja @@ -62,7 +62,7 @@ {% if profile.mailing_subscriptions.exists() and (profile.id == user.id or user.is_root or self.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)) %}

    {% trans %}Subscribed mailing lists{% endtrans %}

    {% for sub in profile.mailing_subscriptions.all() %} -

    {{ sub.mailing.email }} {% trans %}Unsuscribe{% endtrans %}

    +

    {{ sub.mailing.email }} {% trans %}Unsubscribe{% endtrans %}

    {% endfor %} {% endif %} {% endblock %} diff --git a/migrate.py b/migrate.py index 8f63561c..475d0633 100644 --- a/migrate.py +++ b/migrate.py @@ -1353,7 +1353,7 @@ def migrate_mailings(): club = club.first() if mailing['nom']: mailing['nom'] = '.' + mailing['nom'] - Mailing(id=mailing['id_mailing'], club=club, email=str(club.unix_name + mailing['nom'] + '@utbm.fr')).save() + Mailing(id=mailing['id_mailing'], club=club, email=to_unicode(club.unix_name + mailing['nom'] + '@utbm.fr')).save() print("-------------------") cur.execute(""" @@ -1369,7 +1369,7 @@ def migrate_mailings(): user = User.objects.get(id=mailing_sub['id_user']) MailingSubscription(mailing=mailing, user=user, email=user.email).save() elif mailing_sub['email']: - MailingSubscription(mailing=mailing, email=mailing_sub['email']).save() + MailingSubscription(mailing=mailing, email=to_unicode(mailing_sub['email'])).save() def main(): From fe187dae382acc73b30ef1ee3dc7be2d7df5ab5f Mon Sep 17 00:00:00 2001 From: klmp200 Date: Mon, 21 Aug 2017 15:53:32 +0200 Subject: [PATCH 13/18] Only begining of the mail is now needed --- club/models.py | 2 +- club/views.py | 17 +++++++++++++++++ sith/settings.py | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/club/models.py b/club/models.py index e8018fd4..7c05faa5 100644 --- a/club/models.py +++ b/club/models.py @@ -232,7 +232,7 @@ class Mailing(models.Model): email = models.EmailField(_('Email address'), unique=True) def clean(self): - if '@' + settings.SITH_MAILING_ALLOWED_DOMAIN not in self.email: + if '@' + settings.SITH_MAILING_DOMAIN not in self.email: raise ValidationError(_('Unothorized mailing domain')) super(Mailing, self).clean() diff --git a/club/views.py b/club/views.py index 0f3bc29a..f0f967ff 100644 --- a/club/views.py +++ b/club/views.py @@ -36,6 +36,7 @@ from django.utils.translation import ugettext as _t from ajax_select.fields import AutoCompleteSelectField from django.core.exceptions import PermissionDenied from django.shortcuts import get_object_or_404 +from django.core.validators import RegexValidator, validate_email from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin from core.views.forms import SelectDate, SelectDateTime @@ -53,6 +54,16 @@ class MailingForm(forms.ModelForm): model = Mailing fields = ('email', 'club') + email = forms.CharField( + label=_('Email address'), + validators=[ + RegexValidator( + validate_email.user_regex, + _('Enter a valid address. Only the root of the address is needed.') + ) + ], + required=True) + def __init__(self, *args, **kwargs): club_id = kwargs.pop('club_id', None) super(MailingForm, self).__init__(*args, **kwargs) @@ -61,6 +72,12 @@ class MailingForm(forms.ModelForm): self.fields['club'].initial = club_id self.fields['club'].widget = forms.HiddenInput() + def clean(self): + cleaned_data = super(MailingForm, self).clean() + if self.is_valid(): + cleaned_data['email'] += '@' + settings.SITH_MAILING_DOMAIN + return cleaned_data + class MailingSubscriptionForm(forms.ModelForm): class Meta: diff --git a/sith/settings.py b/sith/settings.py index 0e3c7a1f..574b1492 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -562,7 +562,7 @@ SITH_QUICK_NOTIF = { # Mailing related settings -SITH_MAILING_ALLOWED_DOMAIN = 'utbm.fr' +SITH_MAILING_DOMAIN = 'utbm.fr' SITH_MAILING_FETCH_KEY = 'IloveMails' try: From 470680e760012b50c6ec23327c7d8038193a4453 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Mon, 21 Aug 2017 19:53:17 +0200 Subject: [PATCH 14/18] Add moderation for mailing lists --- api/views/club.py | 2 +- club/migrations/0011_auto_20170821_1702.py | 26 ++++++++++++++++ club/models.py | 35 ++++++++++++++++------ club/templates/club/mailing.jinja | 4 ++- club/views.py | 20 ++++++++++--- com/templates/com/mailing_admin.jinja | 25 ++++++++++++---- com/urls.py | 3 ++ com/views.py | 22 ++++++++++++-- migrate.py | 5 +++- sith/settings.py | 1 + 10 files changed, 119 insertions(+), 24 deletions(-) create mode 100644 club/migrations/0011_auto_20170821_1702.py diff --git a/api/views/club.py b/api/views/club.py index ece79602..03b7f36c 100644 --- a/api/views/club.py +++ b/api/views/club.py @@ -58,6 +58,6 @@ def FetchMailingLists(request): if key != settings.SITH_MAILING_FETCH_KEY: raise PermissionDenied data = '' - for mailing in Mailing.objects.all(): + for mailing in Mailing.objects.filter(is_moderated=True).all(): data += mailing.fetch_format() return Response(data) diff --git a/club/migrations/0011_auto_20170821_1702.py b/club/migrations/0011_auto_20170821_1702.py new file mode 100644 index 00000000..04588b8b --- /dev/null +++ b/club/migrations/0011_auto_20170821_1702.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('club', '0010_auto_20170817_1537'), + ] + + operations = [ + migrations.AddField( + model_name='mailing', + name='is_moderated', + field=models.BooleanField(default=False, verbose_name='is moderated'), + ), + migrations.AddField( + model_name='mailing', + name='moderator', + field=models.ForeignKey(related_name='moderated_mailings', to=settings.AUTH_USER_MODEL, null=True, verbose_name='moderator'), + ), + ] diff --git a/club/models.py b/club/models.py index 7c05faa5..5bf85d86 100644 --- a/club/models.py +++ b/club/models.py @@ -27,12 +27,12 @@ from django.db import models from django.core import validators from django.conf import settings from django.utils.translation import ugettext_lazy as _ -from django.core.exceptions import ValidationError +from django.core.exceptions import ValidationError, ObjectDoesNotExist from django.db import transaction from django.core.urlresolvers import reverse from django.utils import timezone -from core.models import User, MetaGroup, Group, SithFile +from core.models import User, MetaGroup, Group, SithFile, RealGroup, Notification # Create your models here. @@ -230,11 +230,18 @@ class Mailing(models.Model): """ club = models.ForeignKey(Club, verbose_name=_('Club'), related_name="mailings", null=False, blank=False) email = models.EmailField(_('Email address'), unique=True) + is_moderated = models.BooleanField(_('is moderated'), default=False) + moderator = models.ForeignKey(User, related_name="moderated_mailings", verbose_name=_("moderator"), null=True) def clean(self): - if '@' + settings.SITH_MAILING_DOMAIN not in self.email: - raise ValidationError(_('Unothorized mailing domain')) - super(Mailing, self).clean() + if self.can_moderate(self.moderator): + self.is_moderated = True + else: + self.moderator = None + super(Mailing, self).clean() + + def can_moderate(self, user): + return user.is_root or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) def is_owned_by(self, user): return user.is_in_group(self) or user.is_root or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) @@ -256,6 +263,13 @@ class Mailing(models.Model): resp += sub.fetch_format() return resp + def save(self): + if not self.is_moderated: + for user in RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID).first().users.all(): + if not user.notifications.filter(type="MAILING_MODERATION", viewed=False).exists(): + Notification(user=user, url=reverse('com:mailing_admin'), type="MAILING_MODERATION").save() + super(Mailing, self).save() + def __str__(self): return "%s - %s" % (self.club, self.email) @@ -274,10 +288,13 @@ class MailingSubscription(models.Model): def clean(self): if not self.user and not self.email: raise ValidationError(_("At least user or email is required")) - 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")) + 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(MailingSubscription, self).clean() def is_owned_by(self, user): diff --git a/club/templates/club/mailing.jinja b/club/templates/club/mailing.jinja index 6e51cf15..797abb12 100644 --- a/club/templates/club/mailing.jinja +++ b/club/templates/club/mailing.jinja @@ -7,9 +7,10 @@ {% block content %} {% if has_objects %} - {% trans %}Remember : mailing lists need to be validated by the school to work, please inform us about any new mailing list created{% endtrans %} + {% trans %}Remember : mailing lists need to be moderated, if your new created list is not shown wait until moderation takes action{% endtrans %} {% for mailing in object_list %} + {% if mailing.is_moderated %}

    {% trans %}Mailing{% endtrans %} {{ mailing.email }} {%- if user.is_owner(mailing) -%} - {% trans %}Delete{% endtrans %} @@ -33,6 +34,7 @@

    {% endfor %}
    + {% endif %} {% endfor %} {% else %} diff --git a/club/views.py b/club/views.py index f0f967ff..77a1979d 100644 --- a/club/views.py +++ b/club/views.py @@ -43,6 +43,7 @@ from core.views.forms import SelectDate, SelectDateTime from club.models import Club, Membership, Mailing, MailingSubscription from sith.settings import SITH_MAXIMUM_FREE_ROLE from counter.models import Selling, Counter +from core.models import User from django.conf import settings @@ -52,7 +53,7 @@ from django.conf import settings class MailingForm(forms.ModelForm): class Meta: model = Mailing - fields = ('email', 'club') + fields = ('email', 'club', 'moderator') email = forms.CharField( label=_('Email address'), @@ -66,11 +67,16 @@ class MailingForm(forms.ModelForm): def __init__(self, *args, **kwargs): club_id = kwargs.pop('club_id', None) + user_id = kwargs.pop('user_id', -1) # Remember 0 is treated as None super(MailingForm, self).__init__(*args, **kwargs) if club_id: self.fields['club'].queryset = Club.objects.filter(id=club_id) self.fields['club'].initial = club_id self.fields['club'].widget = forms.HiddenInput() + if user_id >= 0: + self.fields['moderator'].queryset = User.objects.filter(id=user_id) + self.fields['moderator'].initial = user_id + self.fields['moderator'].widget = forms.HiddenInput() def clean(self): cleaned_data = super(MailingForm, self).clean() @@ -85,11 +91,12 @@ class MailingSubscriptionForm(forms.ModelForm): fields = ('mailing', 'user', 'email') def __init__(self, *args, **kwargs): + kwargs.pop('user_id', None) # For standart interface club_id = kwargs.pop('club_id', None) super(MailingSubscriptionForm, self).__init__(*args, **kwargs) self.fields['email'].required = False if club_id: - self.fields['mailing'].queryset = Mailing.objects.filter(club__id=club_id) + self.fields['mailing'].queryset = Mailing.objects.filter(club__id=club_id, is_moderated=True) user = AutoCompleteSelectField('users', label=_('User'), help_text=None, required=False) @@ -419,7 +426,7 @@ class ClubMailingView(ClubTabsMixin, ListView): if not self.authorized(): raise PermissionDenied self.member_form = MailingSubscriptionForm(club_id=self.club.id) - self.mailing_form = MailingForm(club_id=self.club.id) + self.mailing_form = MailingForm(club_id=self.club.id, user_id=self.user.id) return super(ClubMailingView, self).dispatch(request, *args, **kwargs) def post(self, request, *args, **kwargs): @@ -464,6 +471,7 @@ class MailingGenericCreateView(CreateView, SingleObjectMixin): def get_form_kwargs(self): kwargs = super(MailingGenericCreateView, self).get_form_kwargs() kwargs['club_id'] = self.list_view.club.id + kwargs['user_id'] = self.list_view.user.id return kwargs def dispatch(self, request, *args, **kwargs): @@ -481,13 +489,17 @@ 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(MailingDeleteView, self).dispatch(request, *args, **kwargs) def get_success_url(self, **kwargs): - return reverse_lazy('club:mailing', kwargs={'club_id': self.club_id}) + 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): diff --git a/com/templates/com/mailing_admin.jinja b/com/templates/com/mailing_admin.jinja index b0c7be95..15784fc1 100644 --- a/com/templates/com/mailing_admin.jinja +++ b/com/templates/com/mailing_admin.jinja @@ -4,22 +4,37 @@ {% trans %}Mailing lists administration{% endtrans %} {% endblock %} -{% block content %} -

    {% trans %}This page lists all existing mailing lists{% endtrans %}

    - {% if has_objects %} +{% macro display_mailings(list) %} + - {% for mailing in object_list %} + {% for mailing in list %} - + + {% endfor %}
    {% trans %}Email{% endtrans %} {% trans %}Club{%endtrans%}{% trans %}Actions{% endtrans %}
    {{ mailing.email }}{{ mailing.club }} {% trans %}Delete{% endtrans %}{{ mailing.club }} + {% trans %}Delete{% endtrans %} - {% if not mailing.is_moderated %}{% trans %}Moderate{% endtrans %}{% else %}{% trans user=mailing.moderator %}Moderated by {{ user }}{% endtrans %}{% endif %} +
    + +{% 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 %} diff --git a/com/urls.py b/com/urls.py index 89f0d92c..f5421758 100644 --- a/com/urls.py +++ b/com/urls.py @@ -25,6 +25,7 @@ from django.conf.urls import url from com.views import * +from club.views import MailingDeleteView urlpatterns = [ url(r'^sith/edit/alert$', AlertMsgEditView.as_view(), name='alert_edit'), @@ -43,5 +44,7 @@ urlpatterns = [ url(r'^news/(?P[0-9]+)/edit$', NewsEditView.as_view(), name='news_edit'), url(r'^news/(?P[0-9]+)$', NewsDetailView.as_view(), name='news_detail'), url(r'^mailings$', MailingListAdminView.as_view(), name='mailing_admin'), + url(r'^mailings/(?P[0-9]+)/moderate$', MailingModerateView.as_view(), name='mailing_moderate'), + url(r'^mailings/(?P[0-9]+)/delete$', MailingDeleteView.as_view(redirect_page='com:mailing_admin'), name='mailing_delete'), ] diff --git a/com/views.py b/com/views.py index a005ab8f..942ed335 100644 --- a/com/views.py +++ b/com/views.py @@ -25,7 +25,7 @@ from django.shortcuts import redirect, get_object_or_404 from django.http import HttpResponseRedirect -from django.views.generic import ListView, DetailView +from django.views.generic import ListView, DetailView, View from django.views.generic.edit import UpdateView, CreateView, DeleteView from django.views.generic.detail import SingleObjectMixin from django.utils.translation import ugettext_lazy as _ @@ -429,11 +429,27 @@ class MailingListAdminView(ComTabsMixin, ListView): current_tab = "mailings" def dispatch(self, request, *args, **kwargs): - if not request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or request.user.is_root: + if not (request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or request.user.is_root): raise PermissionDenied return super(MailingListAdminView, self).dispatch(request, *args, **kwargs) def get_context_data(self, **kwargs): kwargs = super(MailingListAdminView, self).get_context_data(**kwargs) - kwargs['has_objects'] = len(kwargs['object_list']) > 0 + 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 diff --git a/migrate.py b/migrate.py index 475d0633..5858af46 100644 --- a/migrate.py +++ b/migrate.py @@ -1346,6 +1346,8 @@ def migrate_mailings(): SELECT * FROM mailing """) + moderator = User.objects.get(id=0) + for mailing in cur: club = Club.objects.filter(id=mailing['id_asso_parent']) if club.exists(): @@ -1353,7 +1355,8 @@ def migrate_mailings(): club = club.first() if mailing['nom']: mailing['nom'] = '.' + mailing['nom'] - Mailing(id=mailing['id_mailing'], club=club, email=to_unicode(club.unix_name + mailing['nom'] + '@utbm.fr')).save() + Mailing(id=mailing['id_mailing'], club=club, email=to_unicode(club.unix_name + mailing['nom'] + '@utbm.fr'), + moderator=moderator, is_moderated=(mailing['is_valid'] > 0)).save() print("-------------------") cur.execute(""" diff --git a/sith/settings.py b/sith/settings.py index 574b1492..a448a394 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -543,6 +543,7 @@ SITH_LAUNDERETTE_PRICES = { } SITH_NOTIFICATIONS = [ + ('MAILING_MODERATION', _("A new mailing list neet to be moderated")), ('NEWS_MODERATION', _("A fresh new to be moderated")), ('FILE_MODERATION', _("New files to be moderated")), ('SAS_MODERATION', _("New pictures/album to be moderated in the SAS")), From d179a0a6d0f960fb8beb70858bfa21834e7adea7 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Tue, 22 Aug 2017 15:34:48 +0200 Subject: [PATCH 15/18] Fix typo and merge migrations --- club/migrations/0009_auto_20170822_1529.py | 39 +++++++++++++++++++ .../0009_mailing_mailingsubscription.py | 33 ---------------- club/migrations/0010_auto_20170817_1537.py | 23 ----------- club/migrations/0011_auto_20170821_1702.py | 26 ------------- core/migrations/0021_auto_20170822_1529.py | 19 +++++++++ sith/settings.py | 2 +- 6 files changed, 59 insertions(+), 83 deletions(-) create mode 100644 club/migrations/0009_auto_20170822_1529.py delete mode 100644 club/migrations/0009_mailing_mailingsubscription.py delete mode 100644 club/migrations/0010_auto_20170817_1537.py delete mode 100644 club/migrations/0011_auto_20170821_1702.py create mode 100644 core/migrations/0021_auto_20170822_1529.py diff --git a/club/migrations/0009_auto_20170822_1529.py b/club/migrations/0009_auto_20170822_1529.py new file mode 100644 index 00000000..419f3890 --- /dev/null +++ b/club/migrations/0009_auto_20170822_1529.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('club', '0008_auto_20170515_2214'), + ] + + operations = [ + migrations.CreateModel( + name='Mailing', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, primary_key=True, auto_created=True)), + ('email', models.EmailField(verbose_name='Email address', max_length=254, unique=True)), + ('is_moderated', models.BooleanField(verbose_name='is moderated', default=False)), + ('club', models.ForeignKey(related_name='mailings', to='club.Club', verbose_name='Club')), + ('moderator', models.ForeignKey(related_name='moderated_mailings', to=settings.AUTH_USER_MODEL, verbose_name='moderator', null=True)), + ], + ), + migrations.CreateModel( + name='MailingSubscription', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, primary_key=True, auto_created=True)), + ('email', models.EmailField(verbose_name='Email address', max_length=254)), + ('mailing', models.ForeignKey(related_name='subscriptions', to='club.Mailing', verbose_name='Mailing')), + ('user', models.ForeignKey(null=True, related_name='mailing_subscriptions', to=settings.AUTH_USER_MODEL, verbose_name='User', blank=True)), + ], + ), + migrations.AlterUniqueTogether( + name='mailingsubscription', + unique_together=set([('user', 'email', 'mailing')]), + ), + ] diff --git a/club/migrations/0009_mailing_mailingsubscription.py b/club/migrations/0009_mailing_mailingsubscription.py deleted file mode 100644 index a87fceeb..00000000 --- a/club/migrations/0009_mailing_mailingsubscription.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models -from django.conf import settings - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('club', '0008_auto_20170515_2214'), - ] - - operations = [ - migrations.CreateModel( - name='Mailing', - fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), - ('email', models.EmailField(verbose_name='Email address', unique=True, max_length=254)), - ('club', models.ForeignKey(verbose_name='Club', related_name='mailings', to='club.Club')), - ], - ), - migrations.CreateModel( - name='MailingSubscription', - fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), - ('email', models.EmailField(verbose_name='Email address', max_length=254, unique=True)), - ('mailing', models.ForeignKey(verbose_name='Mailing', related_name='subscriptions', to='club.Mailing')), - ('user', models.ForeignKey(null=True, verbose_name='User', related_name='mailing_subscriptions', to=settings.AUTH_USER_MODEL, blank=True)), - ], - ), - ] diff --git a/club/migrations/0010_auto_20170817_1537.py b/club/migrations/0010_auto_20170817_1537.py deleted file mode 100644 index 24949949..00000000 --- a/club/migrations/0010_auto_20170817_1537.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('club', '0009_mailing_mailingsubscription'), - ] - - operations = [ - migrations.AlterField( - model_name='mailingsubscription', - name='email', - field=models.EmailField(verbose_name='Email address', max_length=254), - ), - migrations.AlterUniqueTogether( - name='mailingsubscription', - unique_together=set([('user', 'email', 'mailing')]), - ), - ] diff --git a/club/migrations/0011_auto_20170821_1702.py b/club/migrations/0011_auto_20170821_1702.py deleted file mode 100644 index 04588b8b..00000000 --- a/club/migrations/0011_auto_20170821_1702.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models -from django.conf import settings - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('club', '0010_auto_20170817_1537'), - ] - - operations = [ - migrations.AddField( - model_name='mailing', - name='is_moderated', - field=models.BooleanField(default=False, verbose_name='is moderated'), - ), - migrations.AddField( - model_name='mailing', - name='moderator', - field=models.ForeignKey(related_name='moderated_mailings', to=settings.AUTH_USER_MODEL, null=True, verbose_name='moderator'), - ), - ] diff --git a/core/migrations/0021_auto_20170822_1529.py b/core/migrations/0021_auto_20170822_1529.py new file mode 100644 index 00000000..b38e737d --- /dev/null +++ b/core/migrations/0021_auto_20170822_1529.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0020_auto_20170324_0917'), + ] + + operations = [ + migrations.AlterField( + model_name='notification', + name='type', + field=models.CharField(verbose_name='type', default='GENERIC', max_length=32, choices=[('MAILING_MODERATION', 'A new mailing list neet to be moderated'), ('NEWS_MODERATION', 'A fresh new to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'New pictures/album to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')]), + ), + ] diff --git a/sith/settings.py b/sith/settings.py index a448a394..abfed0ed 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -543,7 +543,7 @@ SITH_LAUNDERETTE_PRICES = { } SITH_NOTIFICATIONS = [ - ('MAILING_MODERATION', _("A new mailing list neet to be moderated")), + ('MAILING_MODERATION', _("A new mailing list needs to be moderated")), ('NEWS_MODERATION', _("A fresh new to be moderated")), ('FILE_MODERATION', _("New files to be moderated")), ('SAS_MODERATION', _("New pictures/album to be moderated in the SAS")), From 62b59f92fdcccb19215c6fccc5b7356f02e17d17 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Tue, 22 Aug 2017 15:51:09 +0200 Subject: [PATCH 16/18] Translations --- locale/fr/LC_MESSAGES/django.po | 297 ++++++++++++++++++++++---------- 1 file changed, 203 insertions(+), 94 deletions(-) diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index a20b12e0..986f5a03 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: 2017-08-21 21:00+0200\n" +"POT-Creation-Date: 2017-08-22 15:42+0200\n" "PO-Revision-Date: 2016-07-18\n" "Last-Translator: Skia \n" "Language-Team: AE info \n" @@ -17,7 +17,7 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: accounting/models.py:61 accounting/models.py:110 accounting/models.py:138 -#: accounting/models.py:197 club/models.py:44 +#: accounting/models.py:197 club/models.py:45 #: core/templates/core/base.jinja:233 counter/models.py:113 #: counter/models.py:139 counter/models.py:183 forum/models.py:49 #: launderette/models.py:38 launderette/models.py:84 launderette/models.py:110 @@ -65,7 +65,7 @@ msgstr "IBAN" msgid "account number" msgstr "numero de compte" -#: accounting/models.py:113 accounting/models.py:139 club/models.py:187 +#: accounting/models.py:113 accounting/models.py:139 club/models.py:188 #: com/models.py:65 com/models.py:156 counter/models.py:148 #: counter/models.py:184 trombi/models.py:149 msgid "club" @@ -88,12 +88,12 @@ msgstr "Compte club" msgid "%(club_account)s on %(bank_account)s" msgstr "%(club_account)s sur %(bank_account)s" -#: accounting/models.py:195 club/models.py:188 counter/models.py:463 +#: accounting/models.py:195 club/models.py:189 counter/models.py:463 #: election/models.py:16 launderette/models.py:148 msgid "start date" msgstr "date de début" -#: accounting/models.py:196 club/models.py:189 counter/models.py:464 +#: accounting/models.py:196 club/models.py:190 counter/models.py:464 #: election/models.py:17 msgid "end date" msgstr "date de fin" @@ -172,8 +172,10 @@ msgstr "étiquette" msgid "target type" msgstr "type de cible" -#: accounting/models.py:271 club/templates/club/club_members.jinja:8 +#: accounting/models.py:271 club/models.py:282 +#: club/templates/club/club_members.jinja:8 #: club/templates/club/club_old_members.jinja:8 +#: club/templates/club/mailing.jinja:22 club/views.py:101 #: counter/templates/counter/cash_summary_list.jinja:32 #: counter/templates/counter/stats.jinja:15 #: counter/templates/counter/stats.jinja:52 @@ -182,7 +184,9 @@ msgstr "type de cible" msgid "User" msgstr "Utilisateur" -#: accounting/models.py:271 club/templates/club/club_detail.jinja:5 +#: accounting/models.py:271 club/models.py:231 +#: club/templates/club/club_detail.jinja:5 +#: com/templates/com/mailing_admin.jinja:11 #: com/templates/com/news_admin_list.jinja:21 #: com/templates/com/news_admin_list.jinja:50 #: com/templates/com/news_admin_list.jinja:81 @@ -339,8 +343,9 @@ msgstr "Compte en banque : " #: accounting/templates/accounting/club_account_details.jinja:59 #: accounting/templates/accounting/label_list.jinja:25 #: club/templates/club/club_sellings.jinja:50 -#: com/templates/com/weekmail.jinja:33 com/templates/com/weekmail.jinja:62 -#: core/templates/core/file_detail.jinja:25 +#: club/templates/club/mailing.jinja:16 club/templates/club/mailing.jinja:33 +#: com/templates/com/mailing_admin.jinja:19 com/templates/com/weekmail.jinja:33 +#: com/templates/com/weekmail.jinja:62 core/templates/core/file_detail.jinja:25 #: core/templates/core/file_detail.jinja:62 #: core/templates/core/file_moderation.jinja:24 #: core/templates/core/group_list.jinja:13 core/templates/core/macros.jinja:53 @@ -366,7 +371,7 @@ msgid "Delete" msgstr "Supprimer" #: accounting/templates/accounting/bank_account_details.jinja:17 -#: club/views.py:51 core/views/user.py:164 sas/templates/sas/picture.jinja:86 +#: club/views.py:113 core/views/user.py:164 sas/templates/sas/picture.jinja:86 msgid "Infos" msgstr "Infos" @@ -385,7 +390,7 @@ msgstr "Nouveau compte club" #: accounting/templates/accounting/bank_account_details.jinja:26 #: accounting/templates/accounting/bank_account_list.jinja:21 #: accounting/templates/accounting/club_account_details.jinja:57 -#: accounting/templates/accounting/journal_details.jinja:83 club/views.py:73 +#: accounting/templates/accounting/journal_details.jinja:83 club/views.py:135 #: com/templates/com/news_admin_list.jinja:37 #: com/templates/com/news_admin_list.jinja:64 #: com/templates/com/news_admin_list.jinja:109 @@ -502,6 +507,7 @@ msgstr "Fermé" #: accounting/templates/accounting/club_account_details.jinja:36 #: accounting/templates/accounting/journal_details.jinja:41 +#: com/templates/com/mailing_admin.jinja:12 #: com/templates/com/news_admin_list.jinja:24 #: com/templates/com/news_admin_list.jinja:52 #: com/templates/com/news_admin_list.jinja:85 @@ -850,11 +856,11 @@ msgstr "Opérations sans étiquette" msgid "Refound this account" msgstr "Rembourser ce compte" -#: club/models.py:46 +#: club/models.py:47 msgid "unix name" msgstr "nom unix" -#: club/models.py:50 +#: club/models.py:51 msgid "" "Enter a valid unix name. This value may contain only letters, numbers ./-/_ " "characters." @@ -862,56 +868,84 @@ msgstr "" "Entrez un nom UNIX valide. Cette valeur peut contenir uniquement des " "lettres, des nombres, et les caractères ./-/_" -#: club/models.py:55 +#: club/models.py:56 msgid "A club with that unix name already exists." msgstr "Un club avec ce nom UNIX existe déjà." -#: club/models.py:58 core/models.py:198 +#: club/models.py:59 core/models.py:198 msgid "address" msgstr "Adresse" -#: club/models.py:64 core/models.py:159 +#: club/models.py:65 core/models.py:159 msgid "home" msgstr "home" -#: club/models.py:76 +#: club/models.py:77 msgid "You can not make loops in clubs" msgstr "Vous ne pouvez pas faire de boucles dans les clubs" -#: club/models.py:90 +#: club/models.py:91 msgid "A club with that unix_name already exists" msgstr "Un club avec ce nom UNIX existe déjà." -#: club/models.py:186 counter/models.py:461 counter/models.py:479 +#: club/models.py:187 counter/models.py:461 counter/models.py:479 #: eboutic/models.py:38 eboutic/models.py:72 election/models.py:140 #: launderette/models.py:114 launderette/models.py:152 sas/models.py:158 #: trombi/models.py:148 msgid "user" msgstr "nom d'utilisateur" -#: club/models.py:190 core/models.py:178 election/models.py:139 +#: club/models.py:191 core/models.py:178 election/models.py:139 #: election/models.py:155 trombi/models.py:150 msgid "role" msgstr "rôle" -#: club/models.py:192 core/models.py:64 counter/models.py:114 +#: club/models.py:193 core/models.py:64 counter/models.py:114 #: counter/models.py:140 election/models.py:13 election/models.py:93 #: election/models.py:141 forum/models.py:50 forum/models.py:186 msgid "description" msgstr "description" -#: club/models.py:197 +#: club/models.py:198 msgid "User must be subscriber to take part to a club" msgstr "L'utilisateur doit être cotisant pour faire partie d'un club" -#: club/models.py:199 +#: club/models.py:200 msgid "User is already member of that club" msgstr "L'utilisateur est déjà membre de ce club" -#: club/models.py:203 +#: club/models.py:204 msgid "past member" msgstr "Anciens membres" +#: club/models.py:232 club/models.py:283 club/views.py:59 +msgid "Email address" +msgstr "Adresse email" + +#: club/models.py:233 com/models.py:67 core/models.py:629 +msgid "is moderated" +msgstr "est modéré" + +#: club/models.py:234 com/models.py:68 +msgid "moderator" +msgstr "modérateur" + +#: club/models.py:281 club/templates/club/mailing.jinja:14 +msgid "Mailing" +msgstr "Mailing" + +#: club/models.py:290 +msgid "At least user or email is required" +msgstr "Au moins un utilisateur ou un email est nécessaire" + +#: club/models.py:295 +msgid "This email is already suscribed in this mailing" +msgstr "Cet email est déjà abonné à cette mailing" + +#: club/models.py:313 club/templates/club/mailing.jinja:30 +msgid "Unregistered user" +msgstr "Désabonner un utilisateur" + #: club/templates/club/club_list.jinja:4 club/templates/club/club_list.jinja:24 msgid "Club list" msgstr "Liste des clubs" @@ -977,8 +1011,8 @@ msgstr "Du" msgid "To" msgstr "Au" -#: club/templates/club/club_sellings.jinja:5 club/views.py:78 club/views.py:251 -#: counter/templates/counter/counter_main.jinja:19 +#: club/templates/club/club_sellings.jinja:5 club/views.py:140 +#: club/views.py:318 counter/templates/counter/counter_main.jinja:19 #: counter/templates/counter/last_ops.jinja:35 msgid "Sellings" msgstr "Ventes" @@ -1004,7 +1038,7 @@ msgstr "unités" msgid "Benefit: " msgstr "Bénéfice : " -#: club/templates/club/club_sellings.jinja:21 club/views.py:199 +#: club/templates/club/club_sellings.jinja:21 club/views.py:266 #: 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:134 @@ -1053,7 +1087,7 @@ msgid "Payment method" msgstr "Méthode de paiement" #: club/templates/club/club_tools.jinja:4 -#: core/templates/core/user_tools.jinja:98 +#: core/templates/core/user_tools.jinja:99 msgid "Club tools" msgstr "Outils club" @@ -1089,48 +1123,95 @@ msgstr "Comptabilité : " msgid "Manage launderettes" msgstr "Gestion des laveries" +#: club/templates/club/mailing.jinja:4 +msgid "Mailing lists" +msgstr "Mailing listes" + +#: club/templates/club/mailing.jinja:10 +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éee " +"n'est pas affichée, attendez jusqu'à qu'un modérateur entre en action" + +#: club/templates/club/mailing.jinja:23 +#: com/templates/com/mailing_admin.jinja:10 +msgid "Email" +msgstr "Email" + +#: club/templates/club/mailing.jinja:41 +msgid "No mailing list existing for this club" +msgstr "Aucune mailing liste n'existe pour ce club" + +#: club/templates/club/mailing.jinja:45 +msgid "New member" +msgstr "Nouveau membre" + +#: club/templates/club/mailing.jinja:49 +msgid "Add to mailing list" +msgstr "Ajouter à la mailing liste" + +#: club/templates/club/mailing.jinja:53 +msgid "New mailing" +msgstr "Nouvelle mailing liste" + +#: club/templates/club/mailing.jinja:57 +msgid "Create mailing list" +msgstr "Créer une mailing liste" + #: club/templates/club/stats.jinja:4 club/templates/club/stats.jinja.py:9 msgid "Club stats" msgstr "Statistiques du club" -#: club/views.py:57 +#: club/views.py:63 +msgid "Enter a valid address. Only the root of the address is needed." +msgstr "" + +#: club/views.py:119 msgid "Members" msgstr "Membres" -#: club/views.py:62 +#: club/views.py:124 msgid "Old members" msgstr "Anciens membres" -#: club/views.py:68 core/templates/core/base.jinja:64 core/views/user.py:180 +#: club/views.py:130 core/templates/core/base.jinja:64 core/views/user.py:180 #: sas/templates/sas/picture.jinja:95 trombi/views.py:55 msgid "Tools" msgstr "Outils" -#: club/views.py:84 counter/templates/counter/counter_list.jinja:21 +#: club/views.py:145 +#, fuzzy +#| msgid "File list" +msgid "Mailing list" +msgstr "Liste des fichiers" + +#: club/views.py:151 counter/templates/counter/counter_list.jinja:21 #: counter/templates/counter/counter_list.jinja:42 #: counter/templates/counter/counter_list.jinja:57 msgid "Props" msgstr "Propriétés" -#: club/views.py:130 core/views/forms.py:253 counter/views.py:91 +#: club/views.py:197 core/views/forms.py:253 counter/views.py:91 #: trombi/views.py:124 msgid "Select user" msgstr "Choisir un utilisateur" -#: club/views.py:180 sas/views.py:104 sas/views.py:157 sas/views.py:232 +#: club/views.py:247 sas/views.py:104 sas/views.py:157 sas/views.py:232 msgid "You do not have the permission to do that" msgstr "Vous n'avez pas la permission de faire cela" -#: club/views.py:197 counter/views.py:1097 +#: club/views.py:264 counter/views.py:1097 msgid "Begin date" msgstr "Date de début" -#: club/views.py:198 com/views.py:130 counter/views.py:1098 +#: club/views.py:265 com/views.py:137 counter/views.py:1098 #: election/views.py:135 subscription/views.py:47 msgid "End date" msgstr "Date de fin" -#: club/views.py:213 core/templates/core/user_stats.jinja:27 +#: club/views.py:280 core/templates/core/user_stats.jinja:27 #: counter/views.py:1188 msgid "Product" msgstr "Produit" @@ -1191,14 +1272,6 @@ msgstr "type" msgid "author" msgstr "auteur" -#: com/models.py:67 core/models.py:629 -msgid "is moderated" -msgstr "est modéré" - -#: com/models.py:68 -msgid "moderator" -msgstr "modérateur" - #: com/models.py:93 msgid "news_date" msgstr "date de la nouvelle" @@ -1239,6 +1312,43 @@ msgstr "weekmail" msgid "rank" msgstr "rang" +#: com/templates/com/mailing_admin.jinja:4 com/views.py:89 +#: core/templates/core/user_tools.jinja:90 +msgid "Mailing lists administration" +msgstr "Administration des mailing listes" + +#: com/templates/com/mailing_admin.jinja:19 +#: com/templates/com/news_admin_list.jinja:65 +#: com/templates/com/news_admin_list.jinja:149 +#: com/templates/com/news_admin_list.jinja:221 +#: com/templates/com/news_admin_list.jinja:293 +#: com/templates/com/news_detail.jinja:26 +#: core/templates/core/file_detail.jinja:65 +#: core/templates/core/file_moderation.jinja:23 +#: sas/templates/sas/moderation.jinja:17 sas/templates/sas/picture.jinja:122 +msgid "Moderate" +msgstr "Modérer" + +#: com/templates/com/mailing_admin.jinja:19 +msgid "Moderated by %(user)s" +msgstr "Modéré par %(user)s" + +#: com/templates/com/mailing_admin.jinja:28 +msgid "This page lists all mailing lists" +msgstr "Cette page liste toutes les mailing listes" + +#: com/templates/com/mailing_admin.jinja:31 +msgid "Not moderated mailing lists" +msgstr "Mailing lists non modérées" + +#: com/templates/com/mailing_admin.jinja:35 +msgid "Moderated mailing lists" +msgstr "Modérer les mailing listes" + +#: com/templates/com/mailing_admin.jinja:39 +msgid "No mailing list existing" +msgstr "Aucune mailing list existante" + #: com/templates/com/news_admin_list.jinja:5 msgid "News admin" msgstr "Administration des nouvelles" @@ -1333,17 +1443,6 @@ msgstr "" msgid "Notices to moderate" msgstr "Nouvelles à modérer" -#: com/templates/com/news_admin_list.jinja:65 -#: com/templates/com/news_admin_list.jinja:149 -#: com/templates/com/news_admin_list.jinja:221 -#: com/templates/com/news_admin_list.jinja:293 -#: com/templates/com/news_detail.jinja:26 -#: core/templates/core/file_detail.jinja:65 -#: core/templates/core/file_moderation.jinja:23 -#: sas/templates/sas/moderation.jinja:17 sas/templates/sas/picture.jinja:122 -msgid "Moderate" -msgstr "Modérer" - #: com/templates/com/news_admin_list.jinja:72 #, fuzzy #| msgid "Weekly" @@ -1471,7 +1570,7 @@ msgid "Coming soon... don't miss!" msgstr "Prochainement... à ne pas rater!" #: com/templates/com/weekmail.jinja:5 com/templates/com/weekmail.jinja.py:9 -#: com/views.py:62 core/templates/core/user_tools.jinja:82 +#: com/views.py:64 core/templates/core/user_tools.jinja:82 msgid "Weekmail" msgstr "Weekmail" @@ -1558,55 +1657,55 @@ msgstr "Astuce" msgid "Final word" msgstr "Le mot de la fin" -#: com/views.py:55 +#: com/views.py:57 msgid "Communication administration" msgstr "Administration de la communication" -#: com/views.py:67 core/templates/core/user_tools.jinja:83 +#: com/views.py:69 core/templates/core/user_tools.jinja:83 msgid "Weekmail destinations" msgstr "Destinataires du Weekmail" -#: com/views.py:72 +#: com/views.py:74 msgid "Index page" msgstr "Page d'accueil" -#: com/views.py:77 +#: com/views.py:79 msgid "Info message" msgstr "Message d'info" -#: com/views.py:82 +#: com/views.py:84 msgid "Alert message" msgstr "Message d'alerte" -#: com/views.py:129 election/views.py:133 subscription/views.py:44 +#: com/views.py:136 election/views.py:133 subscription/views.py:44 msgid "Start date" msgstr "Date de début" -#: com/views.py:131 +#: com/views.py:138 msgid "Until" msgstr "Jusqu'à" -#: com/views.py:132 +#: com/views.py:139 msgid "Automoderation" msgstr "Automodération" -#: com/views.py:138 com/views.py:140 com/views.py:144 +#: com/views.py:145 com/views.py:147 com/views.py:151 msgid "This field is required." msgstr "Ce champ est obligatoire." -#: com/views.py:142 +#: com/views.py:149 msgid "You crazy? You can not finish an event before starting it." msgstr "T'es fou? Un événement ne peut pas finir avant même de commencer." -#: com/views.py:312 +#: com/views.py:319 msgid "Delete and save to regenerate" msgstr "Supprimer et sauver pour regénérer" -#: com/views.py:320 +#: com/views.py:327 msgid "Weekmail of the " msgstr "Weekmail du " -#: com/views.py:400 +#: com/views.py:407 msgid "" "You must be a board member of the selected club to post in the Weekmail." msgstr "" @@ -2642,6 +2741,14 @@ msgstr "Clubs actuels : " msgid "Old club(s) :" msgstr "Anciens clubs :" +#: core/templates/core/user_clubs.jinja:63 +msgid "Subscribed mailing lists" +msgstr "Mailing listes abonnées" + +#: core/templates/core/user_clubs.jinja:65 +msgid "Unsubscribe" +msgstr "Se désabonner" + #: core/templates/core/user_detail.jinja:5 #, python-format msgid "%(user_name)s's profile" @@ -2896,35 +3003,35 @@ msgstr "Éditer le message d'informations" msgid "Moderate files" msgstr "Modérer les fichiers" -#: core/templates/core/user_tools.jinja:92 +#: core/templates/core/user_tools.jinja:93 msgid "Moderate pictures" msgstr "Modérer les photos" -#: core/templates/core/user_tools.jinja:105 +#: core/templates/core/user_tools.jinja:106 msgid "Elections" msgstr "Élections" -#: core/templates/core/user_tools.jinja:107 +#: core/templates/core/user_tools.jinja:108 msgid "See available elections" msgstr "Voir les élections disponibles" -#: core/templates/core/user_tools.jinja:108 +#: core/templates/core/user_tools.jinja:109 msgid "See archived elections" msgstr "Voir les élections archivées" -#: core/templates/core/user_tools.jinja:110 +#: core/templates/core/user_tools.jinja:111 msgid "Create a new election" msgstr "Créer une nouvelle élection" -#: core/templates/core/user_tools.jinja:113 +#: core/templates/core/user_tools.jinja:114 msgid "Other tools" msgstr "Autres outils" -#: core/templates/core/user_tools.jinja:115 +#: core/templates/core/user_tools.jinja:116 msgid "Convert dokuwiki/BBcode syntax to Markdown" msgstr "Convertir de la syntaxe dokuwiki/BBcode vers Markdown" -#: core/templates/core/user_tools.jinja:116 +#: core/templates/core/user_tools.jinja:117 msgid "Trombi tools" msgstr "Outils Trombi" @@ -4088,11 +4195,11 @@ msgstr "Fusionner deux utilisateurs" msgid "Merge" msgstr "Fusion" -#: rootplace/views.py:90 +#: rootplace/views.py:91 msgid "User that will be kept" msgstr "Utilisateur qui sera conservé" -#: rootplace/views.py:91 +#: rootplace/views.py:92 msgid "User that will be deleted" msgstr "Utilisateur qui sera supprimé" @@ -4300,10 +4407,8 @@ msgid "Sbarro/ESTA member" msgstr "Membre de Sbarro ou de l'ESTA, 15 €" #: sith/settings.py:482 -#, fuzzy -#| msgid "One semester" msgid "One semester Welcome Week" -msgstr "Un semestre - Welcome Week" +msgstr "Un semestre - Welcome Week 0 €" #: sith/settings.py:504 msgid "President" @@ -4342,52 +4447,56 @@ msgid "Curious" msgstr "Curieux" #: sith/settings.py:546 +msgid "A new mailing list needs to be moderated" +msgstr "Une nouvelle mailing list a besoin d'être modérée" + +#: sith/settings.py:547 msgid "A fresh new to be moderated" msgstr "Une nouvelle toute neuve à modérer" -#: sith/settings.py:547 +#: sith/settings.py:548 msgid "New files to be moderated" msgstr "Nouveaux fichiers à modérer" -#: sith/settings.py:548 +#: sith/settings.py:549 msgid "New pictures/album to be moderated in the SAS" msgstr "Nouvelles photos/albums à modérer dans le SAS" -#: sith/settings.py:549 +#: sith/settings.py:550 msgid "You've been identified on some pictures" msgstr "Vous avez été identifié sur des photos" -#: sith/settings.py:550 +#: sith/settings.py:551 #, python-format msgid "You just refilled of %s €" msgstr "Vous avez rechargé votre compte de %s €" -#: sith/settings.py:551 +#: sith/settings.py:552 #, python-format msgid "You just bought %s" msgstr "Vous avez acheté %s" -#: sith/settings.py:552 +#: sith/settings.py:553 msgid "You have a notification" msgstr "Vous avez une notification" -#: sith/settings.py:556 +#: sith/settings.py:557 msgid "Success!" msgstr "Succès !" -#: sith/settings.py:557 +#: sith/settings.py:558 msgid "Fail!" msgstr "Échec !" -#: sith/settings.py:558 +#: sith/settings.py:559 msgid "You successfully posted an article in the Weekmail" msgstr "Article posté avec succès dans le Weekmail" -#: sith/settings.py:559 +#: sith/settings.py:560 msgid "You successfully edited an article in the Weekmail" msgstr "Article édité avec succès dans le Weekmail" -#: sith/settings.py:560 +#: sith/settings.py:561 msgid "You successfully sent the Weekmail" msgstr "Weekmail envoyé avec succès" From c83a990165854af975a0527566af68ff104a7659 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Tue, 22 Aug 2017 16:03:24 +0200 Subject: [PATCH 17/18] Wtf migration blocking me --- counter/migrations/0015_merge.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 counter/migrations/0015_merge.py diff --git a/counter/migrations/0015_merge.py b/counter/migrations/0015_merge.py new file mode 100644 index 00000000..23830568 --- /dev/null +++ b/counter/migrations/0015_merge.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('counter', '0014_auto_20170817_1537'), + ('counter', '0014_auto_20170816_1521'), + ] + + operations = [ + ] From 4f6109e27c6b2239e58cfabbd22429ecf0bf3843 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Tue, 22 Aug 2017 22:39:12 +0200 Subject: [PATCH 18/18] Refactor mailings email --- club/migrations/0009_auto_20170822_1529.py | 39 -------- club/migrations/0009_auto_20170822_2232.py | 41 +++++++++ club/models.py | 18 ++-- club/templates/club/mailing.jinja | 2 +- club/views.py | 17 ---- com/templates/com/mailing_admin.jinja | 2 +- core/migrations/0022_auto_20170822_2232.py | 19 ++++ locale/fr/LC_MESSAGES/django.po | 100 +++++++++++---------- migrate.py | 4 +- 9 files changed, 127 insertions(+), 115 deletions(-) delete mode 100644 club/migrations/0009_auto_20170822_1529.py create mode 100644 club/migrations/0009_auto_20170822_2232.py create mode 100644 core/migrations/0022_auto_20170822_2232.py diff --git a/club/migrations/0009_auto_20170822_1529.py b/club/migrations/0009_auto_20170822_1529.py deleted file mode 100644 index 419f3890..00000000 --- a/club/migrations/0009_auto_20170822_1529.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models -from django.conf import settings - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('club', '0008_auto_20170515_2214'), - ] - - operations = [ - migrations.CreateModel( - name='Mailing', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, primary_key=True, auto_created=True)), - ('email', models.EmailField(verbose_name='Email address', max_length=254, unique=True)), - ('is_moderated', models.BooleanField(verbose_name='is moderated', default=False)), - ('club', models.ForeignKey(related_name='mailings', to='club.Club', verbose_name='Club')), - ('moderator', models.ForeignKey(related_name='moderated_mailings', to=settings.AUTH_USER_MODEL, verbose_name='moderator', null=True)), - ], - ), - migrations.CreateModel( - name='MailingSubscription', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, primary_key=True, auto_created=True)), - ('email', models.EmailField(verbose_name='Email address', max_length=254)), - ('mailing', models.ForeignKey(related_name='subscriptions', to='club.Mailing', verbose_name='Mailing')), - ('user', models.ForeignKey(null=True, related_name='mailing_subscriptions', to=settings.AUTH_USER_MODEL, verbose_name='User', blank=True)), - ], - ), - migrations.AlterUniqueTogether( - name='mailingsubscription', - unique_together=set([('user', 'email', 'mailing')]), - ), - ] diff --git a/club/migrations/0009_auto_20170822_2232.py b/club/migrations/0009_auto_20170822_2232.py new file mode 100644 index 00000000..67fc9cf6 --- /dev/null +++ b/club/migrations/0009_auto_20170822_2232.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +from django.conf import settings +import re +import django.core.validators + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('club', '0008_auto_20170515_2214'), + ] + + operations = [ + migrations.CreateModel( + name='Mailing', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)), + ('email', models.CharField(max_length=256, unique=True, validators=[django.core.validators.RegexValidator(re.compile('(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+)*\\Z|^"([\\001-\\010\\013\\014\\016-\\037!#-\\[\\]-\\177]|\\\\[\\001-\\011\\013\\014\\016-\\177])*"\\Z)', 34), 'Enter a valid address. Only the root of the address is needed.')], verbose_name='Email address')), + ('is_moderated', models.BooleanField(default=False, verbose_name='is moderated')), + ('club', models.ForeignKey(verbose_name='Club', related_name='mailings', to='club.Club')), + ('moderator', models.ForeignKey(null=True, verbose_name='moderator', related_name='moderated_mailings', to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='MailingSubscription', + fields=[ + ('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)), + ('email', models.EmailField(max_length=254, verbose_name='Email address')), + ('mailing', models.ForeignKey(verbose_name='Mailing', related_name='subscriptions', to='club.Mailing')), + ('user', models.ForeignKey(null=True, verbose_name='User', related_name='mailing_subscriptions', blank=True, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.AlterUniqueTogether( + name='mailingsubscription', + unique_together=set([('user', 'email', 'mailing')]), + ), + ] diff --git a/club/models.py b/club/models.py index 5bf85d86..94b9ca97 100644 --- a/club/models.py +++ b/club/models.py @@ -31,6 +31,7 @@ from django.core.exceptions import ValidationError, ObjectDoesNotExist from django.db import transaction from django.core.urlresolvers import reverse from django.utils import timezone +from django.core.validators import RegexValidator, validate_email from core.models import User, MetaGroup, Group, SithFile, RealGroup, Notification @@ -229,7 +230,11 @@ class Mailing(models.Model): Remember that mailing lists should be validated by UTBM """ club = models.ForeignKey(Club, verbose_name=_('Club'), related_name="mailings", null=False, blank=False) - email = models.EmailField(_('Email address'), unique=True) + 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) @@ -240,6 +245,10 @@ class Mailing(models.Model): self.moderator = None super(Mailing, self).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_in_group(settings.SITH_GROUP_COM_ADMIN_ID) @@ -254,11 +263,8 @@ class Mailing(models.Model): sub.delete() super(Mailing, self).delete() - def base_mail(self): - return self.email.split('@')[0] - def fetch_format(self): - resp = self.base_mail() + ': ' + resp = self.email + ': ' for sub in self.subscriptions.all(): resp += sub.fetch_format() return resp @@ -271,7 +277,7 @@ class Mailing(models.Model): super(Mailing, self).save() def __str__(self): - return "%s - %s" % (self.club, self.email) + return "%s - %s" % (self.club, self.email_full) class MailingSubscription(models.Model): diff --git a/club/templates/club/mailing.jinja b/club/templates/club/mailing.jinja index 797abb12..5ee67422 100644 --- a/club/templates/club/mailing.jinja +++ b/club/templates/club/mailing.jinja @@ -11,7 +11,7 @@ {% for mailing in object_list %} {% if mailing.is_moderated %} -

    {% trans %}Mailing{% endtrans %} {{ mailing.email }} +

    {% trans %}Mailing{% endtrans %} {{ mailing.email_full }} {%- if user.is_owner(mailing) -%} - {% trans %}Delete{% endtrans %} {%- endif -%} diff --git a/club/views.py b/club/views.py index 77a1979d..d2a32b01 100644 --- a/club/views.py +++ b/club/views.py @@ -36,7 +36,6 @@ from django.utils.translation import ugettext as _t from ajax_select.fields import AutoCompleteSelectField from django.core.exceptions import PermissionDenied from django.shortcuts import get_object_or_404 -from django.core.validators import RegexValidator, validate_email from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin from core.views.forms import SelectDate, SelectDateTime @@ -55,16 +54,6 @@ class MailingForm(forms.ModelForm): model = Mailing fields = ('email', 'club', 'moderator') - email = forms.CharField( - label=_('Email address'), - validators=[ - RegexValidator( - validate_email.user_regex, - _('Enter a valid address. Only the root of the address is needed.') - ) - ], - required=True) - def __init__(self, *args, **kwargs): club_id = kwargs.pop('club_id', None) user_id = kwargs.pop('user_id', -1) # Remember 0 is treated as None @@ -78,12 +67,6 @@ class MailingForm(forms.ModelForm): self.fields['moderator'].initial = user_id self.fields['moderator'].widget = forms.HiddenInput() - def clean(self): - cleaned_data = super(MailingForm, self).clean() - if self.is_valid(): - cleaned_data['email'] += '@' + settings.SITH_MAILING_DOMAIN - return cleaned_data - class MailingSubscriptionForm(forms.ModelForm): class Meta: diff --git a/com/templates/com/mailing_admin.jinja b/com/templates/com/mailing_admin.jinja index 15784fc1..75d098bc 100644 --- a/com/templates/com/mailing_admin.jinja +++ b/com/templates/com/mailing_admin.jinja @@ -13,7 +13,7 @@ {% for mailing in list %} - {{ mailing.email }} + {{ mailing.email_full }} {{ mailing.club }} {% trans %}Delete{% endtrans %} - {% if not mailing.is_moderated %}{% trans %}Moderate{% endtrans %}{% else %}{% trans user=mailing.moderator %}Moderated by {{ user }}{% endtrans %}{% endif %} diff --git a/core/migrations/0022_auto_20170822_2232.py b/core/migrations/0022_auto_20170822_2232.py new file mode 100644 index 00000000..111ea439 --- /dev/null +++ b/core/migrations/0022_auto_20170822_2232.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0021_auto_20170822_1529'), + ] + + operations = [ + migrations.AlterField( + model_name='notification', + name='type', + field=models.CharField(choices=[('MAILING_MODERATION', 'A new mailing list needs to be moderated'), ('NEWS_MODERATION', 'A fresh new to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'New pictures/album to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')], default='GENERIC', max_length=32, verbose_name='type'), + ), + ] diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 986f5a03..6ccb516e 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: 2017-08-22 15:42+0200\n" +"POT-Creation-Date: 2017-08-22 22:36+0200\n" "PO-Revision-Date: 2016-07-18\n" "Last-Translator: Skia \n" "Language-Team: AE info \n" @@ -17,7 +17,7 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: accounting/models.py:61 accounting/models.py:110 accounting/models.py:138 -#: accounting/models.py:197 club/models.py:45 +#: accounting/models.py:197 club/models.py:46 #: core/templates/core/base.jinja:233 counter/models.py:113 #: counter/models.py:139 counter/models.py:183 forum/models.py:49 #: launderette/models.py:38 launderette/models.py:84 launderette/models.py:110 @@ -65,7 +65,7 @@ msgstr "IBAN" msgid "account number" msgstr "numero de compte" -#: accounting/models.py:113 accounting/models.py:139 club/models.py:188 +#: accounting/models.py:113 accounting/models.py:139 club/models.py:189 #: com/models.py:65 com/models.py:156 counter/models.py:148 #: counter/models.py:184 trombi/models.py:149 msgid "club" @@ -88,12 +88,12 @@ msgstr "Compte club" msgid "%(club_account)s on %(bank_account)s" msgstr "%(club_account)s sur %(bank_account)s" -#: accounting/models.py:195 club/models.py:189 counter/models.py:463 +#: accounting/models.py:195 club/models.py:190 counter/models.py:463 #: election/models.py:16 launderette/models.py:148 msgid "start date" msgstr "date de début" -#: accounting/models.py:196 club/models.py:190 counter/models.py:464 +#: accounting/models.py:196 club/models.py:191 counter/models.py:464 #: election/models.py:17 msgid "end date" msgstr "date de fin" @@ -172,10 +172,10 @@ msgstr "étiquette" msgid "target type" msgstr "type de cible" -#: accounting/models.py:271 club/models.py:282 +#: accounting/models.py:271 club/models.py:288 #: club/templates/club/club_members.jinja:8 #: club/templates/club/club_old_members.jinja:8 -#: club/templates/club/mailing.jinja:22 club/views.py:101 +#: club/templates/club/mailing.jinja:22 club/views.py:84 #: counter/templates/counter/cash_summary_list.jinja:32 #: counter/templates/counter/stats.jinja:15 #: counter/templates/counter/stats.jinja:52 @@ -184,7 +184,7 @@ msgstr "type de cible" msgid "User" msgstr "Utilisateur" -#: accounting/models.py:271 club/models.py:231 +#: accounting/models.py:271 club/models.py:232 #: club/templates/club/club_detail.jinja:5 #: com/templates/com/mailing_admin.jinja:11 #: com/templates/com/news_admin_list.jinja:21 @@ -371,7 +371,7 @@ msgid "Delete" msgstr "Supprimer" #: accounting/templates/accounting/bank_account_details.jinja:17 -#: club/views.py:113 core/views/user.py:164 sas/templates/sas/picture.jinja:86 +#: club/views.py:96 core/views/user.py:164 sas/templates/sas/picture.jinja:86 msgid "Infos" msgstr "Infos" @@ -390,7 +390,7 @@ msgstr "Nouveau compte club" #: accounting/templates/accounting/bank_account_details.jinja:26 #: accounting/templates/accounting/bank_account_list.jinja:21 #: accounting/templates/accounting/club_account_details.jinja:57 -#: accounting/templates/accounting/journal_details.jinja:83 club/views.py:135 +#: accounting/templates/accounting/journal_details.jinja:83 club/views.py:118 #: com/templates/com/news_admin_list.jinja:37 #: com/templates/com/news_admin_list.jinja:64 #: com/templates/com/news_admin_list.jinja:109 @@ -856,11 +856,11 @@ msgstr "Opérations sans étiquette" msgid "Refound this account" msgstr "Rembourser ce compte" -#: club/models.py:47 +#: club/models.py:48 msgid "unix name" msgstr "nom unix" -#: club/models.py:51 +#: club/models.py:52 msgid "" "Enter a valid unix name. This value may contain only letters, numbers ./-/_ " "characters." @@ -868,81 +868,85 @@ msgstr "" "Entrez un nom UNIX valide. Cette valeur peut contenir uniquement des " "lettres, des nombres, et les caractères ./-/_" -#: club/models.py:56 +#: club/models.py:57 msgid "A club with that unix name already exists." msgstr "Un club avec ce nom UNIX existe déjà." -#: club/models.py:59 core/models.py:198 +#: club/models.py:60 core/models.py:198 msgid "address" msgstr "Adresse" -#: club/models.py:65 core/models.py:159 +#: club/models.py:66 core/models.py:159 msgid "home" msgstr "home" -#: club/models.py:77 +#: club/models.py:78 msgid "You can not make loops in clubs" msgstr "Vous ne pouvez pas faire de boucles dans les clubs" -#: club/models.py:91 +#: club/models.py:92 msgid "A club with that unix_name already exists" msgstr "Un club avec ce nom UNIX existe déjà." -#: club/models.py:187 counter/models.py:461 counter/models.py:479 +#: club/models.py:188 counter/models.py:461 counter/models.py:479 #: eboutic/models.py:38 eboutic/models.py:72 election/models.py:140 #: launderette/models.py:114 launderette/models.py:152 sas/models.py:158 #: trombi/models.py:148 msgid "user" msgstr "nom d'utilisateur" -#: club/models.py:191 core/models.py:178 election/models.py:139 +#: club/models.py:192 core/models.py:178 election/models.py:139 #: election/models.py:155 trombi/models.py:150 msgid "role" msgstr "rôle" -#: club/models.py:193 core/models.py:64 counter/models.py:114 +#: club/models.py:194 core/models.py:64 counter/models.py:114 #: counter/models.py:140 election/models.py:13 election/models.py:93 #: election/models.py:141 forum/models.py:50 forum/models.py:186 msgid "description" msgstr "description" -#: club/models.py:198 +#: club/models.py:199 msgid "User must be subscriber to take part to a club" msgstr "L'utilisateur doit être cotisant pour faire partie d'un club" -#: club/models.py:200 +#: club/models.py:201 msgid "User is already member of that club" msgstr "L'utilisateur est déjà membre de ce club" -#: club/models.py:204 +#: club/models.py:205 msgid "past member" msgstr "Anciens membres" -#: club/models.py:232 club/models.py:283 club/views.py:59 +#: club/models.py:233 club/models.py:289 msgid "Email address" msgstr "Adresse email" -#: club/models.py:233 com/models.py:67 core/models.py:629 +#: club/models.py:236 +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:238 com/models.py:67 core/models.py:629 msgid "is moderated" msgstr "est modéré" -#: club/models.py:234 com/models.py:68 +#: club/models.py:239 com/models.py:68 msgid "moderator" msgstr "modérateur" -#: club/models.py:281 club/templates/club/mailing.jinja:14 +#: club/models.py:287 club/templates/club/mailing.jinja:14 msgid "Mailing" msgstr "Mailing" -#: club/models.py:290 +#: club/models.py:296 msgid "At least user or email is required" msgstr "Au moins un utilisateur ou un email est nécessaire" -#: club/models.py:295 +#: club/models.py:301 msgid "This email is already suscribed in this mailing" msgstr "Cet email est déjà abonné à cette mailing" -#: club/models.py:313 club/templates/club/mailing.jinja:30 +#: club/models.py:319 club/templates/club/mailing.jinja:30 msgid "Unregistered user" msgstr "Désabonner un utilisateur" @@ -1011,8 +1015,8 @@ msgstr "Du" msgid "To" msgstr "Au" -#: club/templates/club/club_sellings.jinja:5 club/views.py:140 -#: club/views.py:318 counter/templates/counter/counter_main.jinja:19 +#: club/templates/club/club_sellings.jinja:5 club/views.py:123 +#: club/views.py:301 counter/templates/counter/counter_main.jinja:19 #: counter/templates/counter/last_ops.jinja:35 msgid "Sellings" msgstr "Ventes" @@ -1038,7 +1042,7 @@ msgstr "unités" msgid "Benefit: " msgstr "Bénéfice : " -#: club/templates/club/club_sellings.jinja:21 club/views.py:266 +#: club/templates/club/club_sellings.jinja:21 club/views.py:249 #: 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:134 @@ -1132,8 +1136,9 @@ 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éee " -"n'est pas affichée, attendez jusqu'à qu'un modérateur entre en action" +"Rappelez vous : les mailing listes doivent être modérées, si votre liste " +"nouvellement créee n'est pas affichée, attendez jusqu'à qu'un modérateur " +"entre en action" #: club/templates/club/mailing.jinja:23 #: com/templates/com/mailing_admin.jinja:10 @@ -1164,54 +1169,50 @@ msgstr "Créer une mailing liste" msgid "Club stats" msgstr "Statistiques du club" -#: club/views.py:63 -msgid "Enter a valid address. Only the root of the address is needed." -msgstr "" - -#: club/views.py:119 +#: club/views.py:102 msgid "Members" msgstr "Membres" -#: club/views.py:124 +#: club/views.py:107 msgid "Old members" msgstr "Anciens membres" -#: club/views.py:130 core/templates/core/base.jinja:64 core/views/user.py:180 +#: club/views.py:113 core/templates/core/base.jinja:64 core/views/user.py:180 #: sas/templates/sas/picture.jinja:95 trombi/views.py:55 msgid "Tools" msgstr "Outils" -#: club/views.py:145 +#: club/views.py:128 #, fuzzy #| msgid "File list" msgid "Mailing list" msgstr "Liste des fichiers" -#: club/views.py:151 counter/templates/counter/counter_list.jinja:21 +#: club/views.py:134 counter/templates/counter/counter_list.jinja:21 #: counter/templates/counter/counter_list.jinja:42 #: counter/templates/counter/counter_list.jinja:57 msgid "Props" msgstr "Propriétés" -#: club/views.py:197 core/views/forms.py:253 counter/views.py:91 +#: club/views.py:180 core/views/forms.py:253 counter/views.py:91 #: trombi/views.py:124 msgid "Select user" msgstr "Choisir un utilisateur" -#: club/views.py:247 sas/views.py:104 sas/views.py:157 sas/views.py:232 +#: club/views.py:230 sas/views.py:104 sas/views.py:157 sas/views.py:232 msgid "You do not have the permission to do that" msgstr "Vous n'avez pas la permission de faire cela" -#: club/views.py:264 counter/views.py:1097 +#: club/views.py:247 counter/views.py:1097 msgid "Begin date" msgstr "Date de début" -#: club/views.py:265 com/views.py:137 counter/views.py:1098 +#: club/views.py:248 com/views.py:137 counter/views.py:1098 #: election/views.py:135 subscription/views.py:47 msgid "End date" msgstr "Date de fin" -#: club/views.py:280 core/templates/core/user_stats.jinja:27 +#: club/views.py:263 core/templates/core/user_stats.jinja:27 #: counter/views.py:1188 msgid "Product" msgstr "Produit" @@ -1330,6 +1331,7 @@ msgid "Moderate" msgstr "Modérer" #: com/templates/com/mailing_admin.jinja:19 +#, python-format msgid "Moderated by %(user)s" msgstr "Modéré par %(user)s" diff --git a/migrate.py b/migrate.py index 5858af46..ce1ad397 100644 --- a/migrate.py +++ b/migrate.py @@ -1340,7 +1340,7 @@ def migrate_mailings(): Mailing.objects.all().delete() - print("Migrating old database") + print("Migrating old mailing database") cur.execute(""" SELECT * FROM mailing @@ -1355,7 +1355,7 @@ def migrate_mailings(): club = club.first() if mailing['nom']: mailing['nom'] = '.' + mailing['nom'] - Mailing(id=mailing['id_mailing'], club=club, email=to_unicode(club.unix_name + mailing['nom'] + '@utbm.fr'), + Mailing(id=mailing['id_mailing'], club=club, email=to_unicode(club.unix_name + mailing['nom']), moderator=moderator, is_moderated=(mailing['is_valid'] > 0)).save() print("-------------------")