Commit f046ff1451e8be3c618c962de53fe91cbb11f333
1 parent
e46a0179
Exists in
master
and in
39 other branches
Adding xmpp password change form with transactions and removing unnecessary changes from user
Showing
6 changed files
with
108 additions
and
30 deletions
Show diff stats
src/accounts/forms.py
... | ... | @@ -4,6 +4,8 @@ from django import forms |
4 | 4 | from django.contrib.auth import get_user_model |
5 | 5 | from django.utils.translation import ugettext_lazy as _ |
6 | 6 | |
7 | +from conversejs.models import XMPPAccount | |
8 | + | |
7 | 9 | from super_archives.models import MailingList |
8 | 10 | from .utils.validators import validate_social_account |
9 | 11 | |
... | ... | @@ -64,3 +66,31 @@ class ListsForm(forms.Form): |
64 | 66 | required=False, |
65 | 67 | widget=forms.CheckboxSelectMultiple, |
66 | 68 | choices=LISTS_NAMES) |
69 | + | |
70 | + | |
71 | +class ChangeXMPPPasswordForm(forms.ModelForm): | |
72 | + password1 = forms.CharField(label=_("Password"), | |
73 | + widget=forms.PasswordInput) | |
74 | + password2 = forms.CharField(label=_("Password confirmation"), | |
75 | + widget=forms.PasswordInput, | |
76 | + help_text=_("Enter the same password as above, for verification.")) | |
77 | + | |
78 | + class Meta: | |
79 | + model = XMPPAccount | |
80 | + fields = ('password1', 'password2') | |
81 | + | |
82 | + def __init__(self, *args, **kwargs): | |
83 | + super(ChangeXMPPPasswordForm, self).__init__(*args, **kwargs) | |
84 | + for field_name, field in self.fields.items(): | |
85 | + # Adds form-control class to all form fields | |
86 | + field.widget.attrs.update({'class': 'form-control'}) | |
87 | + | |
88 | + def clean_password2(self): | |
89 | + password1 = self.cleaned_data.get("password1") | |
90 | + password2 = self.cleaned_data.get("password2") | |
91 | + if password1 and password2 and password1 != password2: | |
92 | + raise forms.ValidationError( | |
93 | + self.error_messages['password_mismatch'], | |
94 | + code='password_mismatch', | |
95 | + ) | |
96 | + return password2 | ... | ... |
src/accounts/models.py
... | ... | @@ -2,8 +2,7 @@ |
2 | 2 | |
3 | 3 | import urlparse |
4 | 4 | |
5 | -from django.db import models | |
6 | -from django.db.models.signals import pre_save | |
5 | +from django.db import models, DatabaseError | |
7 | 6 | from django.contrib.auth.models import AbstractUser |
8 | 7 | from django.core.urlresolvers import reverse |
9 | 8 | |
... | ... | @@ -55,27 +54,3 @@ class User(AbstractUser): |
55 | 54 | # The following workaroud allows to change email field to unique |
56 | 55 | # without having to rewrite all AbstractUser here |
57 | 56 | User._meta.get_field('email')._unique = True |
58 | - | |
59 | - | |
60 | -def password_change(sender, instance, **kwargs): | |
61 | - from conversejs.models import XMPPAccount | |
62 | - # to register an XMPPAccount for an user, do the following: | |
63 | - # xmpp.register_account('username@domain', 'user_password' | |
64 | - # 'name', 'email') | |
65 | - # the domain can be found at conversejs.conf.CONVERSEJS_AUTO_REGISTER | |
66 | - | |
67 | - try: | |
68 | - user = sender.objects.get(pk=instance.pk) | |
69 | - except sender.DoesNotExist: | |
70 | - return # should I register a xmpp account here? | |
71 | - | |
72 | - try: | |
73 | - xmpp_account = XMPPAccount.objects.get(user=instance.pk) | |
74 | - except XMPPAccount.DoesNotExist: | |
75 | - return # User's XMPP account should be created here? | |
76 | - | |
77 | - if user.password != instance.password: | |
78 | - xmpp.change_password(xmpp_account, instance.password) | |
79 | - | |
80 | - | |
81 | -pre_save.connect(password_change, sender=User) | ... | ... |
... | ... | @@ -0,0 +1,21 @@ |
1 | +{% extends "base.html" %} | |
2 | +{% load i18n %} | |
3 | + | |
4 | +{% block main-content %} | |
5 | +<form method="POST" role="form"> | |
6 | + {% csrf_token %} | |
7 | + <div class="row"> | |
8 | + <h2>{% trans "Change XMPP Client and SVN Password" %}</h2> | |
9 | + <div class="col-lg-4 col-md-4 col-sm-12 col-xs-12"> | |
10 | + {% for field in form %} | |
11 | + <div class="form-group required{% if field.errors %} alert alert-danger has-error{% endif %}"> | |
12 | + <label for="{{ field.name }}" class="control-label">{{ field.label }}</label> | |
13 | + {{ field }} | |
14 | + {{ field.errors }} | |
15 | + </div> | |
16 | + {% endfor %} | |
17 | + <button class="btn btn-primary">{% trans "Change Password" %}</button> | |
18 | + </div> | |
19 | + </div> | |
20 | +</form> | |
21 | +{% endblock %} | ... | ... |
src/accounts/templates/accounts/user_update_form.html
... | ... | @@ -178,6 +178,21 @@ $(function() { |
178 | 178 | </div> |
179 | 179 | </div> |
180 | 180 | </div> |
181 | + | |
182 | + <div class="col-lg-4 col-md-5 col-sm-12 col-xm-12"> | |
183 | + <div class="panel panel-default"> | |
184 | + <div class="panel-heading"> | |
185 | + <h3 class="panel-title">{% trans "Change SVN and XMPP Client password" %}</h3> | |
186 | + </div> | |
187 | + <div class="panel-body"> | |
188 | + <div class="form-group"> | |
189 | + {% trans "You don't need to change this password. Change it only if you really know what you are doing." %} | |
190 | + </div> | |
191 | + <a href="{% url 'change_password' %}" class="btn btn-primary pull-right">{% trans "Change Password" %}</a> | |
192 | + </div> | |
193 | + </div> | |
194 | + </div> | |
195 | + | |
181 | 196 | </div> |
182 | 197 | <div class="row"> |
183 | 198 | <div class="submit"> | ... | ... |
src/accounts/urls.py
1 | 1 | |
2 | 2 | from django.conf.urls import patterns, include, url |
3 | 3 | |
4 | -from .views import UserProfileDetailView, UserProfileUpdateView, \ | |
5 | - ManageUserSubscriptionsView | |
4 | +from .views import (UserProfileDetailView, UserProfileUpdateView, | |
5 | + ManageUserSubscriptionsView, ChangeXMPPPasswordView) | |
6 | 6 | |
7 | 7 | |
8 | 8 | urlpatterns = patterns('', |
9 | 9 | url(r'^register/$', 'accounts.views.signup', name='signup'), |
10 | 10 | |
11 | + url(r'^change-password/$', | |
12 | + ChangeXMPPPasswordView.as_view(), name='change_password'), | |
13 | + | |
11 | 14 | url(r'^(?P<username>[\w@+.-]+)/?$', |
12 | 15 | UserProfileDetailView.as_view(), name='user_profile'), |
13 | 16 | ... | ... |
src/accounts/views.py
... | ... | @@ -6,20 +6,25 @@ import datetime |
6 | 6 | from collections import OrderedDict |
7 | 7 | |
8 | 8 | from django.contrib import messages |
9 | +from django.db import transaction | |
9 | 10 | from django.db.models import Count |
10 | 11 | from django.contrib.auth import get_user_model |
11 | 12 | from django.utils.translation import ugettext as _ |
12 | -from django.shortcuts import render, redirect | |
13 | +from django.shortcuts import render, redirect, get_object_or_404 | |
13 | 14 | from django.core.urlresolvers import reverse |
14 | 15 | from django.core.exceptions import PermissionDenied |
15 | 16 | from django.views.generic import DetailView, UpdateView |
17 | +from django.utils.decorators import method_decorator | |
16 | 18 | |
19 | +from conversejs import xmpp | |
20 | +from conversejs.models import XMPPAccount | |
17 | 21 | from haystack.query import SearchQuerySet |
18 | 22 | |
19 | 23 | from super_archives.models import EmailAddress, Message |
20 | 24 | from super_archives.utils.email import send_email_lists |
21 | 25 | from search.utils import trans |
22 | -from .forms import UserCreationForm, ListsForm, UserUpdateForm | |
26 | +from .forms import (UserCreationForm, ListsForm, UserUpdateForm, | |
27 | + ChangeXMPPPasswordForm) | |
23 | 28 | from .utils import mailman |
24 | 29 | |
25 | 30 | |
... | ... | @@ -168,3 +173,32 @@ class ManageUserSubscriptionsView(UserProfileBaseMixin, DetailView): |
168 | 173 | context.update(kwargs) |
169 | 174 | |
170 | 175 | return super(ManageUserSubscriptionsView, self).get_context_data(**context) |
176 | + | |
177 | + | |
178 | +class ChangeXMPPPasswordView(UpdateView): | |
179 | + model = XMPPAccount | |
180 | + form_class = ChangeXMPPPasswordForm | |
181 | + fields = ['password', ] | |
182 | + template_name = 'accounts/change_password.html' | |
183 | + | |
184 | + @method_decorator(transaction.atomic) | |
185 | + def dispatch(self, request, *args, **kwargs): | |
186 | + return super(ChangeXMPPPasswordView, self).dispatch(request, *args, | |
187 | + **kwargs) | |
188 | + | |
189 | + def get_success_url(self): | |
190 | + return reverse('user_profile', kwargs={ | |
191 | + 'username': self.request.user.username | |
192 | + }) | |
193 | + | |
194 | + def get_object(self, queryset=None): | |
195 | + return get_object_or_404(XMPPAccount, user=self.request.user.pk) | |
196 | + | |
197 | + def form_valid(self, form): | |
198 | + self.object = form.save() | |
199 | + | |
200 | + xmpp_account = self.get_object() | |
201 | + changed = xmpp.change_password(xmpp_account, password) | |
202 | + if not changed: | |
203 | + raise Exception | |
204 | + return super(ChangeXMPPPassword, self).form_valid(form) | ... | ... |