diff options
author | Magnus Hagander | 2020-08-11 11:14:55 +0000 |
---|---|---|
committer | Magnus Hagander | 2020-08-11 12:04:24 +0000 |
commit | 952b85ea8fb018acd84c973861ba71b52209d3b1 (patch) | |
tree | 5c0303cd52f52151bc396e80829f6862f93eff99 | |
parent | 86725ca155503df9e88482fd8f8eb690c3eadc23 (diff) |
Move handling of secondary email addresses upstream
Since the upstream main website now handles secondary email addresses,
centralize the handling to there. This removes the local handling
completely, except that we store them in the database. The new
push-changes API ensures that they are kept in sync with upstream.
-rw-r--r-- | pgcommitfest/commitfest/apps.py | 11 | ||||
-rw-r--r-- | pgcommitfest/settings.py | 2 | ||||
-rw-r--r-- | pgcommitfest/urls.py | 2 | ||||
-rw-r--r-- | pgcommitfest/userprofile/forms.py | 35 | ||||
-rw-r--r-- | pgcommitfest/userprofile/migrations/0003_emails_managed_upstream.py | 36 | ||||
-rw-r--r-- | pgcommitfest/userprofile/models.py | 7 | ||||
-rw-r--r-- | pgcommitfest/userprofile/templates/extra_email_mail.txt | 7 | ||||
-rw-r--r-- | pgcommitfest/userprofile/templates/userprofileform.html | 38 | ||||
-rw-r--r-- | pgcommitfest/userprofile/util.py | 34 | ||||
-rw-r--r-- | pgcommitfest/userprofile/views.py | 89 |
10 files changed, 81 insertions, 180 deletions
diff --git a/pgcommitfest/commitfest/apps.py b/pgcommitfest/commitfest/apps.py new file mode 100644 index 0000000..e47efed --- /dev/null +++ b/pgcommitfest/commitfest/apps.py @@ -0,0 +1,11 @@ +from django.apps import AppConfig + + +class CFAppConfig(AppConfig): + name = 'pgcommitfest.commitfest' + + def ready(self): + from pgcommitfest.auth import auth_user_data_received + from pgcommitfest.userprofile.util import handle_user_data + + auth_user_data_received.connect(handle_user_data) diff --git a/pgcommitfest/settings.py b/pgcommitfest/settings.py index 3df6c05..46c6b98 100644 --- a/pgcommitfest/settings.py +++ b/pgcommitfest/settings.py @@ -123,7 +123,7 @@ INSTALLED_APPS = ( # Uncomment the next line to enable admin documentation: # 'django.contrib.admindocs', 'pgcommitfest.selectable', - 'pgcommitfest.commitfest', + 'pgcommitfest.commitfest.apps.CFAppConfig', 'pgcommitfest.mailqueue', 'pgcommitfest.userprofile', ) diff --git a/pgcommitfest/urls.py b/pgcommitfest/urls.py index ec013f4..6cdc21f 100644 --- a/pgcommitfest/urls.py +++ b/pgcommitfest/urls.py @@ -44,8 +44,6 @@ urlpatterns = [ # Account management url(r'^account/profile/$', pgcommitfest.userprofile.views.userprofile), - url(r'^account/profile/delmail/$', pgcommitfest.userprofile.views.deletemail), - url(r'^account/profile/confirm/([0-9a-f]+)/$', pgcommitfest.userprofile.views.confirmemail), # Examples: # url(r'^$', 'pgpgcommitfest.commitfest.views.home', name='home), diff --git a/pgcommitfest/userprofile/forms.py b/pgcommitfest/userprofile/forms.py index 66d68d2..35d74bd 100644 --- a/pgcommitfest/userprofile/forms.py +++ b/pgcommitfest/userprofile/forms.py @@ -1,5 +1,4 @@ from django import forms -from django.contrib.auth.models import User from .models import UserProfile, UserExtraEmail @@ -13,33 +12,11 @@ class UserProfileForm(forms.ModelForm): super(UserProfileForm, self).__init__(*args, **kwargs) self.user = user + mailhelp = "To add a new address to choose from, update your user profile on <a href=\"https://www.postgresql.org/account/profile/\">postgresql.org</a>." + self.fields['selectedemail'].empty_label = self.user.email - self.fields['selectedemail'].queryset = UserExtraEmail.objects.filter(user=self.user, confirmed=True) + self.fields['selectedemail'].queryset = UserExtraEmail.objects.filter(user=self.user) + self.fields['selectedemail'].help_text = mailhelp self.fields['notifyemail'].empty_label = self.user.email - self.fields['notifyemail'].queryset = UserExtraEmail.objects.filter(user=self.user, confirmed=True) - - -class MailForm(forms.Form): - email = forms.EmailField() - email2 = forms.EmailField(label="Repeat email") - - def clean_email(self): - email = self.cleaned_data['email'] - - if User.objects.filter(email=email).exists(): - raise forms.ValidationError("This email is already in use by another account") - - return email - - def clean_email2(self): - # If the primary email checker had an exception, the data will be gone - # from the cleaned_data structure - if 'email' not in self.cleaned_data: - return self.cleaned_data['email2'] - email1 = self.cleaned_data['email'] - email2 = self.cleaned_data['email2'] - - if email1 != email2: - raise forms.ValidationError("Email addresses don't match") - - return email2 + self.fields['notifyemail'].queryset = UserExtraEmail.objects.filter(user=self.user) + self.fields['notifyemail'].help_text = mailhelp diff --git a/pgcommitfest/userprofile/migrations/0003_emails_managed_upstream.py b/pgcommitfest/userprofile/migrations/0003_emails_managed_upstream.py new file mode 100644 index 0000000..165b6e4 --- /dev/null +++ b/pgcommitfest/userprofile/migrations/0003_emails_managed_upstream.py @@ -0,0 +1,36 @@ +# Generated by Django 2.2.11 on 2020-08-11 11:09 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('userprofile', '0002_notifications'), + ] + + operations = [ + migrations.RemoveField( + model_name='userextraemail', + name='confirmed', + ), + migrations.RemoveField( + model_name='userextraemail', + name='token', + ), + migrations.RemoveField( + model_name='userextraemail', + name='tokensent', + ), + migrations.AlterField( + model_name='userprofile', + name='notifyemail', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='notifier', to='userprofile.UserExtraEmail', verbose_name='Notifications sent to'), + ), + migrations.AlterField( + model_name='userprofile', + name='selectedemail', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='userprofile.UserExtraEmail', verbose_name='Sender email'), + ), + ] diff --git a/pgcommitfest/userprofile/models.py b/pgcommitfest/userprofile/models.py index ea1cae9..79da688 100644 --- a/pgcommitfest/userprofile/models.py +++ b/pgcommitfest/userprofile/models.py @@ -5,9 +5,6 @@ from django.contrib.auth.models import User class UserExtraEmail(models.Model): user = models.ForeignKey(User, null=False, blank=False, db_index=True, on_delete=models.CASCADE) email = models.EmailField(max_length=100, null=False, blank=False, unique=True) - confirmed = models.BooleanField(null=False, blank=False, default=False) - token = models.CharField(max_length=100, null=False, blank=True) - tokensent = models.DateTimeField(null=False, blank=False) def __str__(self): return self.email @@ -20,10 +17,10 @@ class UserExtraEmail(models.Model): class UserProfile(models.Model): user = models.OneToOneField(User, null=False, blank=False, on_delete=models.CASCADE) selectedemail = models.ForeignKey(UserExtraEmail, null=True, blank=True, - verbose_name='Sender email', on_delete=models.CASCADE) + verbose_name='Sender email', on_delete=models.SET_NULL) notifyemail = models.ForeignKey(UserExtraEmail, null=True, blank=True, verbose_name='Notifications sent to', - related_name='notifier', on_delete=models.CASCADE) + related_name='notifier', on_delete=models.SET_NULL) notify_all_author = models.BooleanField(null=False, blank=False, default=False, verbose_name="Notify on all where author") notify_all_reviewer = models.BooleanField(null=False, blank=False, default=False, verbose_name="Notify on all where reviewer") notify_all_committer = models.BooleanField(null=False, blank=False, default=False, verbose_name="Notify on all where committer") diff --git a/pgcommitfest/userprofile/templates/extra_email_mail.txt b/pgcommitfest/userprofile/templates/extra_email_mail.txt deleted file mode 100644 index 34c93cc..0000000 --- a/pgcommitfest/userprofile/templates/extra_email_mail.txt +++ /dev/null @@ -1,7 +0,0 @@ -Somebody, probably you, has registered this email address as a secondary -address for the account {{user.username}} on commitfest.postgresql.org. - -To confirm this addition, please click on the following link: - -https://commitfest.postgresql.org/account/profile/confirm/{{token}}/ - diff --git a/pgcommitfest/userprofile/templates/userprofileform.html b/pgcommitfest/userprofile/templates/userprofileform.html index da8b734..ed5e263 100644 --- a/pgcommitfest/userprofile/templates/userprofileform.html +++ b/pgcommitfest/userprofile/templates/userprofileform.html @@ -33,42 +33,4 @@ </div> </form> -<h2>Extra email addresses</h2> -<p> -The following extra email addresses are registered for your account: -</p> -<ul> -{%for e in extramails%} - <li>{{e.email}}{%if not e.confirmed%} (<i>Pending confirmation</i>){%endif%} <a href="delmail/?{{e.id}}">delete</a></li> -{%endfor%} -</ul> - -<h3>Add email</h3> -<form class="form-horizontal" method="post" action=".">{%csrf_token%} -{%if mailform.errors%} - <div class="alert">Please correct the errors below, and re-submit the form.</div> -{%endif%} -{%if mailform.non_field_errors%} - <div class="alert alert-danger">{{mailform.non_field_errors}}</div> -{%endif%} - {%for field in mailform%} - <div class="form-group"> - {{field|label_class:"control-label col-lg-1"}} - <div class="col-lg-11 controls"> - {%if field.errors %} - {%for e in field.errors%} - <div class="alert alert-danger">{{e}}</div> - {%endfor%} - {%endif%} -{{field|field_class:"form-control"}} -{%if field.help_text%}<br/>{{field.help_text|safe}}{%endif%}</div> - </div> -{%endfor%} - - <div class="form-group"> - <div class="col-lg-12"> - <div class="control"><input type="submit" class="btn btn-default" name="submit" value="Add email"></div> - </div> - </div> -</form> {%endblock%} diff --git a/pgcommitfest/userprofile/util.py b/pgcommitfest/userprofile/util.py index e08aa66..92359b7 100644 --- a/pgcommitfest/userprofile/util.py +++ b/pgcommitfest/userprofile/util.py @@ -1,21 +1,7 @@ -from Crypto.Hash import SHA256 -from Crypto import Random from email.utils import formataddr from email.header import Header -from .models import UserProfile - - -def generate_random_token(): - """ - Generate a random token of 64 characters. This token will be - generated using a strong random number, and then hex encoded to make - sure all characters are safe to put in emails and URLs. - """ - s = SHA256.new() - r = Random.new() - s.update(r.read(250)) - return s.hexdigest() +from .models import UserProfile, UserExtraEmail class UserWrapper(object): @@ -26,7 +12,7 @@ class UserWrapper(object): def email(self): try: up = UserProfile.objects.get(user=self.user) - if up.selectedemail and up.selectedemail.confirmed: + if up.selectedemail: return up.selectedemail.email else: return self.user.email @@ -38,3 +24,19 @@ class UserWrapper(object): return formataddr(( str(Header("%s %s" % (self.user.first_name, self.user.last_name), 'utf-8')), self.email)) + + +def handle_user_data(sender, **kwargs): + user = kwargs.pop('user') + userdata = kwargs.pop('userdata') + + secondary = userdata.get('secondaryemails', []) + + # Remove any email attached to this user that are not upstream. Since the foreign keys + # are set to SET_NULL, they will all revert to being the users default in this case. + UserExtraEmail.objects.filter(user=user).exclude(email__in=secondary).delete() + + # Then add back any of the ones that aren't there + current = set([e.email for e in UserExtraEmail.objects.filter(user=user)]) + for e in set(secondary).difference(current): + UserExtraEmail(user=user, email=e).save() diff --git a/pgcommitfest/userprofile/views.py b/pgcommitfest/userprofile/views.py index 577f94a..4c22bac 100644 --- a/pgcommitfest/userprofile/views.py +++ b/pgcommitfest/userprofile/views.py @@ -1,102 +1,27 @@ from django.shortcuts import render from django.http import HttpResponseRedirect -from django.template import RequestContext from django.db import transaction from django.contrib import messages from django.contrib.auth.decorators import login_required -from django.conf import settings -from datetime import datetime - -from pgcommitfest.mailqueue.util import send_template_mail - -from .models import UserProfile, UserExtraEmail -from .forms import UserProfileForm, MailForm -from .util import generate_random_token +from .models import UserProfile +from .forms import UserProfileForm @login_required @transaction.atomic def userprofile(request): (profile, created) = UserProfile.objects.get_or_create(user=request.user) - form = mailform = None if request.method == 'POST': - if request.POST['submit'] == 'Save': - form = UserProfileForm(request.user, request.POST, instance=profile) - if form.is_valid(): - form.save() - messages.add_message(request, messages.INFO, "User profile saved.") - return HttpResponseRedirect('.') - elif request.POST['submit'] == 'Add email': - mailform = MailForm(request.POST) - if mailform.is_valid(): - m = UserExtraEmail(user=request.user, - email=mailform.cleaned_data['email'], - confirmed=False, - token=generate_random_token(), - tokensent=datetime.now()) - m.save() - send_template_mail(settings.NOTIFICATION_FROM, - request.user.username, - m.email, - 'Your email address for commitfest.postgresql.org', - 'extra_email_mail.txt', - {'token': m.token, 'user': m.user}) - messages.info(request, "A confirmation token has been sent to %s" % m.email) - return HttpResponseRedirect('.') - else: - messages.error(request, "Invalid submit button pressed! Nothing saved.") + form = UserProfileForm(request.user, request.POST, instance=profile) + if form.is_valid(): + form.save() + messages.add_message(request, messages.INFO, "User profile saved.") return HttpResponseRedirect('.') - - if not form: + else: form = UserProfileForm(request.user, instance=profile) - if not mailform: - mailform = MailForm() - - extramails = UserExtraEmail.objects.filter(user=request.user) return render(request, 'userprofileform.html', { 'form': form, - 'extramails': extramails, - 'mailform': mailform, }) - - -@login_required -def deletemail(request): - try: - id = int(request.META['QUERY_STRING']) - except ValueError: - messages.error(request, "Invalid format of id in query string") - return HttpResponseRedirect('../') - - try: - e = UserExtraEmail.objects.get(user=request.user, id=id) - except UserExtraEmail.DoesNotExist: - messages.error(request, "Specified email address does not exist on this user") - return HttpResponseRedirect('../') - - messages.info(request, "Email address %s deleted." % e.email) - e.delete() - return HttpResponseRedirect('../') - - -@login_required -def confirmemail(request, tokenhash): - try: - e = UserExtraEmail.objects.get(user=request.user, token=tokenhash) - if e.confirmed: - messages.warning(request, "This email address has already been confirmed.") - else: - # Ok, it's not confirmed. So let's do that now - e.confirmed = True - e.token = '' - e.save() - messages.info(request, "Email address %s added to profile." % e.email) - except UserExtraEmail.DoesNotExist: - messages.error(request, "Token %s was not found for your user. It may be because it has already been used?" % tokenhash) - - return HttpResponseRedirect("../../") |