models.py 6.45 KB
Newer Older
1
from django.core import validators
2
from django.core.exceptions import ValidationError
3
from django.db import models
4
from django.utils import timezone
5
from django.utils.translation import ugettext_lazy as _
6

7
from activemembers.models import MemberGroup, Board
8
from members.models import Member
9
10
11
12
from utils.snippets import datetime_to_lectureyear


def get_automatic_mailinglists():
Joren Vrancken's avatar
Joren Vrancken committed
13
    """Return mailing list names that should be generated automatically."""
14
15
16
    lectureyear = datetime_to_lectureyear(timezone.now())
    list_names = ['leden', 'members', 'begunstigers', 'benefactors',
                  'ereleden', 'honorary', 'mentors', 'activemembers',
17
18
                  'commissievoorzitters', 'committeechairs',
                  'optin', 'oldboards', 'oudbesturen']
19
20
21
22
23
24
25
26
    if Board.objects.exists():
        for year in range(Board.objects.earliest('since').since.year,
                          lectureyear):
            board = Board.objects.get(since__year=year)
            if board is not None:
                years = str(board.since.year)[-2:] + str(board.until.year)[-2:]
                list_names += [f'bestuur{years}', f'board{years}']
    return list_names
27
28
29


class MailingList(models.Model):
Joren Vrancken's avatar
Joren Vrancken committed
30
31
    """Model describing mailing lists."""

32
33
34
35
36
37
38
    name = models.CharField(
        verbose_name=_("Name"),
        max_length=100,
        validators=[validators.RegexValidator(
            regex=r'^[a-zA-Z0-9]+$',
            message=_('Enter a simpler name'))
        ],
39
        unique=True,
40
        help_text=_('Enter the name for the list (i.e. name@thalia.nu).'),
41
42
43
44
    )

    prefix = models.CharField(
        verbose_name=_("Prefix"),
45
        blank=True,
46
47
48
        max_length=200,
        help_text=_('Enter a prefix that should be prefixed to subjects '
                    'of all emails sent via this mailinglist.'),
49
50
51
52
    )

    archived = models.BooleanField(
        verbose_name=_("Archived"),
53
54
        default=True,
        help_text=_('Indicate whether an archive should be kept.')
55
56
57
58
    )

    moderated = models.BooleanField(
        verbose_name=_("Moderated"),
59
60
        default=False,
        help_text=_('Indicate whether emails to the list require approval.')
61
62
    )

63
    members = models.ManyToManyField(
64
        Member,
65
66
67
68
69
        verbose_name=_("Members"),
        blank=True,
        help_text=_('Select individual members to include in the list.'),
    )

70
    member_groups = models.ManyToManyField(
71
        MemberGroup,
72
73
        verbose_name=_("Member groups"),
        help_text=_('Select entire groups to include in the list.'),
74
75
        blank=True,
    )
76

77
78
79
80
81
82
83
84
85
86
87
88
    autoresponse_enabled = models.BooleanField(
        verbose_name=_("Automatic response enabled"),
        default=False,
        help_text=_('Indicate whether emails will get an automatic response.')
    )

    autoresponse_text = models.TextField(
        verbose_name=_("Autoresponse text"),
        null=True,
        blank=True,
    )

89
    def all_addresses(self):
Joren Vrancken's avatar
Joren Vrancken committed
90
        """Return all addresses subscribed to this mailing list."""
91
        for member in self.members.all():
92
            yield member.email
93

94
95
        for group in self.member_groups.all().prefetch_related("members"):
            for member in group.members.exclude(
96
                    membergroupmembership__until__lt=timezone.now().date()):
97
                yield member.email
98

99
100
        for verbatimaddress in self.addresses.all():
            yield verbatimaddress.address
101

102
    def clean(self):
Joren Vrancken's avatar
Joren Vrancken committed
103
        """Validate the mailing list."""
104
105
        super().clean()
        if (ListAlias.objects
106
107
                .filter(alias=self.name).count() > 0 or
                self.name in get_automatic_mailinglists()):
108
109
110
111
112
113
114
115
            raise ValidationError({
                'name': _("%(model_name)s with this "
                          "%(field_label)s already exists.") % {
                             'model_name': _("Mailing list"),
                             'field_label': _("List alias")
                         }
            })

116
117
118
119
120
        if not self.autoresponse_text and self.autoresponse_enabled:
            raise ValidationError({
                'autoresponse_text': _('Enter a text for the auto response.')
            })

121
    def __str__(self):
Joren Vrancken's avatar
Joren Vrancken committed
122
        """Return the name of the mailing list."""
123
124
125
126
        return self.name


class VerbatimAddress(models.Model):
Joren Vrancken's avatar
Joren Vrancken committed
127
128
    """Model that describes an email address subscribed to a mailing list."""

129
130
131
132
133
    address = models.EmailField(
        verbose_name=_("Email address"),
        help_text=_('Enter an explicit email address to include in the list.'),
    )

134
    mailinglist = models.ForeignKey(MailingList,
135
                                    verbose_name=_("Mailing list"),
136
137
                                    on_delete=models.CASCADE,
                                    related_name='addresses')
138

139
    def __str__(self):
Joren Vrancken's avatar
Joren Vrancken committed
140
        """Return the address."""
141
142
        return self.address

143
    class Meta:
Joren Vrancken's avatar
Joren Vrancken committed
144
145
        """Meta class for VerbatimAddress."""

146
147
148
        verbose_name = _("Verbatim address")
        verbose_name_plural = _("Verbatim addresses")

149
150

class ListAlias(models.Model):
Joren Vrancken's avatar
Joren Vrancken committed
151
152
    """Model describing an alias of a mailing list."""

153
    alias = models.CharField(
154
        verbose_name=_("Alternative name"),
155
156
157
158
159
        max_length=100,
        validators=[validators.RegexValidator(
            regex=r'^[a-zA-Z0-9]+$',
            message=_('Enter a simpler name'))
        ],
160
        unique=True,
161
        help_text=_('Enter an alternative name for the list.'),
162
    )
163
    mailinglist = models.ForeignKey(MailingList,
164
                                    verbose_name=_("Mailing list"),
165
166
                                    on_delete=models.CASCADE,
                                    related_name='aliasses')
167

168
    def clean(self):
Joren Vrancken's avatar
Joren Vrancken committed
169
        """Validate the alias."""
170
171
        super().clean()
        if (MailingList.objects
172
173
                .filter(name=self.alias).count() > 0 or
                self.alias in get_automatic_mailinglists()):
174
175
176
177
178
179
180
181
            raise ValidationError({
                'alias': _("%(model_name)s with this "
                           "%(field_label)s already exists.") % {
                    'model_name': _("Mailing list"),
                    'field_label': _("Name")
                }
            })

Thom Wiggers's avatar
Thom Wiggers committed
182
    def __str__(self):
Joren Vrancken's avatar
Joren Vrancken committed
183
        """Return a string representation of the alias and mailing list."""
Thom Wiggers's avatar
Thom Wiggers committed
184
185
186
187
        return (_("List alias {alias} for {list}")
                .format(alias=self.alias,
                        list=self.mailinglist.name))

188
    class Meta:
Joren Vrancken's avatar
Joren Vrancken committed
189
190
        """Meta class for ListAlias."""

191
192
        verbose_name = _("List alias")
        verbose_name_plural = _("List aliasses")