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 ...@@ -3,7 +3,6 @@ This module registers admin pages for the models
""" """
import csv import csv
import datetime import datetime
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User from django.contrib.auth.models import User
...@@ -12,6 +11,7 @@ from django.http import HttpResponse ...@@ -12,6 +11,7 @@ from django.http import HttpResponse
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from members.models import EmailChange
from . import forms, models from . import forms, models
...@@ -145,6 +145,8 @@ class MemberAdmin(UserAdmin): ...@@ -145,6 +145,8 @@ class MemberAdmin(UserAdmin):
return False return False
admin.site.register(EmailChange)
# re-register User admin # re-register User admin
admin.site.unregister(User) admin.site.unregister(User)
admin.site.register(User, UserAdmin) admin.site.register(User, UserAdmin)
from base64 import b64encode from base64 import b64encode
from django.contrib.staticfiles.finders import find as find_static_file from django.contrib.staticfiles.finders import find as find_static_file
from django.templatetags.static import static from django.templatetags.static import static
from django.urls import reverse from django.urls import reverse
from rest_framework import serializers from rest_framework import serializers
from thaliawebsite.api.services import create_image_thumbnail_dict
from events.api.serializers import CalenderJSSerializer from events.api.serializers import CalenderJSSerializer
from members.models import Member from members.models import Member
from members.services import member_achievements from members.services import member_achievements
from thaliawebsite.api.services import create_image_thumbnail_dict
from utils.templatetags.thumbnail import thumbnail from utils.templatetags.thumbnail import thumbnail
......
import copy import copy
from datetime import datetime from datetime import datetime
from django.utils import timezone from django.utils import timezone
from pytz.exceptions import InvalidTimeError
from rest_framework import permissions from rest_framework import permissions
from rest_framework import viewsets, filters from rest_framework import viewsets, filters
from rest_framework.decorators import list_route from rest_framework.decorators import list_route
from rest_framework.exceptions import ParseError from rest_framework.exceptions import ParseError
from rest_framework.response import Response from rest_framework.response import Response
from pytz.exceptions import InvalidTimeError
from members.api.serializers import (MemberBirthdaySerializer, from members.api.serializers import (MemberBirthdaySerializer,
MemberRetrieveSerializer, MemberRetrieveSerializer,
......
from datetime import timedelta from datetime import timedelta
from django.core import mail from django.core import mail
from django.template import loader from django.template import loader
from django.template.defaultfilters import floatformat
from django.urls import reverse
from django.utils import translation from django.utils import translation
from django.utils.datetime_safe import datetime from django.utils.datetime_safe import datetime
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.template.defaultfilters import floatformat
from members.models import Member from members.models import Member
from thaliawebsite import settings from thaliawebsite import settings
...@@ -92,7 +92,7 @@ def send_expiration_announcement(dry_run=False): ...@@ -92,7 +92,7 @@ def send_expiration_announcement(dry_run=False):
'members/email/expiration_announcement.txt', 'members/email/expiration_announcement.txt',
{'name': member.get_full_name(), {'name': member.get_full_name(),
'membership_price': floatformat( 'membership_price': floatformat(
settings.MEMBERSHIP_PRICES['year'], 2 settings.MEMBERSHIP_PRICES['year'], 2
)}) )})
mail.EmailMessage( mail.EmailMessage(
_('Membership expiration announcement'), _('Membership expiration announcement'),
...@@ -125,3 +125,54 @@ def send_welcome_message(user, password, language): ...@@ -125,3 +125,54 @@ def send_welcome_message(user, password, language):
user.email_user( user.email_user(
_('Welcome to Study Association Thalia'), _('Welcome to Study Association Thalia'),
email_body) 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 ...@@ -6,8 +6,8 @@ from django.contrib.auth.forms import UserCreationForm as BaseUserCreationForm
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from members import emails, models
from .models import Profile from .models import Profile
from members import emails
class ProfileForm(forms.ModelForm): class ProfileForm(forms.ModelForm):
...@@ -116,3 +116,9 @@ class UserChangeForm(BaseUserChangeForm): ...@@ -116,3 +116,9 @@ class UserChangeForm(BaseUserChangeForm):
self.cleaned_data['username'] = (self.cleaned_data['username'] self.cleaned_data['username'] = (self.cleaned_data['username']
.lower()) .lower())
super().clean() super().clean()
class EmailChangeForm(forms.ModelForm):
class Meta:
model = models.EmailChange
fields = ['email', 'member']
...@@ -7,8 +7,8 @@ msgid "" ...@@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-05-29 16:25+0200\n" "POT-Creation-Date: 2018-06-07 14:17+0200\n"
"PO-Revision-Date: 2018-05-29 16:26+0200\n" "PO-Revision-Date: 2018-06-07 14:25+0200\n"
"Last-Translator: Sébastiaan Versteeg <se_bastiaan@outlook.com>\n" "Last-Translator: Sébastiaan Versteeg <se_bastiaan@outlook.com>\n"
"Language-Team: \n" "Language-Team: \n"
"Language: nl\n" "Language: nl\n"
...@@ -16,61 +16,61 @@ msgstr "" ...@@ -16,61 +16,61 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\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" msgid "membership type"
msgstr "lidtype" msgstr "lidtype"
#: admin.py:57 #: admin.py:58
msgid "Age" msgid "Age"
msgstr "Leeftijd" msgstr "Leeftijd"
#: admin.py:62 #: admin.py:63
msgid "≥ 18" msgid "≥ 18"
msgstr "≥ 18" msgstr "≥ 18"
#: admin.py:63 #: admin.py:64
msgid "< 18" msgid "< 18"
msgstr "< 18" msgstr "< 18"
#: admin.py:64 #: admin.py:65
msgid "Unknown" msgid "Unknown"
msgstr "Onbekend" msgstr "Onbekend"
#: admin.py:112 admin.py:131 forms.py:87 #: admin.py:113 admin.py:132 forms.py:87
msgid "First name" msgid "First name"
msgstr "Voornaam" msgstr "Voornaam"
#: admin.py:112 admin.py:131 forms.py:95 #: admin.py:113 admin.py:132 forms.py:95
msgid "Last name" msgid "Last name"
msgstr "Achternaam" msgstr "Achternaam"
#: admin.py:112 #: admin.py:113
msgid "Address" msgid "Address"
msgstr "Adres" msgstr "Adres"
#: admin.py:113 #: admin.py:114
msgid "Address line 2" msgid "Address line 2"
msgstr "Tweede adresregel" msgstr "Tweede adresregel"
#: admin.py:113 models.py:217 #: admin.py:114 models.py:218
msgid "Postal code" msgid "Postal code"
msgstr "Postcode" msgstr "Postcode"
#: admin.py:113 models.py:223 #: admin.py:114 models.py:224
msgid "City" msgid "City"
msgstr "Woonplaats" msgstr "Woonplaats"
#: admin.py:123 #: admin.py:124
msgid "Download address label for selected users" msgid "Download address label for selected users"
msgstr "Download adreslabels voor geselecteerde gebruikers" msgstr "Download adreslabels voor geselecteerde gebruikers"
#: admin.py:131 models.py:180 #: admin.py:132 models.py:181
msgid "Student number" msgid "Student number"
msgstr "Studentnummer" msgstr "Studentnummer"
#: admin.py:138 #: admin.py:139
msgid "Download student number label for selected users" msgid "Download student number label for selected users"
msgstr "Download studentnummers voor geselecteerde gebruikers" msgstr "Download studentnummers voor geselecteerde gebruikers"
...@@ -78,34 +78,46 @@ msgstr "Download studentnummers voor geselecteerde gebruikers" ...@@ -78,34 +78,46 @@ msgstr "Download studentnummers voor geselecteerde gebruikers"
msgid "Members" msgid "Members"
msgstr "Leden" msgstr "Leden"
#: emails.py:28 #: emails.py:30
msgid "Membership announcement" msgid "Membership announcement"
msgstr "Mededeling over lidmaatschap" msgstr "Mededeling over lidmaatschap"
#: emails.py:38 #: emails.py:40
msgid "Membership announcement sent" msgid "Membership announcement sent"
msgstr "Mededeling over lidmaatschap verzonden" msgstr "Mededeling over lidmaatschap verzonden"
#: emails.py:60 #: emails.py:62
msgid "Membership information check" msgid "Membership information check"
msgstr "Controle gegevens lidmaatschap" msgstr "Controle gegevens lidmaatschap"
#: emails.py:70 #: emails.py:72
msgid "Membership information check sent" msgid "Membership information check sent"
msgstr "Controle gegevens lidmaatschap verzonden" msgstr "Controle gegevens lidmaatschap verzonden"
#: emails.py:94 #: emails.py:99
msgid "Membership expiration announcement" msgid "Membership expiration announcement"
msgstr "Verlopen lidmaatschap" msgstr "Verlopen lidmaatschap"
#: emails.py:104 #: emails.py:109
msgid "Membership expiration announcement sent" msgid "Membership expiration announcement sent"
msgstr "Meldingen vervallen lidmaatschap verzonden" msgstr "Meldingen vervallen lidmaatschap verzonden"
#: emails.py:122 #: emails.py:127
msgid "Welcome to Study Association Thalia" msgid "Welcome to Study Association Thalia"
msgstr "Welkom bij Studievereniging 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 #: forms.py:31
msgid "Please enter a bank account" msgid "Please enter a bank account"
msgstr "Voer een bankrekening in" msgstr "Voer een bankrekening in"
...@@ -122,83 +134,83 @@ msgstr "Deze e-mail zal het gegenereerde wachtwoord bevatten" ...@@ -122,83 +134,83 @@ msgstr "Deze e-mail zal het gegenereerde wachtwoord bevatten"
msgid "Email address" msgid "Email address"
msgstr "E-mailadres" msgstr "E-mailadres"
#: models.py:125 #: models.py:126
msgid "Is this user currently active" msgid "Is this user currently active"
msgstr "Is deze user op dit moment actief" msgstr "Is deze user op dit moment actief"
#: models.py:159 #: models.py:160
msgid "Computing Science" msgid "Computing Science"
msgstr "Informatica" msgstr "Informatica"
#: models.py:160 #: models.py:161
msgid "Information Sciences" msgid "Information Sciences"
msgstr "Informatiekunde" msgstr "Informatiekunde"
#: models.py:174 templates/members/profile.html:44 #: models.py:175 templates/members/profile.html:44
msgid "Study programme" msgid "Study programme"
msgstr "Studie" msgstr "Studie"
#: models.py:184 #: models.py:185
msgid "Enter a valid student- or e/z/u-number." msgid "Enter a valid student- or e/z/u-number."
msgstr "Voer een geldig student- of e/z/u-nummer in." msgstr "Voer een geldig student- of e/z/u-nummer in."
#: models.py:190 #: models.py:191
msgid "Starting year" msgid "Starting year"
msgstr "Startjaar" msgstr "Startjaar"
#: models.py:191 #: models.py:192
msgid "The year this member started studying." msgid "The year this member started studying."
msgstr "Het jaar waarop dit lid begon met studeren." msgstr "Het jaar waarop dit lid begon met studeren."
#: models.py:202 #: models.py:203
msgid "Include the house number" msgid "Include the house number"
msgstr "Inclusief huisnummer" msgstr "Inclusief huisnummer"
#: models.py:204 #: models.py:205
msgid "Street and house number" msgid "Street and house number"
msgstr "Straat en huisnummer" msgstr "Straat en huisnummer"
#: models.py:210 #: models.py:211
msgid "Second address line" msgid "Second address line"
msgstr "Tweede adresregel" msgstr "Tweede adresregel"
#: models.py:229 #: models.py:230
msgid "Phone number" msgid "Phone number"
msgstr "Telefoonnummer" msgstr "Telefoonnummer"
#: models.py:230 #: models.py:231
msgid "Enter a phone number so Thalia may reach you" msgid "Enter a phone number so Thalia may reach you"
msgstr "Voer een telefoonnummer in zodat Thalia je kan bereiken" 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" msgid "Please enter a valid phone number"
msgstr "Voer svp een geldig telefoonnummer in" msgstr "Voer svp een geldig telefoonnummer in"
#: models.py:243 #: models.py:244
msgid "Emergency contact name" msgid "Emergency contact name"
msgstr "Contact voor noodgevallen" msgstr "Contact voor noodgevallen"
#: models.py:244 #: models.py:245
msgid "Who should we contact in case of emergencies" msgid "Who should we contact in case of emergencies"
msgstr "Wie Thalia moet bereiken in bij noodgevallen" msgstr "Wie Thalia moet bereiken in bij noodgevallen"
#: models.py:251 #: models.py:252
msgid "Emergency contact phone number" msgid "Emergency contact phone number"
msgstr "Telefoonnummer noodcontact" msgstr "Telefoonnummer noodcontact"
#: models.py:252 #: models.py:253
msgid "The phone number for the emergency contact" msgid "The phone number for the emergency contact"
msgstr "Het telefoonummer van de noodcontact" msgstr "Het telefoonummer van de noodcontact"
#: models.py:264 templates/members/profile.html:52 #: models.py:265 templates/members/profile.html:52
msgid "Birthday" msgid "Birthday"
msgstr "Verjaardag" msgstr "Verjaardag"
#: models.py:269 #: models.py:270
msgid "Display birthday" msgid "Display birthday"
msgstr "Laat verjaardag zien" msgstr "Laat verjaardag zien"
#: models.py:271 #: models.py:272
msgid "" msgid ""
"Show your birthday to other members on your profile page and in the birthday " "Show your birthday to other members on your profile page and in the birthday "
"calendar" "calendar"
...@@ -206,107 +218,107 @@ msgstr "" ...@@ -206,107 +218,107 @@ msgstr ""
"Toon je verjaardag aan andere leden op je profielpagina en in de " "Toon je verjaardag aan andere leden op je profielpagina en in de "
"verjaardagskalender" "verjaardagskalender"
#: models.py:278 templates/members/profile.html:48 #: models.py:279 templates/members/profile.html:48
msgid "Website" msgid "Website"
msgstr "Website" msgstr "Website"
#: models.py:279 #: models.py:280
msgid "Website to display on your profile page" msgid "Website to display on your profile page"
msgstr "Website om op je profiel te linken" msgstr "Website om op je profiel te linken"
#: models.py:285 #: models.py:286
msgid "Profile text" msgid "Profile text"
msgstr "Profieltekst" msgstr "Profieltekst"
#: models.py:286 #: models.py:287
msgid "Text to display on your profile" msgid "Text to display on your profile"
msgstr "Tekst om te laten zien op je profielpagina" msgstr "Tekst om te laten zien op je profielpagina"
#: models.py:294 #: models.py:295
msgid "Initials" msgid "Initials"
msgstr "Initialen" msgstr "Initialen"
#: models.py:301 #: models.py:302
msgid "Nickname" msgid "Nickname"
msgstr "Bijnaam" msgstr "Bijnaam"
#: models.py:308 #: models.py:309
msgid "How to display name" msgid "How to display name"
msgstr "Weergave naam" msgstr "Weergave naam"
#: models.py:309 #: models.py:310
msgid "Show full name" msgid "Show full name"
msgstr "Volledige naam" msgstr "Volledige naam"
#: models.py:310 #: models.py:311
msgid "Show only nickname"