Browse Source

User CP change e-mail or password page.

Ralfp 12 years ago
parent
commit
44baafeff6

+ 1 - 1
misago/activation/views.py

@@ -40,7 +40,7 @@ def form(request):
                             'users/activation/resend',
                             _("Account Activation"),
                             )
-            return redirect_message(request, Message(_("%(username)s, e-mail containing new activation link has been sent to %{emaik}s.") % {'username': user.username, 'email': user.email}), 'success')
+            return redirect_message(request, Message(_("%(username)s, e-mail containing new activation link has been sent to %(email)s.") % {'username': user.username, 'email': user.email}), 'success')
         else:
             message = Message(form.non_field_errors()[0], 'error')
     else:

+ 1 - 1
misago/authn/decorators.py

@@ -5,7 +5,7 @@ def block_authenticated(f):
     def decorator(*args, **kwargs):
         request = args[0]
         if not request.firewall.admin and request.user.is_authenticated():
-            return error403(request, _("%{username}s, this page is not available to signed in users.") % {'username': request.user.username})
+            return error403(request, _("%(username)s, this page is not available to signed in users.") % {'username': request.user.username})
         return f(*args, **kwargs)
     return decorator
 

+ 0 - 0
misago/authn/models.py


+ 1 - 1
misago/resetpswd/urls.py

@@ -2,5 +2,5 @@ from django.conf.urls import patterns, url
 
 urlpatterns = patterns('misago.resetpswd.views',
     url(r'^$', 'form', name="forgot_password"),
-    url(r'^(?P<username>[a-z0-9]+)-(?P<user>\d+)/(?P<token>[a-z0-9]+)/$', 'reset', name="reset_password"),
+    url(r'^(?P<username>[a-z0-9]+)-(?P<user>\d+)/(?P<token>[a-zA-Z0-9]+)/$', 'reset', name="reset_password"),
 )

+ 2 - 2
misago/resetpswd/views.py

@@ -39,7 +39,7 @@ def form(request):
                             _("Confirm New Password Request")
                             )
             
-            return redirect_message(request, Message(_("%(username)s, new password request confirmation has been sent to %{email}s.") % {'username': user.username, 'email': user.email}), 'info')
+            return redirect_message(request, Message(_("%(username)s, new password request confirmation has been sent to %(email)s.") % {'username': user.username, 'email': user.email}), 'info')
         else:
             message = Message(form.non_field_errors()[0], 'error')
     else:
@@ -87,6 +87,6 @@ def reset(request, username="", user="0", token=""):
                         {'password': new_password}
                         )
         
-        return redirect_message(request, Message(_("%(username)s, your password has been changed with new one that was sent to %{email}s.") % {'username': user.username, 'email': user.email}), 'success')
+        return redirect_message(request, Message(_("%(username)s, your password has been changed with new one that was sent to %(email)s.") % {'username': user.username, 'email': user.email}), 'success')
     except User.DoesNotExist:
         return error404(request)

+ 2 - 2
misago/sessions/models.py

@@ -3,7 +3,7 @@ from django.db import models
 class Session(models.Model):
     id = models.CharField(max_length=42, primary_key=True)
     data = models.TextField(db_column="session_data")
-    user = models.ForeignKey('users.User', related_name='+', null=True, on_delete=models.SET_NULL)
+    user = models.ForeignKey('users.User', related_name='sessions', null=True, on_delete=models.SET_NULL)
     crawler = models.CharField(max_length=255, blank=True, null=True)
     ip = models.GenericIPAddressField()
     agent = models.CharField(max_length=255)
@@ -16,6 +16,6 @@ class Session(models.Model):
 
 class Token(models.Model):
     id = models.CharField(max_length=42, primary_key=True)
-    user = models.ForeignKey('users.User', related_name='+')
+    user = models.ForeignKey('users.User', related_name='signin_tokens')
     created = models.DateTimeField()
     accessed = models.DateTimeField()

+ 2 - 0
misago/sessions/sessions.py

@@ -155,6 +155,8 @@ class SessionHuman(SessionMisago):
             except AuthException as e:
                 # Autolog failed
                 self.create(request)
+        self.id = self._session_rk.id        
+        
         # Make cookie live longer
         if request.firewall.admin:
             request.cookie_jar.set('ASID', self._session_rk.id)

+ 52 - 0
misago/usercp/credentials/forms.py

@@ -0,0 +1,52 @@
+import hashlib
+from django import forms
+from django.core.exceptions import ValidationError
+from django.utils.translation import ugettext_lazy as _
+from misago.forms import Form
+from misago.users.models import User
+from misago.users.validators import validate_password, validate_email
+
+class CredentialsChangeForm(Form):
+    new_email = forms.EmailField(max_length=255,required=False)
+    new_password = forms.CharField(max_length=255,widget=forms.PasswordInput,required=False)
+    current_password = forms.CharField(max_length=255,widget=forms.PasswordInput)
+    
+    layout = [
+              (
+               None,
+               [
+                ('new_email', {'label': _('New E-mail'), 'help_text': _("Enter new e-mail address or leave this field empty if you want only to change your password.")}),
+                ('new_password', {'label': _('New Password'), 'help_text': _("Enter new password or leave this empty if you only want to change your e-mail address.")}),
+                ('current_password', {'label': _('Current Password'), 'help_text': _("Confirm changes by entering new password.")})
+                ]
+               ),
+              ]
+        
+    def clean_new_email(self):
+        if self.cleaned_data['new_email']:
+            new_hash = hashlib.md5(self.cleaned_data['new_email'].lower()).hexdigest()
+            if new_hash == self.request.user.email_hash:
+                raise ValidationError(_("New e-mail is same as your current e-mail."))
+            try:
+                User.objects.get(email_hash=new_hash)
+                raise ValidationError(_("New e-mail address is already in use by other member."))
+            except User.DoesNotExist:
+                pass
+            validate_email(self.cleaned_data['new_email'])
+        return self.cleaned_data['new_email'].lower()
+        
+    def clean_new_password(self):
+        if self.cleaned_data['new_password']:
+            validate_password(self.cleaned_data['new_password'])
+        return self.cleaned_data['new_password']
+        
+    def clean_current_password(self):
+        if not self.request.user.check_password(self.cleaned_data['current_password']):
+            raise ValidationError(_("You have entered wrong password."))
+        return ''
+        
+    def clean(self):
+        cleaned_data = super(CredentialsChangeForm, self).clean()
+        if not cleaned_data['new_email'] and not cleaned_data['new_password']:
+            raise ValidationError(_("You have to enter either new e-mail address or new password."))
+        return cleaned_data

+ 1 - 0
misago/usercp/credentials/urls.py

@@ -2,4 +2,5 @@ from django.conf.urls import patterns, url
 
 urlpatterns = patterns('misago.usercp.credentials.views',
     url(r'^credentials/$', 'credentials', name="usercp_credentials"),
+    url(r'^credentials/activate/(?P<token>[a-zA-Z0-9]+)/$', 'activate', name="usercp_credentials_activate"),
 )

+ 65 - 1
misago/usercp/credentials/views.py

@@ -1,9 +1,73 @@
+from django.core.exceptions import ValidationError
+from django.core.urlresolvers import reverse
+from django.shortcuts import redirect
+from django.utils.translation import ugettext as _
 from misago.authn.decorators import block_guest
+from misago.forms import FormLayout
+from misago.messages import Message
 from misago.usercp.template import RequestContext
+from misago.usercp.credentials.forms import CredentialsChangeForm
+from misago.views import error404
+from misago.utils import get_random_string
 
 @block_guest
 def credentials(request):
+    message = request.messages.get_message('usercp_credentials')
+    if request.method == 'POST':
+        form = CredentialsChangeForm(request.POST, request=request)
+        if form.is_valid():
+            token = get_random_string(12)
+            request.user.email_user(
+                                    request,
+                                    'users/new_credentials',
+                                    _("Activate new Sign-In Credentials"),
+                                    {'token': token}
+                                    )
+            request.session['new_credentials'] = {
+                                                  'token': token,
+                                                  'email_hash': request.user.email_hash,
+                                                  'new_email': form.cleaned_data['new_email'],
+                                                  'new_password': form.cleaned_data['new_password'],
+                                                  }
+            if form.cleaned_data['new_email']:
+                request.user.email = form.cleaned_data['new_email']
+                request.messages.set_flash(Message(_("We have sent e-mail message to your new e-mail address with link you have to click to confirm change of your sign-in credentials. This link will be valid only for duration of this session, do not sign out until you confirm change!")), 'success', 'usercp_credentials')
+            else:
+                request.messages.set_flash(Message(_("We have sent e-mail message to your e-mail address with link you have to click to confirm change of your sign-in credentials. This link will be valid only for duration of this session, do not sign out until you confirm change!")), 'success', 'usercp_credentials')
+            return redirect(reverse('usercp_credentials'))
+        message = Message(form.non_field_errors()[0], 'error')
+    else:
+        form = CredentialsChangeForm(request=request)
+        
     return request.theme.render_to_response('usercp/credentials.html',
                                             context_instance=RequestContext(request, {
+                                              'message': message,
+                                              'form': FormLayout(form),
                                               'tab': 'credentials',
-                                             }));
+                                             }));
+
+
+@block_guest
+def activate(request, token):
+    new_credentials = request.session.get('new_credentials')
+    if not new_credentials or new_credentials['token'] != token:
+        return error404(request)
+    
+    if new_credentials['new_email']:
+        request.user.set_email(new_credentials['new_email'])
+    if new_credentials['new_password']:
+        request.user.set_password(new_credentials['new_password'])
+        
+    try:
+        request.user.full_clean()
+        request.user.save(force_update=True)
+        request.user.sessions.exclude(id=request.session.id).delete()
+        request.user.signin_tokens.all().delete()
+        request.messages.set_flash(Message(_("%(username)s, your Sign-In credentials have been changed.") % {'username': request.user.username}), 'success', 'security')
+        request.session.sign_out(request)
+        del request.session['new_credentials']
+        return redirect(reverse('sign_in'))
+    except ValidationError:
+        request.messages.set_flash(Message(_("Your new credentials have been invalidated. Please try again.")), 'error', 'usercp_credentials')
+        return redirect(reverse('usercp_credentials'))
+    

+ 3 - 2
misago/usercp/username/views.py

@@ -30,10 +30,11 @@ def username(request):
         org_username = request.user.username
         form = UsernameChangeForm(request.POST, request=request)
         if form.is_valid():
-            request.user.username = form.cleaned_data['username']
+            request.user.set_username(form.cleaned_data['username'])
             request.user.save(force_update=True)
-            request.messages.set_flash(Message(_("Your username has been changed")), 'success', 'usercp_username')
             request.user.namechanges.create(date=timezone.now(),old_username=org_username)
+            
+            request.messages.set_flash(Message(_("Your username has been changed.")), 'success', 'usercp_username')
             return redirect(reverse('usercp_username'))
         message = Message(form.non_field_errors()[0], 'error')
     else:

+ 15 - 0
templates/_email/users/new_credentials_html.html

@@ -0,0 +1,15 @@
+{% extends "_email/base_html.html" %}
+{% load i18n %}
+{% load url from future %}
+
+{% block title %}{% trans board_name=settings.board_name %}Activate new Sign-In Credentials{% endtrans %}{% endblock %}
+
+{% block content %}
+<p {{ style_p|safe }}>{% trans username=user.username %}{{ username }}, you are receiving this message because you have changed your acount's sign-in credentials.{% endtrans %}</p>
+<p {{ style_p|safe }}>{% trans %}To confirm that you want to change your account's sign-in credentials with new ones click the link below:{% endtrans %}</p>
+<a href="{{ board_address }}{% url 'usercp_credentials_activate' token=token %}" {{ style_button|safe }}>{% trans %}Activate New Credentials{% endtrans %}</a>
+
+<p {{ style_p|safe }}>{% trans %}If the above link is not clickable, copy and paste this link into your web browser's address bar:{% endtrans %}</p>
+<a href="{{ board_address }}{% url 'usercp_credentials_activate' token=token %}" {{ style_link|safe }}>{{ board_address }}{% url 'usercp_credentials_activate' token=token %}</a>
+
+{% endblock %}

+ 12 - 0
templates/_email/users/new_credentials_plain.html

@@ -0,0 +1,12 @@
+{% extends "_email/base_plain.html" %}
+{% load i18n %}
+{% load url from future %}
+
+{% block title %}{% trans board_name=settings.board_name %}Activate new Sign-In Credentials{% endtrans %}{% endblock %}
+
+{% block content %}
+{% trans username=user.username %}{{ username }}, you are receiving this message because you have changed your acount's sign-in credentials.{% endtrans %}
+
+{% trans %}To confirm that you want to change your account's sign-in credentials with new ones click the link below:{% endtrans %}
+{{ board_address }}{% url 'usercp_credentials_activate' token=token %}
+{% endblock %}

+ 1 - 1
templates/sora/signin.html

@@ -13,7 +13,7 @@
 <div class="row">
   <div class="span6">
     <div class="well">
-	  {% if message %}<div class="alert alert-form alert-error">
+	  {% if message %}<div class="alert alert-form alert-{{ message.type }}">
   	    {{ macros.draw_message_icon(message) }}
 	    <p><strong>{{ message.message }}</strong></p>{% if bad_password %}
 	    <p class="protip"><a href="{% url 'forgot_password' %}">{% trans %}Click here if you forgot your sign in credentials.{% endtrans %}</a></p>{% endif %}{% if not_active %}

+ 0 - 1
templates/sora/usercp/blocked.html

@@ -6,6 +6,5 @@
 {% block title %}{{ macros.page_title(title=_('Blocked Members')) }}{% endblock %}
 
 {% block action %}
-{{ super() }}
 <h2>{% trans %}Blocked Members List{% endtrans %}</h2>
 {% endblock %}

+ 8 - 1
templates/sora/usercp/credentials.html

@@ -1,11 +1,18 @@
 {% extends "sora/usercp/layout.html" %}
 {% load i18n %}
 {% load url from future %}
+{% import "_forms.html" as form_theme with context %}
 {% import "sora/macros.html" as macros with context %}
 
 {% block title %}{{ macros.page_title(title=_('Change your Sign-In Credentials')) }}{% endblock %}
 
 {% block action %}
-{{ super() }}
 <h2>{% trans %}Change Sign-In Credentials{% endtrans %}</h2>
+{% if message %}{{ macros.draw_message(message, 'alert-form') }}{% endif %}
+<form action="{% url 'usercp_credentials' %}" method="post">
+  {{ form_theme.form_widget(form, width=9) }}
+  <div class="form-actions">
+  	<button name="save" type="submit" class="btn btn-primary">{% trans %}Change Credentials{% endtrans %}</button>
+  </div>
+</form>
 {% endblock %}

+ 0 - 1
templates/sora/usercp/options.html

@@ -7,7 +7,6 @@
 {% block title %}{{ macros.page_title(title=_('Change Forum Options')) }}{% endblock %}
 
 {% block action %}
-{{ super() }}
 <h2>{% trans %}Change Forum Options{% endtrans %}</h2>
 {% if message %}{{ macros.draw_message(message, 'alert-form') }}{% endif %}
 <form action="{% url 'usercp' %}" method="post">

+ 0 - 1
templates/sora/usercp/signature.html

@@ -6,6 +6,5 @@
 {% block title %}{{ macros.page_title(title=_('Edit your Signature')) }}{% endblock %}
 
 {% block action %}
-{{ super() }}
 <h2>{% trans %}Edit your Signature{% endtrans %}</h2>
 {% endblock %}

+ 0 - 1
templates/sora/usercp/signature_banned.html

@@ -6,7 +6,6 @@
 {% block title %}{{ macros.page_title(title=_('Edit your Signature')) }}{% endblock %}
 
 {% block action %}
-{{ super() }}
 <h2>{% trans %}Edit your Signature{% endtrans %}</h2>
 {% if user.signature_ban_reason_user %}
 <p class="lead">{% trans username=user.username %}{{ username }}, your ability to edit your signature has been removed for following reason:{% endtrans %}</p>

+ 0 - 1
templates/sora/usercp/username.html

@@ -7,7 +7,6 @@
 {% block title %}{{ macros.page_title(title=_('Change your Username')) }}{% endblock %}
 
 {% block action %}
-{{ super() }}
 <h2>{% trans %}Change your Username{% endtrans %}</h2>
 {% if message %}{{ macros.draw_message(message, 'alert-form') }}{% endif %}
 <p class="lead">{% if changes_left > 0 -%}