Verified Commit 3be5cfc5 authored by Sébastiaan Versteeg's avatar Sébastiaan Versteeg
Browse files

Add email change feature to members

parent 73fa3a39
......@@ -3,7 +3,6 @@ This module registers admin pages for the models
"""
import csv
import datetime
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User
......@@ -12,6 +11,7 @@ from django.http import HttpResponse
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from members.models import EmailChange
from . import forms, models
......@@ -145,6 +145,8 @@ class MemberAdmin(UserAdmin):
return False
admin.site.register(EmailChange)
# re-register User admin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
from base64 import b64encode
from django.contrib.staticfiles.finders import find as find_static_file
from django.templatetags.static import static
from django.urls import reverse
from rest_framework import serializers
from thaliawebsite.api.services import create_image_thumbnail_dict
from events.api.serializers import CalenderJSSerializer
from members.models import Member
from members.services import member_achievements
from thaliawebsite.api.services import create_image_thumbnail_dict
from utils.templatetags.thumbnail import thumbnail
......
import copy
from datetime import datetime
from django.utils import timezone
from pytz.exceptions import InvalidTimeError
from rest_framework import permissions
from rest_framework import viewsets, filters
from rest_framework.decorators import list_route
from rest_framework.exceptions import ParseError
from rest_framework.response import Response
from pytz.exceptions import InvalidTimeError
from members.api.serializers import (MemberBirthdaySerializer,
MemberRetrieveSerializer,
......
from datetime import timedelta
from django.core import mail
from django.template import loader
from django.template.defaultfilters import floatformat
from django.urls import reverse
from django.utils import translation
from django.utils.datetime_safe import datetime
from django.utils.translation import ugettext as _
from django.template.defaultfilters import floatformat
from members.models import Member
from thaliawebsite import settings
......@@ -92,7 +92,7 @@ def send_expiration_announcement(dry_run=False):
'members/email/expiration_announcement.txt',
{'name': member.get_full_name(),
'membership_price': floatformat(
settings.MEMBERSHIP_PRICES['year'], 2
settings.MEMBERSHIP_PRICES['year'], 2
)})
mail.EmailMessage(
_('Membership expiration announcement'),
......@@ -125,3 +125,54 @@ def send_welcome_message(user, password, language):
user.email_user(
_('Welcome to Study Association Thalia'),
email_body)
def send_email_change_confirmation_messages(change_request):
member = change_request.member
with translation.override(member.profile.language):
mail.EmailMessage(
'[THALIA] {}'.format(_('Please confirm your email change')),
loader.render_to_string(
'members/email/email_change_confirm.txt',
{
'confirm_link': '{}{}'.format(
'https://thalia.nu',
reverse(
'members:email-change-confirm',
args=[change_request.confirm_key]
)),
'name': member.first_name
}
),
settings.WEBSITE_FROM_ADDRESS,
[change_request.email]
).send()
mail.EmailMessage(
'[THALIA] {}'.format(_('Please verify your email address')),
loader.render_to_string(
'members/email/email_change_verify.txt',
{
'confirm_link': '{}{}'.format(
'https://thalia.nu',
reverse(
'members:email-change-verify',
args=[change_request.verify_key]
)),
'name': member.first_name
}
),
settings.WEBSITE_FROM_ADDRESS,
[change_request.email]
).send()
def send_email_change_completion_message(change_request):
change_request.member.email_user(
'[THALIA] {}'.format(_('Your email address has been changed')),
loader.render_to_string(
'members/email/email_change_completed.txt',
{
'name': change_request.member.first_name
}
))
......@@ -6,8 +6,8 @@ from django.contrib.auth.forms import UserCreationForm as BaseUserCreationForm
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from members import emails, models
from .models import Profile
from members import emails
class ProfileForm(forms.ModelForm):
......@@ -116,3 +116,9 @@ class UserChangeForm(BaseUserChangeForm):
self.cleaned_data['username'] = (self.cleaned_data['username']
.lower())
super().clean()
class EmailChangeForm(forms.ModelForm):
class Meta:
model = models.EmailChange
fields = ['email', 'member']
......@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-05-29 16:25+0200\n"
"PO-Revision-Date: 2018-05-29 16:26+0200\n"
"POT-Creation-Date: 2018-06-07 14:17+0200\n"
"PO-Revision-Date: 2018-06-07 14:25+0200\n"
"Last-Translator: Sébastiaan Versteeg <se_bastiaan@outlook.com>\n"
"Language-Team: \n"
"Language: nl\n"
......@@ -16,61 +16,61 @@ msgstr ""
"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.7.1\n"
"X-Generator: Poedit 2.0.4\n"
#: admin.py:39
#: admin.py:40
msgid "membership type"
msgstr "lidtype"
#: admin.py:57
#: admin.py:58
msgid "Age"
msgstr "Leeftijd"
#: admin.py:62
#: admin.py:63
msgid "≥ 18"
msgstr "≥ 18"
#: admin.py:63
#: admin.py:64
msgid "< 18"
msgstr "< 18"
#: admin.py:64
#: admin.py:65
msgid "Unknown"
msgstr "Onbekend"
#: admin.py:112 admin.py:131 forms.py:87
#: admin.py:113 admin.py:132 forms.py:87
msgid "First name"
msgstr "Voornaam"
#: admin.py:112 admin.py:131 forms.py:95
#: admin.py:113 admin.py:132 forms.py:95
msgid "Last name"
msgstr "Achternaam"
#: admin.py:112
#: admin.py:113
msgid "Address"
msgstr "Adres"
#: admin.py:113
#: admin.py:114
msgid "Address line 2"
msgstr "Tweede adresregel"
#: admin.py:113 models.py:217
#: admin.py:114 models.py:218
msgid "Postal code"
msgstr "Postcode"
#: admin.py:113 models.py:223
#: admin.py:114 models.py:224
msgid "City"
msgstr "Woonplaats"
#: admin.py:123
#: admin.py:124
msgid "Download address label for selected users"
msgstr "Download adreslabels voor geselecteerde gebruikers"
#: admin.py:131 models.py:180
#: admin.py:132 models.py:181
msgid "Student number"
msgstr "Studentnummer"
#: admin.py:138
#: admin.py:139
msgid "Download student number label for selected users"
msgstr "Download studentnummers voor geselecteerde gebruikers"
......@@ -78,34 +78,46 @@ msgstr "Download studentnummers voor geselecteerde gebruikers"
msgid "Members"
msgstr "Leden"
#: emails.py:28
#: emails.py:30
msgid "Membership announcement"
msgstr "Mededeling over lidmaatschap"
#: emails.py:38
#: emails.py:40
msgid "Membership announcement sent"
msgstr "Mededeling over lidmaatschap verzonden"
#: emails.py:60
#: emails.py:62
msgid "Membership information check"
msgstr "Controle gegevens lidmaatschap"
#: emails.py:70
#: emails.py:72
msgid "Membership information check sent"
msgstr "Controle gegevens lidmaatschap verzonden"
#: emails.py:94
#: emails.py:99
msgid "Membership expiration announcement"
msgstr "Verlopen lidmaatschap"
#: emails.py:104
#: emails.py:109
msgid "Membership expiration announcement sent"
msgstr "Meldingen vervallen lidmaatschap verzonden"
#: emails.py:122
#: emails.py:127
msgid "Welcome to Study Association Thalia"
msgstr "Welkom bij Studievereniging Thalia"
#: emails.py:135
msgid "Please confirm your email change"
msgstr "Bevestig de verandering van je e-mailadres"
#: emails.py:153
msgid "Please verify your email address"
msgstr "Verifieer je nieuwe e-mailadres"
#: emails.py:173
msgid "Your email address has been changed"
msgstr "Je e-mailadres is aangepast"
#: forms.py:31
msgid "Please enter a bank account"
msgstr "Voer een bankrekening in"
......@@ -122,83 +134,83 @@ msgstr "Deze e-mail zal het gegenereerde wachtwoord bevatten"
msgid "Email address"
msgstr "E-mailadres"
#: models.py:125
#: models.py:126
msgid "Is this user currently active"
msgstr "Is deze user op dit moment actief"
#: models.py:159
#: models.py:160
msgid "Computing Science"
msgstr "Informatica"
#: models.py:160
#: models.py:161
msgid "Information Sciences"
msgstr "Informatiekunde"
#: models.py:174 templates/members/profile.html:44
#: models.py:175 templates/members/profile.html:44
msgid "Study programme"
msgstr "Studie"
#: models.py:184
#: models.py:185
msgid "Enter a valid student- or e/z/u-number."
msgstr "Voer een geldig student- of e/z/u-nummer in."
#: models.py:190
#: models.py:191
msgid "Starting year"
msgstr "Startjaar"
#: models.py:191
#: models.py:192
msgid "The year this member started studying."
msgstr "Het jaar waarop dit lid begon met studeren."
#: models.py:202
#: models.py:203
msgid "Include the house number"
msgstr "Inclusief huisnummer"
#: models.py:204
#: models.py:205
msgid "Street and house number"
msgstr "Straat en huisnummer"
#: models.py:210
#: models.py:211
msgid "Second address line"
msgstr "Tweede adresregel"
#: models.py:229
#: models.py:230
msgid "Phone number"
msgstr "Telefoonnummer"
#: models.py:230
#: models.py:231
msgid "Enter a phone number so Thalia may reach you"
msgstr "Voer een telefoonnummer in zodat Thalia je kan bereiken"
#: models.py:233 models.py:255
#: models.py:234 models.py:256
msgid "Please enter a valid phone number"
msgstr "Voer svp een geldig telefoonnummer in"
#: models.py:243
#: models.py:244
msgid "Emergency contact name"
msgstr "Contact voor noodgevallen"
#: models.py:244
#: models.py:245
msgid "Who should we contact in case of emergencies"
msgstr "Wie Thalia moet bereiken in bij noodgevallen"
#: models.py:251
#: models.py:252
msgid "Emergency contact phone number"
msgstr "Telefoonnummer noodcontact"
#: models.py:252
#: models.py:253
msgid "The phone number for the emergency contact"
msgstr "Het telefoonummer van de noodcontact"
#: models.py:264 templates/members/profile.html:52
#: models.py:265 templates/members/profile.html:52
msgid "Birthday"
msgstr "Verjaardag"
#: models.py:269
#: models.py:270
msgid "Display birthday"
msgstr "Laat verjaardag zien"
#: models.py:271
#: models.py:272
msgid ""
"Show your birthday to other members on your profile page and in the birthday "
"calendar"
......@@ -206,107 +218,107 @@ msgstr ""
"Toon je verjaardag aan andere leden op je profielpagina en in de "
"verjaardagskalender"
#: models.py:278 templates/members/profile.html:48
#: models.py:279 templates/members/profile.html:48
msgid "Website"
msgstr "Website"
#: models.py:279
#: models.py:280
msgid "Website to display on your profile page"
msgstr "Website om op je profiel te linken"
#: models.py:285
#: models.py:286
msgid "Profile text"
msgstr "Profieltekst"
#: models.py:286
#: models.py:287
msgid "Text to display on your profile"
msgstr "Tekst om te laten zien op je profielpagina"
#: models.py:294
#: models.py:295
msgid "Initials"
msgstr "Initialen"
#: models.py:301
#: models.py:302
msgid "Nickname"
msgstr "Bijnaam"
#: models.py:308
#: models.py:309
msgid "How to display name"
msgstr "Weergave naam"
#: models.py:309
#: models.py:310
msgid "Show full name"
msgstr "Volledige naam"
#: models.py:310
#: models.py:311
msgid "Show only nickname"
msgstr "Alleen initialen"
#: models.py:311
#: models.py:312
msgid "Show only first name"
msgstr "Alleen voornaam"
#: models.py:312
#: models.py:313
msgid "Show initials and last name"
msgstr "Alleen initialen en achternaam"
#: models.py:313
#: models.py:314
msgid "Show name like \"John 'nickname' Doe\""
msgstr "Laat zien als \"John 'bijnaam' Doe\""
#: models.py:314
#: models.py:315
msgid "Show nickname and last name"
msgstr "Laat bijnaam en achternaam zien"
#: models.py:319
#: models.py:320
msgid "Photo"
msgstr "Foto"
#: models.py:327
#: models.py:328
msgid "Which events can this member attend"
msgstr "Welke evenementen mag dit lid bijwonen"
#: models.py:328
#: models.py:329
msgid "All events"
msgstr "Alle evenementen"
#: models.py:329
#: models.py:330
msgid "User may not attend events"
msgstr "Gebruiker mag niet naar evenementen"
#: models.py:330
#: models.py:331
msgid "User may not attend drinks"
msgstr "Gebruiker mag niet naar borrels"
#: models.py:331
#: models.py:332
msgid "User may not attend anything"
msgstr "Gebruiker mag nergens heen"
#: models.py:338
#: models.py:339
msgid "Preferred language"
msgstr "Voorkeurstaal"
#: models.py:339
#: models.py:340
msgid "Preferred language for e.g. newsletters"
msgstr "Voorkeurstaal voor b.v.b. nieuwsbrieven"
#: models.py:346
#: models.py:347
msgid "Receive opt-in mailings"
msgstr "Ontvang opt-in mailings"
#: models.py:347
#: models.py:348
msgid "Receive mailings about vacancies and events from Thalia's sponsors."
msgstr "Ontvang mailings over vacatures en evenementen van Thalia's sponsoren."
#: models.py:353
#: models.py:354
msgid "Receive newsletter"
msgstr "Ontvang nieuwsbrief"
#: models.py:354
#: models.py:355
msgid "Receive the Thalia Newsletter"
msgstr "Ontvang de Thalia nieuwsbrief"
#: models.py:361
#: models.py:362
msgid ""
"Yes, I want Thalia to take the membership fees from my bank account through "
"direct debit for each year."
......@@ -314,90 +326,126 @@ msgstr ""
"Ja, ik wil dat Thalia verschuldigde lidmaatschapsgelden elk jaar van mijn "
"bankrekening afschrijft."
#: models.py:364
#: models.py:365
msgid "No, I will pay the contribution myself"
msgstr "Nee, ik zal de contributie zelf betalen"
#: models.py:365
#: models.py:366
msgid "Direct debit"
msgstr "Automatische afschijving"
#: models.py:366
#: models.py:367
msgid "Each year, have Thalia take the membership fees from my bank account"
msgstr ""
"Laat Thalia elk jaar het lidmaatschapsgeld van mijn bankrekening afschrijven"
#: models.py:372
#: models.py:373
msgid "Bank account"
msgstr "Bankrekening"
#: models.py:373
#: models.py:374
msgid "Bank account for direct debit"
msgstr "Bankrekening voor automatische afschrijving"
#: models.py:397
#: models.py:398
msgid "Display name"
msgstr "Weergavenaam"
#: models.py:426
#: models.py:427
msgid "You need to enter a nickname to use it as display name"
msgstr ""
"Je moet een bijnaam invoeren voordat je deze kunt gebruiken als weergavenaam"
#: models.py:431
#: models.py:432
msgid "A birthday cannot be in the future."
msgstr "Een verjaardag kan niet in de toekomst liggen."
#: models.py:481
#: models.py:482
msgid "Member"
msgstr "Lid"
#: models.py:482
#: models.py:483
msgid "Supporter"
msgstr "Begunstiger"
#: models.py:483
#: models.py:484
msgid "Honorary Member"
msgstr "Erelid"
#: models.py:488 templates/members/profile.html:37
#: models.py:489 templates/members/profile.html:37
msgid "Membership type"
msgstr "Lidtype"
#: models.py:494
#: models.py:495
msgid "User"
msgstr "Gebruiker"
#: models.py:498
#: models.py:499
msgid "Membership since"
msgstr "Lid sinds"
#: models.py:499
#: models.py:500
msgid "The date the member started holding this membership."
msgstr "De datum waarop het lid dit lidmaatschap is begonnen."
#: models.py:504
#: models.py:505
msgid "Membership until"
msgstr "Lid tot"
#: models.py:505
#: models.py:506
msgid "The date the member stops holding this membership."
msgstr "De datum waarop het lid dit lidmaatschap beëindigd."
#: models.py:516
#: models.py:517
msgid "End date can't be before start date"
msgstr "De einddatum kan niet eerder zijn dan de startdatum"
#: models.py:530 models.py:532
#: models.py:531 models.py:533
msgid "A membership already exists for that period"
msgstr "Er bestaat al een lidmaatschap voor deze periode"
#: models.py:544