Fix: typo
[myslice.git] / portal / django_passresetview.py
1 # -*- coding: utf-8 -*-
2 #
3 # portal/views.py: views for the portal application
4 # This file is part of the Manifold project.
5 #
6 # Author:
7 #   Mohammed Yasin Rahman <mohammed-yasin.rahman@lip6.fr>
8 # Copyright 2014, UPMC Sorbonne Universités / LIP6
9 #
10 # This program is free software; you can redistribute it and/or modify it under
11 # the terms of the GNU General Public License as published by the Free Software
12 # Foundation; either version 3, or (at your option) any later version.
13
14 # This program is distributed in the hope that it will be useful, but WITHOUT
15 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17 # details.
18 #   
19 # You should have received a copy of the GNU General Public License along with
20 # this program; see the file COPYING.  If not, write to the Free Software
21 # Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23
24
25
26
27 """
28 View Description:
29
30 Allows a user to reset their password by generating a one-time use link that can be used to reset the password, and sending that link to the user's 
31 registered email address.
32
33 If the email address provided does not exist in the system, this view won't send an email, but the user won't receive any error message either. 
34 This prevents information leaking to potential attackers. If you want to provide an error message in this case, you can subclass PasswordResetForm 
35 and use the password_reset_form argument.
36
37 Users flagged with an unusable password - see set_unusable_password() - aren't allowed to request a password reset to prevent misuse when using an external 
38 authentication source like LDAP. Note that they won't receive any error message since this would expose their account's existence but no mail will be sent either.
39
40 More Detail: https://docs.djangoproject.com/en/dev/topics/auth/default/#topics-auth-creating-users
41 """
42
43
44
45 try:
46     from urllib.parse import urlparse, urlunparse
47 except ImportError:     # Python 2
48     from urlparse import urlparse, urlunparse
49
50 from django.conf import settings
51 from django.core.urlresolvers import reverse
52 from django.http import HttpResponseRedirect, QueryDict
53 from django.template.response import TemplateResponse
54 from django.utils.http import base36_to_int, is_safe_url
55 from django.utils.translation import ugettext as _
56 from django.shortcuts import resolve_url
57 from django.views.decorators.debug import sensitive_post_parameters
58 from django.views.decorators.cache import never_cache
59 from django.views.decorators.csrf import csrf_protect
60
61 # Avoid shadowing the login() and logout() views below.
62 from django.contrib.auth import REDIRECT_FIELD_NAME, login as auth_login, logout as auth_logout, get_user_model
63 from django.contrib.auth.decorators import login_required
64 from portal.forms import PasswordResetForm, SetPasswordForm
65 from django.contrib.auth.tokens import default_token_generator
66 from django.contrib.sites.models import get_current_site
67 from django.contrib.auth.hashers import identify_hasher
68
69 ##
70 import os.path, re
71 import json
72
73 from random                     import choice
74
75 from django.core.mail           import send_mail
76 from django.contrib             import messages
77 from django.views.generic       import View
78 from django.shortcuts           import render
79 from django.http                        import HttpResponse, HttpResponseRedirect
80
81 from unfold.loginrequired       import FreeAccessView
82 from ui.topmenu                 import topmenu_items_live
83
84 from manifoldapi.manifoldapi    import execute_admin_query
85 from manifold.core.query        import Query
86 from portal.actions             import manifold_update_user
87
88 from portal.forms               import PassResetForm
89 from portal.actions             import manifold_update_user
90
91 from theme import ThemeView
92
93 # 4 views for password reset:
94 # - password_reset sends the mail
95 # - password_reset_done shows a success message for the above
96 # - password_reset_confirm checks the link the user clicked and
97 #   prompts for a new password
98 # - password_reset_complete shows a success message for the above
99
100 @csrf_protect
101 def password_reset(request, is_admin_site=False,
102                    template_name='password_reset_form.html',
103                    email_template_name='password_reset_email.html',
104                    subject_template_name='registration/password_reset_subject.txt',
105                    password_reset_form=PasswordResetForm,
106                    token_generator=default_token_generator,
107                    post_reset_redirect=None,
108                    from_email=None,
109                    current_app=None,
110                    extra_context=None):
111     
112     themeview = ThemeView()
113     themeview.template_name = template_name
114     
115     if post_reset_redirect is None:
116         post_reset_redirect = reverse('portal.django_passresetview.password_reset_done')
117     if request.method == "POST":
118         form = password_reset_form(request.POST)
119         if form.is_valid():
120
121             ### email check in manifold DB ###
122             email = form.cleaned_data['email'].lower() # email inserted on the form
123             user_query  = Query().get('local:user').select('user_id','email')
124             user_details = execute_admin_query(request, user_query)
125             flag = 0
126             for user_detail in user_details:
127                 if user_detail['email']==email:
128                     flag = 1
129                     break
130                     
131             if flag == 0:
132                 messages.error(request, 'Sorry, this email is not registered.')
133                 return render(request, themeview.theme, {
134                     'form': form,
135                     })
136             ### end of email check in manifold  ### 
137
138             opts = {
139                 'use_https': request.is_secure(),
140                 'token_generator': token_generator,
141                 'from_email': from_email,
142                 'email_template_name': email_template_name,
143                 'subject_template_name': subject_template_name,
144                 'request': request,
145             }
146             if is_admin_site:
147                 opts = dict(opts, domain_override=request.get_host())
148             form.save(**opts)
149             return HttpResponseRedirect(post_reset_redirect)
150     else:
151         form = password_reset_form()
152     context = {
153         'form': form,
154         'theme': themeview.theme
155     }
156     if extra_context is not None:
157         context.update(extra_context)
158     return TemplateResponse(request, themeview.template, context,
159                             current_app=current_app)
160
161
162 def password_reset_done(request,
163                         template_name='password_reset_done.html',
164                         current_app=None, extra_context=None):
165     themeview = ThemeView()
166     themeview.template_name = template_name
167     context = {
168                'theme' : themeview.theme
169     }
170     if extra_context is not None:
171         context.update(extra_context)
172     return TemplateResponse(request, themeview.template, context,
173                             current_app=current_app)
174
175
176 # Doesn't need csrf_protect since no-one can guess the URL
177 @sensitive_post_parameters()
178 @never_cache
179 def password_reset_confirm(request, uidb36=None, token=None,
180                            template_name='password_reset_confirm.html',
181                            token_generator=default_token_generator,
182                            set_password_form=SetPasswordForm,
183                            post_reset_redirect=None,
184                            current_app=None, extra_context=None):
185     """
186     View that checks the hash in a password reset link and presents a
187     form for entering a new password.
188     """
189     themeview = ThemeView()
190     themeview.template_name = template_name
191     
192     UserModel = get_user_model()
193     assert uidb36 is not None and token is not None  # checked by URLconf
194     if post_reset_redirect is None:
195         post_reset_redirect = reverse('portal.django_passresetview.password_reset_complete')
196     try:
197         uid_int = base36_to_int(uidb36)
198         user = UserModel._default_manager.get(pk=uid_int)
199     except (ValueError, OverflowError, UserModel.DoesNotExist):
200         user = None
201
202     if user is not None and token_generator.check_token(user, token):
203         validlink = True
204         if request.method == 'POST':
205             form = set_password_form(user, request.POST)
206             if form.is_valid():
207
208                 ### manifold pass update ###
209                 #password = form.cleaned_data('password1')
210                 password=request.POST['new_password1']
211                 #user_query  = Query().get('local:user').select('user_id','email','password')
212                 #user_details = execute_admin_query(request, user_query)
213                 #for user_detail in user_details:
214                 #    if user_detail['email'] == user.email:
215                 #        user_detail['password'] = password
216                 #updating password in local:user
217                 user_params = { 'password': password}
218                 manifold_update_user(request,user.email,user_params)    
219                 ### end of manifold pass update ###            
220     
221     
222                 form.save()
223                 return HttpResponseRedirect(post_reset_redirect)
224         else:
225             form = set_password_form(None)
226     else:
227         validlink = False
228         form = None
229     context = {
230         'form': form,
231         'validlink': validlink,
232         'theme' : themeview.theme
233     }
234     if extra_context is not None:
235         context.update(extra_context)
236     return TemplateResponse(request, themeview.template, context,
237                             current_app=current_app)
238
239
240 def password_reset_complete(request,
241                             template_name='password_reset_complete.html',
242                             current_app=None, extra_context=None):
243     themeview = ThemeView()
244     themeview.template_name = template_name
245     context = {
246         'login_url': resolve_url(settings.LOGIN_URL),
247         'theme' : themeview.theme
248     }
249     if extra_context is not None:
250         context.update(extra_context)
251     return TemplateResponse(request, themeview.template, context,
252                             current_app=current_app)
253
254