Commit f046ff1451e8be3c618c962de53fe91cbb11f333

Authored by Luan
1 parent e46a0179

Adding xmpp password change form with transactions and removing unnecessary changes from user

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)
... ...
src/accounts/templates/accounts/change_password.html 0 → 100644
... ... @@ -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)
... ...