source: seiven/usuario/views.py

Last change on this file was 71c82f7, checked in by Ing. Roldan D. Vargas G <rvargas@…>, 7 años ago

correcciones en la modificación de datos de perfil debido a contraseña almacenada vacia

  • Propiedad mode establecida a 100644
File size: 18.3 KB
Línea 
1"""
2Sistema Estadístico Integral de Venezuela - (SEIVEN)
3
4Copyleft (@) 2015 CENDITEL nodo Mérida - https://mpv.cenditel.gob.ve/seiven
5"""
6## @namespace usuario.views
7#
8# Contiene las clases, atributos, métodos y/o funciones a implementar para las vistas del módulo de usuario
9# @author Ing. Roldan Vargas (rvargas at cenditel.gob.ve)
10# @author <a href='http://www.cenditel.gob.ve'>Centro Nacional de Desarrollo e Investigación en Tecnologías Libres
11# (CENDITEL) nodo Mérida - Venezuela</a>
12# @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
13from __future__ import unicode_literals
14
15import base64
16import hashlib
17from datetime import datetime
18
19from django.conf import settings
20from django.contrib import messages
21from django.contrib.auth import logout, login, authenticate
22from django.contrib.auth.models import User
23from django.contrib.messages.views import SuccessMessageMixin
24from django.core import urlresolvers, signing
25from django.core.urlresolvers import reverse_lazy, reverse
26from django.http import HttpResponseRedirect
27from django.shortcuts import render
28from django.template import RequestContext
29from django.views.generic import CreateView, UpdateView, ListView
30from django.utils.translation import ugettext_lazy as _
31
32from base.constant import REGISTRO_MESSAGE, UPDATE_MESSAGE, EMAIL_SUBJECT_REGISTRO, CADUCIDAD_LINK_REGISTRO
33from base.functions import enviar_correo, calcular_diferencia_fechas
34from base.models import Institucion
35from .forms import AutenticarForm, RegistroForm, OlvidoClaveForm, ModificarClaveForm, PerfilForm
36
37import logging
38
39from .models import UserProfile
40
41date_now = datetime.now()
42logger = logging.getLogger("usuario")
43
44def hash_user(user, is_new_user=False, is_reset=False):
45    """!
46    Función que permite encriptar los datos del usuario
47
48    @author Ing. Roldan Vargas (rvargas at cenditel.gob.ve)
49    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
50    @date 22-08-2016
51    @param user <b>{object}</b> Objeto que obtiene los datos del usuario
52    @param is_new_user <b>{boolean}</b> Indica si es un nuevo usuario
53    @param is_reset <b>{boolean}</b> Indica si se reinician los datos del usuario
54    @return Devuelve un enlace cifrado
55    """
56
57    if is_new_user or not user.last_login:
58        date_to_hash = user.date_joined.isoformat()
59    else:
60        date_to_hash = user.last_login.isoformat()
61
62    username = user.username
63    password = user.password
64    date_to_hash = date_to_hash + ("", "|reset")[is_reset]
65    cadena = username + "|" + password + "|" + date_to_hash
66
67    hash = hashlib.sha1(cadena.encode("utf-8")).hexdigest()
68    return base64.urlsafe_b64encode(bytes(hash, "utf-8"))
69
70def acceso(request):
71    """!
72    Funcion que gestiona el acceso al sistema
73
74    @author Ing. Roldan Vargas (rvargas at cenditel.gob.ve)
75    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
76    @date 23-04-2016
77    @param request <b>{object}</b> Objeto que obtiene la petición
78    @return Redirecciona al usuario a la pagina correspondiente en caso de que se haya autenticado o no
79    """
80    form = AutenticarForm()
81    alert = None
82
83    if request.method == "POST":
84        form = AutenticarForm(data=request.POST)
85
86        if form.is_valid():
87            username = "%s%s" % (
88                request.POST['tipo_documento_0'], request.POST['tipo_documento_1']
89            )
90            if User.objects.filter(username=username, is_active=True):
91                usuario = authenticate(username=username, password=str(request.POST['clave']))
92
93                if usuario is not None:
94                    login(request, usuario)
95                    usr = User.objects.get(username=username)
96                    usr.last_login = datetime.now()
97                    usr.save()
98                else:
99                    logger.error(str(_("Error al autenticar el usuario [%s]") % username))
100
101                logger.info(str(_("Acceso al sistema por el usuario [%s]") % username))
102                return HttpResponseRedirect(urlresolvers.reverse("inicio"))
103            else:
104                alert = str(_("Su usuario se encuentra inactivo. Intente más tarde..."))
105
106
107    return render(request, 'base.template.html', {'form': form, 'alert': alert})
108
109
110def salir(request):
111    """!
112    Funcion que gestiona la salida del sistema
113
114    @author Ing. Roldan Vargas (rvargas at cenditel.gob.ve)
115    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
116    @date 23-04-2016
117    @param request <b>{object}</b> Objeto que contiene la petición
118    @return Redirecciona al usuario a la pagina de inicio, si fue desautenticado lo envia a la pagina de acceso
119    """
120    user = request.user
121    if user.is_authenticated():
122        logout(request)
123
124        logger.info("El usuario [%s] salio del sistema" % user)
125
126    return HttpResponseRedirect(urlresolvers.reverse("inicio"))
127
128
129def olvido_clave(request):
130    """!
131    Funcion que gestiona el envío de enlace para la modificación de la contraseña
132
133    @author Ing. Roldan Vargas (rvargas at cenditel.gob.ve)
134    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
135    @date 06-05-2016
136    @param request <b>{object}</b> Objeto que obtiene la petición
137    @return Redirecciona al usuario a la pagina de acceso al sistema
138    """
139
140    form = OlvidoClaveForm()
141    alert = None
142
143    if request.method == "POST":
144        form = OlvidoClaveForm(data=request.POST)
145
146        if form.is_valid():
147            username = "%s%s" % (
148                request.POST['tipo_documento_0'], request.POST['tipo_documento_1']
149            )
150
151            correo = request.POST['correo']
152
153            usr = User.objects.get(username=username)
154
155            ## Fecha (cifrada) en la que se genero el enlace para la modificacion de contraseña
156            date_link_signed = signing.dumps("%s-%s-%s" % (date_now.year, date_now.month, date_now.day))
157
158            link = request.build_absolute_uri("%s?userid=%s&key=%s&date=%s" % (
159                urlresolvers.reverse('confirmar_modificar_clave'),
160                username, hash_user(usr, is_reset=True).decode(),
161                date_link_signed
162            ))
163
164            administrador, admin_email = '', ''
165            if settings.ADMINS:
166                administrador = settings.ADMINS[0][0]
167                admin_email = settings.ADMINS[0][1]
168
169            ## Indica si el correo electrónico fue enviado
170            enviado = enviar_correo(usr.email, 'usuario.olvido.clave.mail', EMAIL_SUBJECT_REGISTRO, {
171                'link': link, 'emailapp': settings.EMAIL_FROM, 'administrador': administrador,
172                'admin_email': admin_email
173            })
174
175            if not enviado:
176                logger.warning(
177                    str(_("Ocurrió un inconveniente al enviar el correo de recuperación de clave al usuario [%s]")
178                        % username)
179                )
180            else:
181                form = OlvidoClaveForm()
182                alert = _("Se le ha enviado, al correo electrónico indicado, la información necesaria para la "
183                          "modificación de la contraseña")
184                messages.info(request, _("Se le ha enviado, al correo electrónico indicado, la información necesaria "
185                                         "para la modificación de la contraseña"))
186
187    return render(request, 'usuario.recuperar.clave.html', {'form': form, 'alert': alert})
188
189
190def confirmar_modificar_clave(request):
191    """!
192    Función que permite confirmar el enlace enviado al usuario para la modificación de contraseña
193
194    @author Ing. Roldan Vargas (rvargas at cenditel.gob.ve)
195    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
196    @date 06-05-2016
197    @param request <b>{object}</b> Objeto que contiene la petición
198    @return Devuelve un mensje al usuario indicando el estatus de la validación del enlace
199    """
200    userid = request.GET.get('userid', None)
201    key = request.GET.get('key', None)
202    date_link_generate = request.GET.get('date', None)
203    verificado = False
204    mensaje = str(_("El usuario ha sido verificado"))
205    modificar_clave_url = None
206
207    if userid and key and date_link_generate and User.objects.filter(username=userid):
208        user = User.objects.get(username=userid)
209
210        ## Fecha (descifrada) en la que se genero el enlace para la modificacion de contraseña
211        link_date = datetime.strptime(signing.loads(date_link_generate), "%Y-%m-%d")
212
213        if calcular_diferencia_fechas(link_date) <= CADUCIDAD_LINK_REGISTRO:
214            if key.strip() == hash_user(user, is_reset=True).decode():
215                modificar_clave_url = "%s?userid=%s&key=%s" % (
216                    urlresolvers.reverse('modificar_clave'), user.username, hash_user(user, is_reset=True)
217                )
218                verificado = True
219            else:
220                mensaje = str(_("El usuario no puede ser verificado"))
221        else:
222            mensaje = str(_("El enlace utilizado expiró. Contacte al administrador del sistema."))
223
224    return render(request, 'usuario.validar.olvido.clave.html', {
225        'verificado': verificado, 'emailapp': settings.EMAIL_FROM, 'mensaje': mensaje,
226        'modificar_clave_url': modificar_clave_url
227    })
228
229
230def modificar_clave(request):
231    """!
232    Funcion que gestiona la modificación de contraseña
233
234    @author Ing. Roldan Vargas (rvargas at cenditel.gob.ve)
235    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
236    @date 06-05-2016
237    @param request <b>{object}</b> Objeto que obtiene la petición
238    @return Redirecciona al usuario a la pagina de autenticación del sistema
239    """
240    form = ModificarClaveForm()
241    username = request.GET.get('userid', None)
242
243    if request.method == "POST":
244        form = ModificarClaveForm(data=request.POST)
245
246        if form.is_valid():
247            username = username if username else request.POST['username']
248            user = User.objects.get(username=username)
249            user.set_password(request.POST['clave'])
250            user.save()
251            if UserProfile.objects.filter(user=user):
252                perfil = UserProfile.objects.get(user=user)
253                perfil.fecha_modpass = datetime.now()
254                perfil.save()
255            messages.info(request, _("Su contraseña ha sido modificada correctamente"))
256            alert = str(_("La contraseña fue modificada satisfactoriamente"))
257            logger.info(str(_("El usuario [%s] modificó su contraseña por olvido") % username))
258            form = AutenticarForm()
259            return render(request, 'base.template.html', {'form': form, 'alert': alert})
260            #return HttpResponseRedirect(urlresolvers.reverse("acceso"))
261
262    return render(request, 'usuario.modificar.clave.html', {'form': form, 'fortaleza_clave': True, 'username': username})
263
264
265def confirmar_registro(request):
266    """!
267    Función que permite confirmar el enlace enviado al usuario durante el registro
268
269    @author Ing. Roldan Vargas (rvargas at cenditel.gob.ve)
270    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
271    @date 02-05-2016
272    @param request <b>{object}</b> Objeto que contiene la petición
273    @return Devuelve un mensje al usuario indicando el estatus de la validación del enlace
274    """
275    userid = request.GET.get('userid', None)
276    key = request.GET.get('key', None)
277    verificado = False
278    mensaje = str(_("El usuario ha sido verificado"))
279    login_url = None
280
281    if userid and key and User.objects.filter(username=userid):
282        user = User.objects.get(username=userid)
283        if calcular_diferencia_fechas(user.date_joined) <= CADUCIDAD_LINK_REGISTRO:
284            if key.strip() == hash_user(user, is_new_user=True).decode():
285                if UserProfile.objects.filter(user=user, ocupacion='ES'):
286                    # Si es estudiante el sistema activa automáticamente el usuario,
287                    # en caso contrario debe esperar por la confirmación del administrador
288                    user.is_active = True
289                    user.save()
290                    user_profile = UserProfile.objects.get(user=user)
291                    user_profile.nivel_acceso = 3
292                else:
293                    mensaje = str(_("El enlace fue verificado y el administrador esta evaluando sus credenciales para "
294                                    "otorgarle un nivel de acceso al sistema"))
295                login_url = "%s?userid=%s&key=%s" % (
296                    urlresolvers.reverse('acceso'), user.username, hash_user(user, is_new_user=True)
297                )
298                verificado = True
299            else:
300                mensaje = str(_("El usuario no puede ser verificado"))
301        else:
302            mensaje = str(_("El enlace utilizado expiró. Contacte al administrador del sistema."))
303
304    return render(request, 'usuario.validar.cuenta.html', {
305        'verificado': verificado, 'emailapp': settings.EMAIL_FROM, 'mensaje': mensaje, 'login_url': login_url
306    })
307
308
309class RegistroCreate(SuccessMessageMixin, CreateView):
310    """!
311    Clase que registra usuarios en el sistema
312
313    @author Ing. Roldan Vargas (rvargas at cenditel.gob.ve)
314    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
315    @date 25-04-2016
316    @version 2.0.0
317    """
318    model = User
319    form_class = RegistroForm
320    template_name = 'usuario.registro.html'
321    success_url = reverse_lazy('acceso')
322    success_message = REGISTRO_MESSAGE
323
324    def form_valid(self, form):
325        """!
326        Metodo que valida si el formulario es valido, en cuyo caso se procede a registrar los datos del usuario
327
328        @author Ing. Roldan Vargas (rvargas at cenditel.gob.ve)
329        @copyright GNU/GPLv2
330        @date 22-08-2016
331        @param self <b>{object}</b> Objeto que instancia la clase
332        @param form <b>{object}</b> Objeto que contiene el formulario de registro
333        @return Retorna el formulario validado
334        """
335
336        self.object = form.save(commit=False)
337        self.object.username = form.cleaned_data['tipo_documento']
338        self.object.first_name = form.cleaned_data['nombre']
339        self.object.last_name = form.cleaned_data['apellido']
340        self.object.set_password(form.cleaned_data['password'])
341        self.object.email = form.cleaned_data['correo']
342        self.object.save()
343
344
345        ## Crea el perfil del usuario
346        UserProfile.objects.create(
347            tipo_documento=form.cleaned_data['tipo_documento'],
348            institucion=form.cleaned_data['institucion'],
349            ocupacion=form.cleaned_data['ocupacion'],
350            user=self.object
351        )
352        ## Asigna un enlace de verificación en el registro de usuarios
353        link = self.request.build_absolute_uri("%s?userid=%s&key=%s" % (
354            urlresolvers.reverse(confirmar_registro),
355            self.object.username, hash_user(self.object, is_new_user=True).decode()
356        ))
357
358        administrador, admin_email = '', ''
359        if settings.ADMINS:
360            administrador = settings.ADMINS[0][0]
361            admin_email = settings.ADMINS[0][1]
362
363        ## Indica si el correo electrónico fue enviado
364        enviado = enviar_correo(self.object.email, 'usuario.bienvenida.mail', EMAIL_SUBJECT_REGISTRO, {
365            'link': link, 'emailapp': settings.EMAIL_FROM, 'administrador': administrador, 'admin_email': admin_email
366        })
367
368        if not enviado:
369            logger.warning(
370                str(_("Ocurrió un inconveniente al enviar el correo de registro al usuario [%s]")
371                    % self.object.username)
372            )
373
374        return super(RegistroCreate, self).form_valid(form)
375
376
377class ModificarPerfilView(SuccessMessageMixin, UpdateView):
378    """!
379    Clase que muestra el formulario de modificación de datos del perfil de usuario
380
381    @author Ing. Roldan Vargas (rvargas at cenditel.gob.ve)
382    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
383    @date 02-12-2016
384    @version 1.0.0
385    """
386    model = User #UserProfile
387    form_class = PerfilForm
388    template_name = 'usuario.update.html'
389    success_url = reverse_lazy('inicio')
390    success_message = UPDATE_MESSAGE
391
392    def get_initial(self, **kwargs):
393        """!
394        Metodo que asigna los valores iniciales del formulario del perfil de usuario con los datos actualmente registrados
395
396        @author Ing. Roldan Vargas (rvargas at cenditel.gob.ve)
397        @copyright GNU/GPLv2
398        @date @date 02-12-2016
399        @return Retorna los valores iniciales del formulario
400        """
401        usr = User.objects.get(username=self.request.user)
402
403        return {
404            'nombre': usr.first_name, 'apellido': usr.last_name, 'correo': usr.email, 'tipo_documento': usr.username,
405            'institucion': self.request.user.profile.institucion.pk, 'ocupacion': self.request.user.profile.ocupacion,
406        }
407
408    def form_valid(self, form):
409        """!
410        Metodo que valida si el formulario es valido, en cuyo caso se procede a modificar los datos del perfil del usuario
411
412        @author Ing. Roldan Vargas (rvargas at cenditel.gob.ve)
413        @copyright GNU/GPLv2
414        @date @date 02-12-2016
415        @return Retorna el formulario validado y modifica los datos de perfil del usuario
416        """
417
418        self.object = form.save(commit=False)
419        usr = User.objects.get(username=self.object.username)
420        self.object.password = usr.password
421        if self.object.first_name != form.cleaned_data['nombre']:
422            self.object.first_name = form.cleaned_data['nombre']
423        if self.object.last_name != form.cleaned_data['apellido']:
424            self.object.last_name = form.cleaned_data['apellido']
425        if self.object.email != form.cleaned_data['correo']:
426            self.object.email = form.cleaned_data['correo']
427        if form.cleaned_data.get('password', None):
428            self.object.set_password(form.cleaned_data['password'])
429
430        self.object.save()
431
432        if UserProfile.objects.filter(user__username=str(self.object.username)):
433            perfil = UserProfile.objects.get(user__username=str(self.object.username))
434            perfil.ocupacion = form.cleaned_data['ocupacion']
435            perfil.institucion = Institucion.objects.get(nombre=form.cleaned_data['institucion'])
436            perfil.save()
437
438        messages.info(self.request, UPDATE_MESSAGE)
439
440        return HttpResponseRedirect(self.get_success_url())
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.