models.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. import subprocess
  4. from django.conf import settings
  5. from django.db import models
  6. from django.db.models.signals import pre_save, post_save, post_delete
  7. from django.dispatch import receiver
  8. from coin.members.models import Member
  9. class SyncCommandError(SystemError):
  10. pass
  11. class MaillingListSubscription(models.Model):
  12. member = models.ForeignKey(Member, verbose_name='membre')
  13. maillinglist = models.ForeignKey('MaillingList', verbose_name='liste mail')
  14. class Meta:
  15. verbose_name = 'abonnement à une liste mail'
  16. verbose_name_plural = 'abonnements aux listes mail'
  17. unique_together = ('member', 'maillinglist')
  18. def __str__(self):
  19. return str(self.maillinglist)
  20. class MaillingList(models.Model):
  21. short_name = models.CharField(
  22. 'identifiant technique', max_length=50, unique=True,
  23. help_text=(
  24. "c'est l'identifiant qui servira à "
  25. "communiquer avec le serveur de liste mail "
  26. "(typiquement, la partie avant le \"@\" dans l'adress )"
  27. )
  28. )
  29. email = models.EmailField("adresse mail d'envoi", unique=True)
  30. verbose_name = models.CharField(
  31. 'nom complet', max_length=130,
  32. help_text="Nom affiché dans l'interface membre"
  33. )
  34. description = models.TextField()
  35. subscribers = models.ManyToManyField(
  36. Member, related_name='subscribed_maillinglists',
  37. through=MaillingListSubscription,
  38. verbose_name='abonné·e·s', blank=True)
  39. class Meta:
  40. verbose_name = 'liste mail'
  41. verbose_name_plural = 'listes mail'
  42. def __unicode__(self):
  43. return '{} ({})'.format(self.verbose_name, self.email)
  44. def as_text_listing(self):
  45. """ One subscriber email per line
  46. """
  47. return '\n'.join(
  48. self.subscribers.values_list('email', flat=True))
  49. def sync_to_list_server(self, force_clear=False):
  50. if not settings.MAILLIST_SYNC_COMMAND:
  51. raise ValueError('You should define MAILLIST_SYNC_COMMAND'
  52. ' setting to use maillist module')
  53. else:
  54. cmd = settings.MAILLIST_SYNC_COMMAND.format(
  55. email=self.email,
  56. short_name=self.short_name,
  57. )
  58. p = subprocess.Popen(
  59. cmd, shell=True,
  60. stdin=subprocess.PIPE, stderr=subprocess.PIPE)
  61. if force_clear:
  62. text_listing = ''
  63. else:
  64. text_listing = self.as_text_listing()
  65. out_stdout, out_stderr = p.communicate(text_listing)
  66. if p.returncode != 0:
  67. raise SyncCommandError(
  68. "Erreur à l'appel de la commande : \"{}\"".format(
  69. out_stderr.decode('utf-8')))
  70. @receiver(post_save, sender=MaillingListSubscription)
  71. def push_new_subscription(sender, instance, created, raw, *args, **kwargs):
  72. if raw:
  73. print("The synchronization of mailling list with Coin was not performed, please launch it by hand in the admin interface.")
  74. else:
  75. instance.maillinglist.sync_to_list_server()
  76. @receiver(post_delete, sender=MaillingListSubscription)
  77. def push_remove_subscription(sender, instance, *args, **kwargs):
  78. instance.maillinglist.sync_to_list_server()
  79. @receiver(pre_save, sender=Member)
  80. def store_previous_email(sender, instance, *args, **kwargs):
  81. """Record the email address for post_save handler
  82. update_an_email_address needs the old email address for comparison, but
  83. this information is not available at post_save stage.
  84. """
  85. member = instance
  86. # if not, this is a user creation, nothing to do
  87. if member.pk:
  88. old_member = Member.objects.get(pk=member.pk)
  89. member._previous_email = old_member.email
  90. @receiver(post_save, sender=Member)
  91. def update_an_email_address(sender, instance, *args, **kwargs):
  92. """Check if the member email has changed and sync mail lists if so.
  93. We do that at post_save stage because we need the new information to be
  94. recorded in database, otherwise, sync_list_to_server() would use the old
  95. email.
  96. """
  97. member = instance
  98. old_email = getattr(member, '_previous_email', None)
  99. if old_email and (old_email != member.email):
  100. for maillist in member.subscribed_maillinglists.all():
  101. maillist.sync_to_list_server()
  102. # Error handling ???
  103. # try:
  104. # except SyncCommandError as e:
  105. # print("error", e)
  106. # we cannot send a message because we don't have the request