Commit 09a49de8 authored by Joost Rijneveld's avatar Joost Rijneveld
Browse files

Merge branch 'feature/mailinglist-committee-contact' into 'master'

Add OneToOneField from Committee to MailingList next to contact email string

See merge request !486
parents 532099f0 e8c1a5f3
......@@ -35,8 +35,9 @@ class CommitteeAdmin(TranslatedModelAdmin):
search_fields = ('name', 'description')
filter_horizontal = ('permissions',)
fields = ('name', 'description', 'photo', 'permissions',
'since', 'until', 'contact_email', 'wiki_namespace', 'active')
fields = ('name', 'description', 'photo', 'permissions', 'since',
'until', 'contact_mailinglist', 'contact_email',
'wiki_namespace', 'active')
def get_queryset(self, request):
qs = super().get_queryset(request)
......@@ -49,8 +50,8 @@ class BoardAdmin(TranslatedModelAdmin):
exclude = ('is_board',)
filter_horizontal = ('permissions',)
fields = ('name', 'photo', 'permissions',
'since', 'until',)
fields = ('name', 'photo', 'permissions', 'contact_mailinglist',
'contact_email', 'since', 'until',)
@admin.register(models.CommitteeMembership)
......
......@@ -7,170 +7,185 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-13 21:12+0100\n"
"PO-Revision-Date: 2017-01-30 18:54+0100\n"
"Last-Translator: Joost Rijneveld <joost@joostrijneveld.nl>\n"
"POT-Creation-Date: 2017-07-05 19:09+0200\n"
"PO-Revision-Date: 2017-08-17 11:41+0200\n"
"Last-Translator: Sébastiaan Versteeg <se_bastiaan@outlook.com>\n"
"Language-Team: \n"
"Language: nl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.8.11\n"
"X-Generator: Poedit 2.0.3\n"
#: models.py:53
#: models.py:55
msgid "Committee name"
msgstr "Commissienaam"
#: models.py:59
#: models.py:61
msgid "Description"
msgstr "Beschrijving"
#: models.py:63
#: models.py:65
msgid "Image"
msgstr "Afbeelding"
#: models.py:76
#: models.py:78
msgid "permissions"
msgstr "permissies"
#: models.py:81
#: models.py:83
msgid "founded in"
msgstr "opgericht in"
#: models.py:87
#: models.py:89
msgid "existed until"
msgstr "bestond tot"
#: models.py:94
#: models.py:97
msgid "contact email address"
msgstr "contact e-mailadres"
#: models.py:97
#: models.py:104
msgid "contact mailing list"
msgstr "contact mailinglijst"
#: models.py:110
msgid "Wiki namespace"
msgstr "Wiki namespace"
#: models.py:109
#: models.py:121 models.py:124
msgid "Please use either the mailing list or email address option."
msgstr "Selecteer een mailinglijst óf vul een e-mailadres in."
#: models.py:135
msgid "committee"
msgstr "commissie"
#: models.py:110 templates/activemembers/committee_index.html:6
#: models.py:136 templates/activemembers/committee_index.html:7
msgid "committees"
msgstr "commissies"
#: models.py:131
#: models.py:157
msgid "Is this a board"
msgstr "Is dit een bestuur"
#: models.py:149 models.py:150
#: models.py:164
msgid "Access the board wiki"
msgstr ""
#: models.py:190 models.py:191
msgid "A board already exists for those years"
msgstr "Er bestaat al een bestuur voor die jaren"
#: models.py:167 models.py:299
#: models.py:209 models.py:342
msgid "Member"
msgstr "Lid"
#: models.py:173
#: models.py:215
msgid "Committee"
msgstr "Commissie"
#: models.py:177
#: models.py:219
msgid "Committee member since"
msgstr "Commissielid sinds"
#: models.py:178
#: models.py:220
msgid "The date this member joined the committee in this role"
msgstr "De datum waarop deze persoon lid werd deze commissie in deze rol"
#: models.py:183
#: models.py:225
msgid "Committee member until"
msgstr "Commissielid tot"
#: models.py:184
#: models.py:226
msgid "A member of this committee until this time (can't be in the future)."
msgstr ""
"De datum waarop deze persoon de commissie verliet (kan niet in de toekomst "
"liggen)"
#: models.py:191
#: models.py:233
msgid "Chair of the committee"
msgstr "Voorzitter van de commissie"
#: models.py:192
#: models.py:234
msgid "There can only be one chair at a time!"
msgstr "Er kan maar één voorzitter tegelijkertijd zijn!"
#: models.py:198
#: models.py:240
msgid "role"
msgstr "rol"
#: models.py:199
#: models.py:241
msgid "The role of this member"
msgstr "De rol van dit lid binnen de commissie"
#: models.py:225
#: models.py:267
msgid "End date can't be before start date"
msgstr "De einddatum kan niet voor de startdatum liggen"
#: models.py:228
#: models.py:270
msgid "End date can't be in the future"
msgstr "De einddatum kan niet in de toekomst liggen"
#: models.py:232
#: models.py:274
msgid "End date cannot be set for boards"
msgstr "Voor besturen kan geen einddatum worden opgegeven"
#: models.py:255
#: models.py:298
msgid "There already is a chair for this time period"
msgstr "Er is al een voorzitter voor deze periode"
#: models.py:271
#: models.py:314
msgid "This member is already in the committee for this period"
msgstr "Deze persoon is al lid van deze commissie in de aangegeven periode"
#: models.py:291
#: models.py:334
msgid "committee membership"
msgstr "commissielidmaatschap"
#: models.py:292
#: models.py:335
msgid "committee memberships"
msgstr "commissielidmaatschappen"
#: models.py:304
#: models.py:347
#, python-brace-format
msgid "{name} mentor in {year}"
msgstr "{name} mentor in {year}"
#: templates/activemembers/board_detail.html:4
#: templates/activemembers/board_detail.html:8
#: templates/activemembers/board_index.html:45
#: templates/activemembers/board_index.html:50
#: templates/activemembers/board_detail.html:5
#: templates/activemembers/board_detail.html:9
#: templates/activemembers/board_index.html:46
#: templates/activemembers/board_index.html:51
msgid "Board"
msgstr "Bestuur"
#: templates/activemembers/board_detail.html:4
#: templates/activemembers/board_detail.html:5
#: templates/activemembers/board_index.html:3
#: templates/activemembers/board_index.html:4
msgid "Boards"
msgstr "Besturen"
#: templates/activemembers/board_detail.html:26
#: templates/activemembers/board_detail.html:27
msgid "Board members"
msgstr "Bestuursleden"
#: templates/activemembers/board_detail.html:42
#: templates/activemembers/committee_detail.html:44
#: templates/activemembers/board_detail.html:43
#: templates/activemembers/committee_detail.html:45
msgid "Chair"
msgstr "Voorzitter"
#: templates/activemembers/board_detail.html:59
#: templates/activemembers/board_detail.html:60
msgid "This board doesn't have any members?"
msgstr "Dit bestuur heeft geen leden?"
#: templates/activemembers/board_index.html:6
#: templates/activemembers/board_index.html:7
msgid "The board"
msgstr "Het bestuur"
#: templates/activemembers/board_index.html:9
#: templates/activemembers/board_index.html:10
msgid ""
"Thalia's board makes sure all operations during the academic year are taken "
"care of, in front or behind the scenes. If you have any questions then you "
......@@ -183,48 +198,50 @@ msgstr ""
"schermen. Bij vragen en opmerkingen kun je ze altijd persoonlijk aanspreken "
"of <a href=\"mailto:info@thalia.nu\">mailen</a>."
#: templates/activemembers/board_index.html:27
#: templates/activemembers/board_index.html:28
msgid "Old boards"
msgstr "Oude besturen"
#: templates/activemembers/board_index.html:37
#: templates/activemembers/committee_detail.html:18
#: templates/activemembers/committee_detail.html:20
#: templates/activemembers/board_index.html:38
#: templates/activemembers/committee_detail.html:19
#: templates/activemembers/committee_detail.html:21
#, python-format
msgid "Photo of %(name)s"
msgstr "Foto van %(name)s"
#: templates/activemembers/board_index.html:57
#: templates/activemembers/board_index.html:58
msgid "There are no boards!"
msgstr "Er zijn geen besturen!"
#: templates/activemembers/committee_detail.html:3
#: templates/activemembers/committee_detail.html:4
#: templates/activemembers/committee_index.html:3
#: templates/activemembers/committee_index.html:4
msgid "Committees"
msgstr "Commissies"
#: templates/activemembers/committee_detail.html:24
#: templates/activemembers/committee_detail.html:25
#, python-format
msgid "About the %(name)s"
msgstr "Over de %(name)s"
#: templates/activemembers/committee_detail.html:28
#: templates/activemembers/committee_detail.html:29
msgid "Committee members"
msgstr "Commissieleden"
#: templates/activemembers/committee_detail.html:53
#: templates/activemembers/committee_detail.html:54
msgid "Committee member since: ?"
msgstr "Commissielid sinds: ?"
#: templates/activemembers/committee_detail.html:55
#: templates/activemembers/committee_detail.html:56
#, python-format
msgid "Committee member since: %(since)s"
msgstr "Commissielid sinds: %(since)s"
#: templates/activemembers/committee_detail.html:67
#: templates/activemembers/committee_detail.html:68
msgid "This committee doesn't have any members?"
msgstr "Deze commissie heeft geen leden?"
#: templates/activemembers/committee_index.html:39
#: templates/activemembers/committee_index.html:40
msgid "There are no committees!"
msgstr "Er zijn geen commissies!"
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2017-07-05 16:59
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mailinglists', '0009_auto_20170429_2149'),
('activemembers', '0019_auto_20170227_1632'),
]
operations = [
migrations.AddField(
model_name='committee',
name='contact_mailinglist',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mailinglists.MailingList', verbose_name='contact mailing list'),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2017-07-05 17:02
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('activemembers', '0020_committee_contact_mailinglist'),
]
operations = [
migrations.AlterField(
model_name='committee',
name='contact_email',
field=models.EmailField(blank=True, max_length=254, null=True, verbose_name='contact email address'),
),
]
......@@ -17,6 +17,7 @@ logger = logging.getLogger(__name__)
class UnfilteredSortedManager(models.Manager):
"""Returns committees and boards, sorted by name"""
def get_queryset(self):
return (super().get_queryset()
.order_by(localize_attr_name('name')))
......@@ -24,6 +25,7 @@ class UnfilteredSortedManager(models.Manager):
class CommitteeManager(models.Manager):
"""Returns committees only"""
def get_queryset(self):
return (super().get_queryset()
.exclude(board__is_board=True)
......@@ -32,6 +34,7 @@ class CommitteeManager(models.Manager):
class ActiveCommitteeManager(models.Manager):
"""Returns active committees only"""
def get_queryset(self):
return (super().get_queryset()
.exclude(board__is_board=True)
......@@ -90,7 +93,18 @@ class Committee(models.Model, metaclass=ModelTranslateMeta):
active = models.BooleanField(default=False)
contact_email = models.EmailField(_('contact email address'))
contact_email = models.EmailField(
_('contact email address'),
blank=True,
null=True,
)
contact_mailinglist = models.OneToOneField(
'mailinglists.MailingList',
verbose_name=_('contact mailing list'),
null=True,
blank=True,
)
wiki_namespace = models.CharField(
_('Wiki namespace'),
......@@ -98,6 +112,21 @@ class Committee(models.Model, metaclass=ModelTranslateMeta):
blank=True,
max_length=50)
def clean(self):
"""Validation"""
if ((self.contact_email is not None and
self.contact_mailinglist is not None) or
(self.contact_email is None and
self.contact_mailinglist is None)):
raise ValidationError({
'contact_email':
_("Please use either the mailing list "
"or email address option."),
'contact_mailinglist':
_("Please use either the mailing list "
"or email address option.")
})
def __str__(self):
return self.name
......@@ -114,8 +143,8 @@ class BoardManager(models.Manager):
def get_queryset(self):
# sorting by descending order by default makes more sense for boards
return (super().get_queryset()
.filter(is_board=True)
.order_by(localize_attr_name('-name')))
.filter(is_board=True)
.order_by(localize_attr_name('-name')))
class Board(Committee):
......@@ -155,10 +184,10 @@ class Board(Committee):
continue
if ((board.until is None and (
self.until is None or self.until >= board.since)) or
(self.until is None and self.since <= board.until) or
(self.until and board.until and
self.since <= board.until and
self.until >= board.since)):
(self.until is None and self.since <= board.until) or
(self.until and board.until and
self.since <= board.until and
self.until >= board.since)):
raise ValidationError({
'since': _('A board already exists for those years'),
'until': _('A board already exists for those years')})
......@@ -166,6 +195,7 @@ class Board(Committee):
class ActiveMembershipManager(models.Manager):
"""Get only active memberships"""
def get_queryset(self):
"""Get the currently active committee memberships"""
return super().get_queryset().exclude(until__lt=timezone.now().date())
......@@ -260,13 +290,14 @@ class CommitteeMembership(models.Model, metaclass=ModelTranslateMeta):
continue
if ((chair.until is None and
(self.until is None or self.until > chair.since)) or
(self.until is None and self.since < chair.until) or
(self.until and chair.until and
self.since < chair.until and
self.until > chair.since)):
(self.until is None and self.since < chair.until) or
(self.until and chair.until and
self.since < chair.until and
self.until > chair.since)):
raise ValidationError({
NON_FIELD_ERRORS:
_('There already is a chair for this time period')})
_('There already is a '
'chair for this time period')})
# check if this member is already in the committee in this period
memberships = (CommitteeMembership.objects
......@@ -277,22 +308,20 @@ class CommitteeMembership(models.Model, metaclass=ModelTranslateMeta):
continue
if ((mship.until is None and
(self.until is None or self.until > mship.since)) or
(self.until is None and self.since < mship.until) or
(self.until and mship.until and
self.since < mship.until and
self.until > mship.since)):
(self.until is None and self.since < mship.until) or
(self.until and mship.until and
self.since < mship.until and
self.until > mship.since)):
raise ValidationError({
'member': _('This member is already in the committee for '
'this period')})
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
self.member.user.is_staff = (
self.member
.committeemembership_set
.exclude(
until__lte=timezone.now().date())
.count()) >= 1
self.member.user.is_staff = (self.member
.committeemembership_set
.exclude(until__lte=timezone.now().date())
.count()) >= 1
self.member.user.save()
def __str__(self):
......
......@@ -5,6 +5,7 @@ from django.test import TestCase
from django.utils import timezone
from activemembers.models import Committee, CommitteeMembership, Board
from mailinglists.models import MailingList
from members.models import Member
......@@ -155,6 +156,55 @@ class PermissionsBackendTest(TestCase):
self.assertEqual(set(), u.get_all_permissions())
class CommitteeMailingListTest(TestCase):
fixtures = ['mailinglists.json', 'committees.json']
@classmethod
def setUpTestData(cls):
cls.testcie1 = Committee.objects.get(pk=1)
cls.testcie2 = Committee.objects.get(pk=2)
cls.mailtest1 = MailingList.objects.get(pk=1)
cls.mailtest2 = MailingList.objects.get(pk=2)
def setUp(self):
self.testcie1.refresh_from_db()
self.testcie2.refresh_from_db()
self.mailtest1.refresh_from_db()
self.mailtest2.refresh_from_db()
def test_one_to_one(self):
self.testcie1.contact_mailinglist = self.mailtest1
self.testcie1.save()
self.testcie2.contact_mailinglist = self.mailtest1
with self.assertRaises(ValidationError):
self.testcie2.full_clean()
self.testcie2.contact_mailinglist = self.mailtest2
self.testcie2.full_clean()
def test_exactly_one_address(self):
with self.assertRaises(ValidationError):
self.testcie1.contact_mailinglist = self.mailtest1
self.testcie1.contact_email = "test@test.com"
self.testcie1.full_clean()
with self.assertRaises(ValidationError):
self.testcie1.contact_mailinglist = None
self.testcie1.contact_email = None
self.testcie1.full_clean()
self.testcie1.contact_mailinglist = self.mailtest1
self.testcie1.contact_email = None
self.testcie1.full_clean()
self.testcie1.contact_mailinglist = None
self.testcie1.contact_email = "test@test.com"
self.testcie1.full_clean()
class BoardTest(TestCase):
fixtures = ['committees.json']
......@@ -173,7 +223,7 @@ class BoardTest(TestCase):
b = Board(
name_nl="testbe",
name_en="testbo",
contact_email="test@test.com",
contact_email='board@example.org',
description_nl="descnl",
description_en="descen",
since=timezone.now().date()
......@@ -197,7 +247,7 @@ class BoardTest(TestCase):
b = Board(
name_nl="testbe",
name_en="testbo",
contact_email="test@test.com",
contact_email='board@example.org',
description_nl="descnl",
description_en="descen",
since=timezone.now().date()
......
[
{
"model": "mailinglists.mailinglist",
"pk": 1,
"fields": {
"name": "mailtest1"
}
},
{
"model": "mailinglists.mailinglist",
"pk": 2,
"fields": {
"name": "mailtest2"
}
}
]
Supports Markdown
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