Commit 1ea6cb0c0b1a8705c943a59fe28e541e15ef6e3d

Authored by Zambom
1 parent f1e1b1d3

Adding password recovering

amadeus/settings.py
... ... @@ -180,7 +180,7 @@ LOGS_URL = 'logs/'
180 180  
181 181 # E-mail
182 182 EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
183   -DEFAULT_FROM_EMAIL = 'admin@admin.com'
  183 +DEFAULT_FROM_EMAIL = 'admin@amadeus.com.br'
184 184  
185 185 # Messages
186 186 from django.contrib.messages import constants as messages_constants
... ...
amadeus/templates/recover_pass_email_template.html 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +{% extends 'base.html' %}
  2 +
  3 +{% load i18n %}
  4 +
  5 +{% block nav %}
  6 +{% endblock %}
  7 +
  8 +{% block breadcrumbs %}
  9 +{% endblock %}
  10 +
  11 +{% block sidebar %}
  12 +{% endblock sidebar %}
  13 +
  14 +{% autoescape off %}
  15 +
  16 +{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
  17 +
  18 +{% trans "Please go to the following page and choose a new password:" %}
  19 +
  20 +{% block reset_link %}
  21 + {{ domain }}{% url 'users:reset_password_confirm' uidb64=uid token=token %}
  22 + <!--This is the only change from ` django/contrib/admin/templates/registration/password_reset_subject.html`. the url name is commented out in urls.py section. The view associated with the url is going to described later in this post. -->
  23 +{% endblock %}
  24 +
  25 +{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
  26 +
  27 +{% endautoescape %}
0 28 \ No newline at end of file
... ...
users/forms.py
... ... @@ -3,12 +3,25 @@ from django import forms
3 3 from django.utils.translation import ugettext_lazy as _
4 4 from rolepermissions.shortcuts import assign_role
5 5 from django.contrib.auth import update_session_auth_hash
  6 +from django.core.validators import validate_email
  7 +from django.core.exceptions import ValidationError
6 8 from .models import User
7 9  
8 10 class Validation(forms.ModelForm):
9 11 MIN_PASS_LENGTH = 8
10 12 MAX_UPLOAD_SIZE = 2*1024*1024
11 13  
  14 + def clean_email(self):
  15 + email = self.cleaned_data.get('email', '')
  16 +
  17 + try:
  18 + validate_email( email )
  19 + return email
  20 + except ValidationError:
  21 + self._errors['email'] = [_('You must insert an email address')]
  22 +
  23 + return ValueError
  24 +
12 25 def clean_image(self):
13 26 image = self.cleaned_data.get('image', False)
14 27  
... ... @@ -170,4 +183,18 @@ class ChangePassForm(Validation):
170 183 }
171 184 widgets = {
172 185 'password': forms.PasswordInput
173   - }
174 186 \ No newline at end of file
  187 + }
  188 +
  189 +class PassResetRequest(forms.Form):
  190 + email = forms.CharField(label = _('Email'), max_length = 254)
  191 +
  192 + def clean_email(self):
  193 + email = self.cleaned_data.get('email', '')
  194 +
  195 + try:
  196 + validate_email( email )
  197 + return email
  198 + except ValidationError:
  199 + self._errors['email'] = [_('You must insert an email address')]
  200 +
  201 + return ValueError
175 202 \ No newline at end of file
... ...
users/templates/users/forgot_password.html 0 → 100644
... ... @@ -0,0 +1,84 @@
  1 +{% extends 'base.html' %}
  2 +
  3 +{% load static i18n %}
  4 +{% load widget_tweaks %}
  5 +
  6 +{% block nav %}
  7 +{% endblock %}
  8 +
  9 +{% block breadcrumbs %}
  10 +{% endblock %}
  11 +
  12 +{% block sidebar %}
  13 +{% endblock sidebar %}
  14 +
  15 +{% block content %}
  16 + <div class="row">
  17 + <div class="col-sm-7 col-sm-offset-4 col-md-6 col-md-offset-4 col-xs-8 col-xs-offset-3 col-lg-6 col-lg-offset-4 col-xl-6 col-xl-offset-4 ">
  18 + <div class="col-sm-9 col-sm-offset-2 col-md-8 col-md-offset-2 col-xs-9 col-xs-offset-2 col-lg-8 col-lg-offset-2 col-xl-8 col-xl-offset-2">
  19 + <img src="{% static 'img/amadeus.png' %}" class="img-responsive center-block logo-login " alt="logo amadeus">
  20 + </div>
  21 + </div>
  22 + </div>
  23 + <div class="row">
  24 + <div class="col-lg-8 col-lg-offset-3 col-md-8 col-md-offset-3 col-sm-9 col-sm-offset-3 col-xs-10 col-xs-offset-2">
  25 + {% if messages %}
  26 + {% for message in messages %}
  27 + <div class="alert alert-{{ message.tags }} alert-dismissible" role="alert">
  28 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  29 + <span aria-hidden="true">&times;</span>
  30 + </button>
  31 + <p>{{ message }}</p>
  32 + </div>
  33 + {% endfor %}
  34 + {% endif %}
  35 + <div class="card">
  36 + <div class="card-block">
  37 + <div class="row">
  38 + <div class="col-md-12 text-center">
  39 + <h2 style="color:#43a251"><strong> {% trans 'Forgot Password' %} </strong></h2>
  40 + <p>{% trans 'Enter your email below (the one used to access the platform) to recover your password' %}</p>
  41 + </div>
  42 + </div>
  43 +
  44 + <form id="form-reset" method="post" action="">
  45 + {% csrf_token %}
  46 + {% for field in form %}
  47 + <div class="col-md-10 col-md-offset-1">
  48 + <div class="form-group{% if form.has_error %} has-error {% endif %}">
  49 + {% if field.field.required %}
  50 + <label for="{{ field.auto_id }}" class="control-label">{{ field.label }} <span>*</span></label>
  51 + {% else %}
  52 + <label for="{{ field.auto_id }}" class="control-label">{{ field.label }}</label>
  53 + {% endif %}
  54 + {% render_field field class='form-control' %}
  55 + <span id="helpBlock" class="help-block">{{ field.help_text }}</span>
  56 + {% if field.errors %}
  57 + <div class="alert alert-danger alert-dismissible" role="alert">
  58 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  59 + <span aria-hidden="true">&times;</span>
  60 + </button>
  61 + <ul>
  62 + {% for error in field.errors %}
  63 + <li>{{ error }}</li>
  64 + {% endfor %}
  65 + </ul>
  66 + </div>
  67 + {% endif %}
  68 + </div>
  69 + </div>
  70 + {% endfor %}
  71 + </form>
  72 + <div class="row">
  73 + <div class="col-md-5 col-xs-6 col-sm-6 col-lg-5 col-lg-offset-1 col-md-offset-1 text-center">
  74 + <button type="submit" class="btn btn-success btn-raised btn-block" form="form-reset" style="position: initial;"> {% trans 'Recover' %} </button>
  75 + </div>
  76 + <div class="col-md-5 col-xs-6 col-sm-6 col-lg-5 text-center">
  77 + <a class="btn btn-default btn-raised btn-block" href="{% url 'users:login' %}" formaction="#" style="position: initial;">{% trans 'Back' %}</a>
  78 + </div>
  79 + </div>
  80 + </div>
  81 + </div>
  82 + </div>
  83 + </div>
  84 +{% endblock %}
0 85 \ No newline at end of file
... ...
users/templates/users/login.html
... ... @@ -65,7 +65,7 @@
65 65 </div>
66 66 <div class="row">
67 67 <div class="col-md-offset-1 col-md-10 text-right forgotPassword">
68   - <a href="#">{% trans 'Forgot your password?' %}</a>
  68 + <a href="{% url 'users:forgot_pass' %}">{% trans 'Forgot your password?' %}</a>
69 69 </div>
70 70 </div>
71 71 </div>
... ...
users/urls.py
... ... @@ -7,6 +7,8 @@ urlpatterns = [
7 7 url(r'^login/$', views.login, name='login'),
8 8 url(r'^logout/$', auth_views.logout, {'next_page': 'users:login'}, name='logout'),
9 9 url(r'^signup/$', views.RegisterUser.as_view(), name = 'signup'),
  10 + url(r'^forgot_password/$', views.ForgotPassword.as_view(), name = 'forgot_pass'),
  11 + url(r'^reset_password_confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$', views.ForgotPassword.as_view(), name = 'reset_password_confirm'),
10 12 url(r'^$', views.UsersListView.as_view(), name = 'manage'),
11 13 url(r'^create/$', views.CreateView.as_view(), name = 'create'),
12 14 url(r'^edit/(?P<email>[\w.%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})/$', views.UpdateView.as_view(), name='update'),
... ...
users/views.py
1   -from django.http import Http404
2 1 from django.shortcuts import get_object_or_404,redirect, render
3   -from django.db.models import Q
4 2 from django.views import generic
5 3 from django.contrib import messages
6 4 from rolepermissions.mixins import HasRoleMixin
... ... @@ -10,11 +8,17 @@ from django.core.urlresolvers import reverse, reverse_lazy
10 8 from django.utils.translation import ugettext_lazy as _
11 9 from rolepermissions.shortcuts import assign_role
12 10 from rolepermissions.verifications import has_role
13   -from itertools import chain
14   -from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
15 11  
16 12 from .models import User
17   -from .forms import RegisterUserForm, ProfileForm, UserForm, ChangePassForm
  13 +from .forms import RegisterUserForm, ProfileForm, UserForm, ChangePassForm, PassResetRequest
  14 +
  15 +#RECOVER PASS IMPORTS
  16 +from django.contrib.auth.tokens import default_token_generator
  17 +from django.core.mail import send_mail
  18 +from django.conf import settings
  19 +from django.utils.encoding import force_bytes
  20 +from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
  21 +from django.template import loader
18 22  
19 23 #API IMPORTS
20 24 from rest_framework import viewsets
... ... @@ -342,6 +346,57 @@ class RegisterUser(generic.edit.CreateView):
342 346  
343 347 return super(RegisterUser, self).form_valid(form)
344 348  
  349 +class ForgotPassword(generic.FormView):
  350 + template_name = "users/forgot_password.html"
  351 + success_url = reverse_lazy('users:login')
  352 + form_class = PassResetRequest
  353 +
  354 + def get_context_data(self, **kwargs):
  355 + context = super(ForgotPassword, self).get_context_data(**kwargs)
  356 + context['title'] = _('Forgot Password')
  357 +
  358 + return context
  359 +
  360 + def post(self, request, *args, **kwargs):
  361 + form = self.get_form()
  362 +
  363 + if form.is_valid():
  364 + email = form.cleaned_data['email']
  365 +
  366 + users = User.objects.filter(email = email)
  367 +
  368 + if users.exists():
  369 + for user in users:
  370 + c = {
  371 + 'email': user.email,
  372 + 'domain': 'amadeus.com.br', #or your domain
  373 + 'site_name': 'Amadeus',
  374 + 'uid': urlsafe_base64_encode(force_bytes(user.pk)),
  375 + 'user': user,
  376 + 'token': default_token_generator.make_token(user),
  377 + 'protocol': 'http',
  378 + }
  379 +
  380 + subject_template_name='registration/password_reset_subject.txt'
  381 + email_template_name = 'recover_pass_email_template.html'
  382 +
  383 + subject = loader.render_to_string(subject_template_name, c)
  384 + # Email subject *must not* contain newlines
  385 + subject = ''.join(subject.splitlines())
  386 + email = loader.render_to_string(email_template_name, c)
  387 +
  388 + send_mail(subject, email, settings.DEFAULT_FROM_EMAIL , [user.email], fail_silently=False)
  389 +
  390 + result = self.form_valid(form)
  391 + messages.success(request, _("An email has been sent to the informed address. Please check its inbox to continue reseting password."))
  392 +
  393 + return result
  394 +
  395 + result = self.form_invalid(form)
  396 + messages.error(request, _('No user is associated with this email address'))
  397 +
  398 + return result
  399 +
345 400 def login(request):
346 401 context = {}
347 402 context['title'] = _('Log In')
... ...