summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMagnus Hagander2020-08-11 11:14:55 +0000
committerMagnus Hagander2020-08-11 12:04:24 +0000
commit952b85ea8fb018acd84c973861ba71b52209d3b1 (patch)
tree5c0303cd52f52151bc396e80829f6862f93eff99
parent86725ca155503df9e88482fd8f8eb690c3eadc23 (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.py11
-rw-r--r--pgcommitfest/settings.py2
-rw-r--r--pgcommitfest/urls.py2
-rw-r--r--pgcommitfest/userprofile/forms.py35
-rw-r--r--pgcommitfest/userprofile/migrations/0003_emails_managed_upstream.py36
-rw-r--r--pgcommitfest/userprofile/models.py7
-rw-r--r--pgcommitfest/userprofile/templates/extra_email_mail.txt7
-rw-r--r--pgcommitfest/userprofile/templates/userprofileform.html38
-rw-r--r--pgcommitfest/userprofile/util.py34
-rw-r--r--pgcommitfest/userprofile/views.py89
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("../../")