Commit 2b59d862 authored by SimonBoulier's avatar SimonBoulier

Use an intermediate model to manage mailling list subscriptions.

parent 64b0e37f
......@@ -8,7 +8,18 @@ from django.contrib import admin
from django.contrib import messages
from django.http import HttpResponseRedirect
from .models import MaillingList, SyncCommandError
from .models import MaillingList, MaillingListSubscription, SyncCommandError
import coin.members.admin
class MaillingListSubscriptionInline(admin.TabularInline):
model = MaillingListSubscription
extra = 0
form = autocomplete_light.modelform_factory(
MaillingListSubscription,
fields='__all__',
)
class MaillingListAdmin(admin.ModelAdmin):
......@@ -32,29 +43,42 @@ class MaillingListAdmin(admin.ModelAdmin):
sync_to_server.short_description = (
'Synchroniser les listes sélectionnées vers le serveur')
form = autocomplete_light.modelform_factory(
MaillingList,
fields='__all__',
)
inlines = [MaillingListSubscriptionInline,]
def change_view(self, request, object_id, form_url='', extra_context=None):
def change_view(self, request, object_id, *args, **kwargs):
try:
return super(MaillingListAdmin, self).change_view(
request, object_id, form_url, extra_context)
request, object_id, *args, **kwargs)
except SyncCommandError as e:
try:
ml = MaillingList.objects.get(pk=object_id)
ml_name = "La liste mail « {} »".format(ml.short_name)
except MaillingList.DoesNotExist:
ml_name = "La nouvelle liste mail"
messages.error(
request,
"{} n'a pas pu être synchronisée".format(ml_name) +
" vers le serveur de listes : « {} ». Vous pouvez".format(e) +
" relancer la synchro depuis la liste des listes mail.")
" vers le serveur de listes : « {} ».".format(e))
return HttpResponseRedirect(request.path)
admin.site.register(MaillingList, MaillingListAdmin)
class MemberAdmin(coin.members.admin.MemberAdmin):
inlines = coin.members.admin.MemberAdmin.inlines + [MaillingListSubscriptionInline]
def change_view(self, request, *args, **kwargs):
try:
return super(MemberAdmin, self).change_view(
request, *args, **kwargs)
except SyncCommandError as e:
messages.error(
request,
"Les listes mails n'ont pas pu être synchronisées" +
" vers le serveur de listes : « {} ».".format(e))
return HttpResponseRedirect(request.path)
admin.site.unregister(coin.members.admin.Member)
admin.site.register(coin.members.admin.Member, MemberAdmin)
......@@ -16,15 +16,31 @@ class Migration(migrations.Migration):
name='MaillingList',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('short_name', models.CharField(help_text=b'c\'est l\'identifiant qui servira \xc3\xa0 communiquer avec le syst\xc3\xa8me de mailling-list(typiquement, la partie avant le "@" dans l\'adress )', max_length=50, verbose_name=b'identifiant technique')),
('email', models.EmailField(max_length=254, verbose_name=b"adresse mail d'envoi")),
('verbose_name', models.CharField(help_text=b"Nom affich\xc3\xa9 dans l'interface membre", max_length=130, verbose_name=b'nom complet')),
('short_name', models.CharField(help_text='c\'est l\'identifiant qui servira \xe0 communiquer avec le syst\xe8me de mailling-list(typiquement, la partie avant le "@" dans l\'adress )', max_length=50, verbose_name='identifiant technique')),
('email', models.EmailField(max_length=254, verbose_name="adresse mail d'envoi")),
('verbose_name', models.CharField(help_text="Nom affich\xe9 dans l'interface membre", max_length=130, verbose_name='nom complet')),
('description', models.TextField()),
('subscribers', models.ManyToManyField(related_name='subscribed_maillinglists', verbose_name=b'abonn\xc3\xa9\xc2\xb7e\xc2\xb7s', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'liste mail',
'verbose_name_plural': 'listes mail',
},
),
migrations.CreateModel(
name='MaillingListSubscription',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('maillinglist', models.ForeignKey(to='maillists.MaillingList')),
('member', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'abonnement \xe0 une liste mail',
'verbose_name_plural': 'abonnements \xe0 des listes mail',
},
),
migrations.AddField(
model_name='maillinglist',
name='subscribers',
field=models.ManyToManyField(related_name='subscribed_maillinglists', verbose_name='abonn\xe9\xb7e\xb7s', to=settings.AUTH_USER_MODEL, through='maillists.MaillingListSubscription', blank=True),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
('maillists', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='maillinglist',
name='short_name',
field=models.CharField(help_text='c\'est l\'identifiant qui servira \xe0 communiquer avec le syst\xe8me de mailling-list(typiquement, la partie avant le "@" dans l\'adress )', max_length=50, verbose_name='identifiant technique'),
),
migrations.AlterField(
model_name='maillinglist',
name='subscribers',
field=models.ManyToManyField(related_name='subscribed_maillinglists', verbose_name='abonn\xe9\xb7e\xb7s', to=settings.AUTH_USER_MODEL, blank=True),
),
migrations.AlterField(
model_name='maillinglist',
name='verbose_name',
field=models.CharField(help_text="Nom affich\xe9 dans l'interface membre", max_length=130, verbose_name='nom complet'),
),
]
......@@ -6,7 +6,7 @@ import subprocess
from django.conf import settings
from django.db import models
from django.db.models.signals import pre_save, post_save, m2m_changed
from django.db.models.signals import pre_save, post_save, post_delete
from django.dispatch import receiver
from coin.members.models import Member
......@@ -15,6 +15,16 @@ from coin.members.models import Member
class SyncCommandError(SystemError):
pass
class MaillingListSubscription(models.Model):
member = models.ForeignKey(Member, verbose_name='membre')
maillinglist = models.ForeignKey('MaillingList', verbose_name='liste mail')
class Meta:
verbose_name = 'abonnement à une liste mail'
verbose_name_plural = 'abonnements à des listes mail'
unique_together = ('member', 'maillinglist')
class MaillingList(models.Model):
short_name = models.CharField(
'identifiant technique', max_length=50,
......@@ -32,6 +42,7 @@ class MaillingList(models.Model):
description = models.TextField()
subscribers = models.ManyToManyField(
Member, related_name='subscribed_maillinglists',
through=MaillingListSubscription,
verbose_name='abonné·e·s', blank=True)
class Meta:
......@@ -71,30 +82,17 @@ class MaillingList(models.Model):
out_stderr.decode('utf-8')))
@receiver(m2m_changed, sender=MaillingList.subscribers.through)
def push_updated_list(sender, instance, action, reverse, model, pk_set, **kwargs):
if action in ('post_add', 'post_remove'):
if reverse:
impacted_mls = MaillingList.objects.filter(pk__in=pk_set)
else:
impacted_mls = [instance]
elif action == 'post_clear' and not reverse:
impacted_mls = [instance]
# cannot be handled at post_clear (we would have lost the information on
# what has been removed)
elif action == 'pre_clear' and reverse:
impacted_mls = instance.subscribed_maillinglists.all()
@receiver(post_save, sender=MaillingListSubscription)
def push_new_subscription(sender, instance, created, raw, *args, **kwargs):
if raw:
print("The synchronization of mailling list with Coin was not performed, please launch it by hand in the admin interface.")
else:
return
instance.maillinglist.sync_to_list_server()
@receiver(post_delete, sender=MaillingListSubscription)
def push_remove_subscription(sender, instance, *args, **kwargs):
instance.maillinglist.sync_to_list_server()
for ml in impacted_mls:
if action == 'pre_clear':
# We have to force it because it has not yet been reflected in DB.
ml.sync_to_list_server(force_clear=True)
else:
ml.sync_to_list_server()
@receiver(pre_save, sender=Member)
......
......@@ -7,7 +7,7 @@ from django import forms
from django.forms import formset_factory
from django.shortcuts import render, redirect
from .models import MaillingList, SyncCommandError
from .models import MaillingList, MaillingListSubscription, SyncCommandError
from coin.members.models import Member
......@@ -51,11 +51,12 @@ def lists_list(request):
)
old_subscriptions = set(request.user.subscribed_maillinglists.all())
try:
# add
for mail_list in new_subscriptions - old_subscriptions:
request.user.subscribed_maillinglists.add(mail_list)
for mail_list in old_subscriptions - new_subscriptions:
request.user.subscribed_maillinglists.remove(mail_list)
MaillingListSubscription.objects.create(member=request.user, maillinglist=mail_list)
# remove
to_remove = old_subscriptions - new_subscriptions
MaillingListSubscription.objects.filter(member=request.user, maillinglist__in=to_remove).delete()
except SyncCommandError as e:
messages.error(
request,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment