source: sapic/users/views.py @ 67f406d

erwinexplicacion_situacionalgestion_usuariostaller_django
Last change on this file since 67f406d was 67f406d, checked in by lhernandez <lhernandez@…>, 7 años ago

Cambios menores a los templates de usurs

  • Propiedad mode establecida a 100644
File size: 25.0 KB
Línea 
1# -*- coding: utf-8 -*-
2"""!
3Vista que controla los procesos de los usuarios
4
5@author Ing. Leonel P. Hernandez M. (lhernandez at cenditel.gob.ve)
6@copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
7@date 29-05-2017
8@version 1.0.0
9"""
10
11from django.shortcuts import render
12from django import forms
13from django.db.models import Q
14from django.conf import settings
15from django.contrib import messages
16from django.contrib.auth import (
17    authenticate, logout, login
18)
19
20from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION
21from django.contrib.auth.models import (
22    Group, Permission, User
23)
24from django.contrib.auth.views import redirect_to_login
25from django.contrib.auth.mixins import (
26    LoginRequiredMixin
27)
28from django.contrib.contenttypes.models import ContentType
29from django.contrib.messages.views import SuccessMessageMixin
30from django.contrib.auth.views import PasswordChangeView
31from django.core.exceptions import PermissionDenied
32from django.core.urlresolvers import (
33    reverse_lazy, reverse
34)
35from django.core.validators import validate_email
36
37from django.shortcuts import (
38    render, redirect, get_object_or_404
39)
40from django.views.generic import (
41    TemplateView, ListView
42)
43from django.views.generic.base import RedirectView
44from django.views.generic.edit import (
45    FormView, UpdateView
46)
47from multi_form_view import MultiModelFormView
48
49from utils.views import LoginRequeridoPerAuth
50
51from .forms import *
52
53from organizaciones.models import VoceroComite
54
55from .models import (
56    UserProfile, UserProfileVocero
57    )
58
59
60
61
62class LoginView(FormView):
63    """!
64    Muestra el formulario de ingreso a la aplicación
65
66    @author Ing. Leonel P. Hernandez M. (lhernandez at cenditel.gob.ve)
67    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
68    @date 09-01-2017
69    @version 1.0.0
70    """
71    form_class = FormularioLogin
72    template_name = 'users.login.html'
73    success_url = '/inicio/'
74
75    def form_valid(self, form):
76        """
77        Valida el formulario de logeo
78        @return: Dirige a la pantalla inicial de la plataforma
79        """
80        usuario = form.cleaned_data['usuario']
81        contrasena = form.cleaned_data['contrasena']
82
83        try:
84            validate_email(usuario)
85            try:
86                usuario = User.objects.get(email=usuario).username
87                valid_email = True
88            except:
89                messages.error(self.request, 'No existe este correo: %s \
90                                              asociado a una cuenta' % (usuario))
91        except:
92            valid_email = False
93
94        usuario = authenticate(username=usuario, password=contrasena)
95        if usuario is not None:
96            login(self.request, usuario)
97            self.request.session['permisos'] = list(usuario.get_all_permissions())
98            try:
99                grupos = usuario.groups.all()
100                grupo = []
101                if len(grupos) > 1:
102                    for g in grupos:
103                        grupo += str(g),
104                else:
105                    grupo = str(usuario.groups.get())
106            except:
107                grupo = "No pertenece a un grupo"
108
109            self.request.session['grupos'] = grupo
110
111            if self.request.POST.get('remember_me') is not None:
112                # Session expira a los dos meses si no se deslogea
113                self.request.session.set_expiry(1209600)
114            messages.info(self.request, 'Bienvenido %s has ingresado a el \
115                                         SAPIC con el usuario %s \
116                                         ' % (usuario.first_name,
117                                              usuario.username))
118        else:
119            user = User.objects.filter(username=form.cleaned_data['usuario'])
120            if user:
121                user = user.get()
122                if not user.is_active:
123                    self.success_url = reverse_lazy('users:login')
124                    messages.error(self.request, 'La cuenta esta inactiva \
125                                                consulte con un adminitrador')
126                else:
127                    self.success_url = reverse_lazy('users:login')
128                    messages.warning(self.request, 'Verifique su nombre y contraseña\
129                                                 y vuelve a intertar')
130
131        return super(LoginView, self).form_valid(form)
132
133class PasswordChangeView(LoginRequeridoPerAuth, SuccessMessageMixin,
134                         PasswordChangeView):
135    """!
136    Cambiar la Contraseña
137
138    @author Ing. Leonel P. Hernandez M. (lhernandez at cenditel.gob.ve)
139    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
140    @date 20-07-2017
141    @version 1.0.0
142    """
143    template_name = 'users.change.pass.html'
144    form_class = PasswordChangeForm
145    success_url = '/inicio/'
146    success_message = "Cambio de contraseña con exito"
147    group_required = [u"Administradores", u"Voceros", u"Integrantes"]
148
149
150class LogOutView(RedirectView):
151    """!
152    Salir de la apliacion
153
154    @author Ing. Leonel P. Hernandez M. (lhernandez at cenditel.gob.ve)
155    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
156    @date 09-01-2017
157    @version 1.0.0
158    """
159    permanent = False
160    query_string = True
161
162    def get_redirect_url(self):
163        """!
164        Dirige a la pantalla del login
165        @return: A la url del login
166        """
167        logout(self.request)
168        return reverse_lazy('users:login')
169
170
171class OthersOptionsView(LoginRequeridoPerAuth, TemplateView):
172    """!
173    Clase que muestra el templates de las opciones del usuario
174
175    @author Ing. Leonel P. Hernandez M. (lhernandez at cenditel.gob.ve)
176    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
177    @date 30-005-2017
178    @version 1.0.0
179    """
180    template_name = "users.other.options.html"
181    group_required = [u"Administradores", u"Voceros", u"Integrantes"]
182
183
184
185class RegisterView(LoginRequeridoPerAuth, MultiModelFormView):
186    """!
187    Muestra el formulario de registro de usuarios
188
189    @author Ing. Leonel P. Hernandez M. (lhernandez at cenditel.gob.ve)
190    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
191    @date 09-01-2017
192    @version 1.0.0
193    """
194    template_name = "users.register.html"
195    form_classes = {
196      'user': FormularioAdminRegistro,
197      'user_perfil': FormularioAdminRegPerfil,
198    }
199    success_url = reverse_lazy('utils:inicio')
200    model = Group
201    model_permi = Permission
202    group_required = [u"Administradores"]
203    record_id=None
204
205    def get_context_data(self, **kwargs):
206        """
207        Carga el formulario en la vista,para registrar usuarios
208        @return: El contexto con los objectos para la vista
209        """
210        return super(RegisterView, self).get_context_data(**kwargs)
211
212    def forms_valid(self, forms, **kwargs):
213        """
214        Valida el formulario de registro del perfil de usuario
215        @return: Dirige con un mensaje de exito a el home
216        """
217        nuevo_usuario = forms['user'].save()
218        nuevo_perfil = forms['user_perfil'].save(commit=False)
219        nuevo_perfil.fk_user = nuevo_usuario
220        nuevo_perfil.save()
221        usuario = forms['user'].cleaned_data['username']
222        grupos = forms['user'].cleaned_data['groups']
223        for group in grupos:
224            # Agrega a el usuario al(los) grupo(s) seleccionado(s)
225            nuevo_usuario.groups.add(group.pk)
226        model_user = ContentType.objects.get_for_model(User).pk
227        LogEntry.objects.log_action(
228            user_id=self.request.user.id,
229            content_type_id=model_user,
230            object_id=nuevo_usuario.id,
231            object_repr=str(nuevo_usuario.username),
232            action_flag=ADDITION)
233        messages.success(self.request, "Usuario %s creado con exito\
234                                       " % (str(usuario)))
235        return super(RegisterView, self).forms_valid(forms)
236
237
238
239class DataDetailView(LoginRequeridoPerAuth, ListView):
240    """!
241    Consultar los datos basicos del usuario
242    @author Ing. Leonel P. Hernandez M. (lhernandez at cenditel.gob.ve)
243    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
244    @date 21-07-2017
245    @version 1.0.0
246    """
247    template_name = 'users.data.detail.html'
248    model = UserProfileVocero
249    group_required = [u"Voceros"]
250
251    def dispatch(self, request, *args, **kwargs):
252        if int(request.user.pk) != int(self.kwargs.get('pk', None)):
253            return redirect('utils:403error')
254        return super(DataDetailView, self).dispatch(request, *args, **kwargs)
255
256    def get_context_data(self, **kwargs):
257        """
258        Carga el formulario en la vista,para registrar usuarios
259        @return: El contexto con los objectos para la vista
260        """
261        context = super(DataDetailView, self).get_context_data(**kwargs)
262        self.record_id = self.kwargs.get('pk', None)
263        try:
264            record = self.model.objects.select_related().get(fk_user=self.record_id)
265        except User.DoesNotExist:
266            record = None
267        if record.fk_vocero.fk_rol_unidad.pk == 1:
268            try:
269                comite = VoceroComite.objects.get(fk_vocero=record.fk_vocero)
270            except:
271                comite = {}
272                comite['fk_comite'] = "Este vocero no fue asignado a un comite"
273        else:
274            comite = None
275        context['upUser'] = record
276        context['comite'] = comite
277        return context
278
279
280class UpdatePerfilAdmin(LoginRequeridoPerAuth, MultiModelFormView):
281    """!
282    Actualizar el perfil del usuario
283
284    @author Ing. Leonel P. Hernandez M. (lhernandez at cenditel.gob.ve)
285    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
286    @date 31-01-2017
287    @version 1.0.0
288    """
289    model = UserProfile
290    form_classes = {
291      'user': FormularioUpdate,
292      'user_perfil': FormularioAdminRegPerfil,
293    }
294    template_name = 'users.update.perfil.html'
295    success_url = reverse_lazy('users:options')
296    group_required = [u"Administradores"]
297    record_id = None
298
299    def dispatch(self, request, *args, **kwargs):
300        if int(request.user.pk) != int(self.kwargs.get('pk', None)):
301            return redirect('utils:403error')
302        return super(UpdatePerfilAdmin, self).dispatch(request, *args, **kwargs)
303
304    def get_context_data(self, **kwargs):
305        """
306        Carga el formulario en la vista,para registrar usuarios
307        @return: El contexto con los objectos para la vista
308        """
309        context = super(UpdatePerfilAdmin, self).get_context_data(**kwargs)
310        self.record_id = self.kwargs.get('pk', None)
311        try:
312            record = self.model.objects.select_related().get(fk_user=self.record_id)
313        except User.DoesNotExist:
314            record = None
315        context['upUser'] = record
316        return context
317
318    def get_objects(self, **kwargs):
319        """
320        Carga el formulario en la vista,para actualizar el perfil del  usuario
321        @return: El contexto con los objectos para la vista
322        """
323        self.record_id = self.kwargs.get('pk', None)
324        try:
325            record = self.model.objects.select_related().get(fk_user=self.record_id)
326        except User.DoesNotExist:
327            record = None
328        return {
329          'user_perfil': record,
330          'user': record.fk_user if record else None}
331
332    def forms_valid(self, forms, **kwargs):
333        """
334        Valida el formulario de registro del perfil de usuario
335        @return: Dirige con un mensaje de exito a el home
336        """
337        self.record_id = self.kwargs.get('pk', None)
338        objeto = get_object_or_404(User, pk=self.record_id)
339        if self.record_id is not None:
340            messages.success(self.request, "Usuario %s Actualizado con exito\
341                                           " % (str(objeto.username)))
342        return super(UpdatePerfilAdmin, self).forms_valid(forms)
343
344
345class DataDetailAdminView(LoginRequeridoPerAuth, ListView):
346    """!
347    Consultar los datos basicos del usuario
348    @author Ing. Leonel P. Hernandez M. (lhernandez at cenditel.gob.ve)
349    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
350    @date 21-07-2017
351    @version 1.0.0
352    """
353    template_name = 'users.data.detail.html'
354    model = UserProfile
355    group_required = [u"Administradores"]
356
357    def dispatch(self, request, *args, **kwargs):
358        if int(request.user.pk) != int(self.kwargs.get('pk', None)):
359            return redirect('utils:403error')
360        return super(DataDetailAdminView, self).dispatch(request, *args, **kwargs)
361
362    def get_context_data(self, **kwargs):
363        """
364        Carga el formulario en la vista,para registrar usuarios
365        @return: El contexto con los objectos para la vista
366        """
367        context = super(DataDetailAdminView, self).get_context_data(**kwargs)
368        self.record_id = self.kwargs.get('pk', None)
369        try:
370            record = self.model.objects.select_related().get(fk_user=self.record_id)
371        except User.DoesNotExist:
372            record = None
373        context['upUser'] = record
374        return context
375
376    def forms_valid(self, forms, **kwargs):
377        """
378        Valida el formulario de registro del perfil de usuario
379        @return: Dirige con un mensaje de exito a el home
380        """
381        self.record_id = self.kwargs.get('pk', None)
382        objeto = get_object_or_404(User, pk=self.record_id)
383        if self.record_id is not None:
384            messages.success(self.request, "Usuario %s Actualizado con exito\
385                                           " % (str(objeto.username)))
386        return super(UpdatePerfilAdmin, self).forms_valid(forms)
387
388
389class ListUsersView(LoginRequeridoPerAuth, TemplateView):
390    """!
391    Listar usuarios de la plataforma
392
393    @author Ing. Leonel P. Hernandez M. (lhernandez at cenditel.gob.ve)
394    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
395    @date 30-05-2017
396    @version 1.0.0
397    """
398    template_name = "users.list.html"
399    model = User
400    success_url = reverse_lazy('users:lista_users')
401    group_required = [u"Administradores"]
402
403    def __init__(self):
404        super(ListUsersView, self).__init__()
405
406    def post(self, *args, **kwargs):
407        '''
408        Cambia el estado activo a el usuario
409        @return: Dirige a la tabla que muestra los usuarios de la apliacion
410        '''
411        accion = self.request.POST
412        activar = accion.get('activar', None)
413        inactivar = accion.get('inactivar', None)
414        estado = False
415
416        if activar is not None:
417            user = activar
418            estado = True
419        elif inactivar is not None:
420            user = inactivar
421            estado = False
422        else:
423            messages.error(self.request, "Esta intentando hacer \
424                                          una accion incorrecta")
425        try:
426            user_act = self.model.objects.get(pk=user)
427            user_act.is_active = estado
428            user_act.save()
429            if estado:
430                messages.success(self.request, "Se ha activado \
431                                                el usuario: %s\
432                                                " % (str(user_act)))
433            else:
434                messages.warning(self.request, "Se ha inactivado \
435                                                el usuario: %s\
436                                                " % (str(user_act)))
437        except:
438            messages.info(self.request, "El usuario no existe")
439        return redirect(self.success_url)
440
441
442class ModalsPerfil(LoginRequeridoPerAuth, MultiModelFormView):
443    """!
444    Construye el modals para la actualizacion del usuario
445
446    @author Ing. Leonel P. Hernandez M. (lhernandez at cenditel.gob.ve)
447    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
448    @date 31-01-2017
449    @version 1.0.0
450    """
451    model = UserProfile
452    form_classes = {
453      'user': FormularioAdminUpdate,
454      'user_perfil': FormularioAdminRegPerfil,
455    }
456    template_name = 'users.modals.perfil.html'
457    success_url = reverse_lazy('users:lista_users')
458    group_required = [u"Administradores"]
459    record_id = None
460
461
462    def get_context_data(self, **kwargs):
463        """
464        Carga el formulario en la vista,para registrar usuarios
465        @return: El contexto con los objectos para la vista
466        """
467        context = super(ModalsPerfil, self).get_context_data(**kwargs)
468        self.record_id = self.kwargs.get('pk', None)
469        try:
470            record = self.model.objects.select_related().get(fk_user=self.record_id)
471        except User.DoesNotExist:
472            record = None
473        context['upUser'] = record
474        return context
475
476    def get_objects(self, **kwargs):
477        """
478        Carga el formulario en la vista,para actualizar el perfil del  usuario
479        @return: El contexto con los objectos para la vista
480        """
481        self.record_id = self.kwargs.get('pk', None)
482        try:
483            record = self.model.objects.select_related().get(fk_user=self.record_id)
484        except User.DoesNotExist:
485            record = None
486        return {
487          'user_perfil': record,
488          'user': record.fk_user if record else None}
489
490    def get_success_url(self):
491        return reverse('users:lista_users')
492
493    def forms_valid(self, forms, **kwargs):
494        """
495        Valida el formulario de registro del perfil de usuario
496        @return: Dirige con un mensaje de exito a el home
497        """
498        self.record_id = self.kwargs.get('pk', None)
499        if self.record_id is not None:
500            objeto = get_object_or_404(User, pk=self.record_id)
501            messages.success(self.request, "Usuario %s Actualizado con exito\
502                                           " % (str(objeto.username)))
503        return super(ModalsPerfil, self).forms_valid(forms)
504
505
506class UpdatePerfil(LoginRequeridoPerAuth, MultiModelFormView):
507    """!
508    Actualizar el perfil del usuario
509
510    @author Ing. Leonel P. Hernandez M. (lhernandez at cenditel.gob.ve)
511    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
512    @date 31-01-2017
513    @version 1.0.0
514    """
515    model = UserProfileVocero
516    form_classes = {
517      'user': FormularioUpdate,
518      'user_perfil': FormularioRegVoceros,
519    }
520    template_name = 'users.update.perfil.html'
521    success_url = reverse_lazy('users:options')
522    group_required = [u"Voceros"]
523    record_id = None
524
525    def dispatch(self, request, *args, **kwargs):
526        if int(request.user.pk) != int(self.kwargs.get('pk', None)):
527            return redirect('utils:403error')
528        return super(UpdatePerfil, self).dispatch(request, *args, **kwargs)
529
530    def get_context_data(self, **kwargs):
531        """
532        Carga el formulario en la vista, para registrar usuarios
533        @return: El contexto con los objectos para la vista
534        """
535        context = super(UpdatePerfil, self).get_context_data(**kwargs)
536        self.record_id = self.kwargs.get('pk', None)
537        try:
538            record = self.model.objects.select_related().get(fk_user=self.record_id)
539        except User.DoesNotExist:
540            record = None
541        context['upUser'] = record
542        return context
543
544    def get_objects(self, **kwargs):
545        """
546        Carga el formulario en la vista,para actualizar el perfil del  usuario
547        @return: El contexto con los objectos para la vista
548        """
549        self.record_id = self.kwargs.get('pk', None)
550        try:
551            record = self.model.objects.select_related().get(fk_user=self.record_id)
552        except User.DoesNotExist:
553            record = None
554        return {
555          'user_perfil': record.fk_vocero,
556          'user': record.fk_user if record else None}
557
558    def forms_valid(self, forms, **kwargs):
559        """
560        Valida el formulario de registro del perfil de usuario
561        @return: Dirige con un mensaje de exito a el home
562        """
563        self.record_id = self.kwargs.get('pk', None)
564        objeto = get_object_or_404(User, pk=self.record_id)
565        if self.record_id is not None:
566            messages.success(self.request, "Usuario %s Actualizado con exito\
567                                           " % (str(objeto.username)))
568        return super(UpdatePerfil, self).forms_valid(forms)
569
570
571class RegisterVocerosView(LoginRequeridoPerAuth, MultiModelFormView):
572    """!
573    Muestra el formulario de registro de usuarios voceros
574
575    @author Ing. Leonel P. Hernandez M. (lhernandez at cenditel.gob.ve)
576    @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
577    @date 09-01-2017
578    @version 1.0.0
579    """
580    model = UserProfileVocero
581    form_classes = {
582      'user': FormularioAdminRegVoceros,
583      'user_vocero': FormularioRegVoceros,
584    }
585    template_name = 'users.register.vocero.html'
586    success_url = reverse_lazy('users:options')
587    group_required = [u"Administradores"]
588    record_id = None
589
590
591    def get_objects(self, **kwargs):
592        """
593        Carga el formulario en la vista,para actualizar el perfil del  usuario
594        @return: El contexto con los objectos para la vista
595        """
596        self.record_id = self.kwargs.get('pk', None)
597        try:
598            record = self.model.objects.select_related().get(fk_user=self.record_id)
599        except self.model.DoesNotExist:
600            record = None
601        return {
602          'user_vocero': record,
603          'user': record.fk_user if record else None}
604
605    def forms_valid(self, forms, **kwargs):
606        """
607        Valida el formulario del perfil de vocero y usuario
608        @return: Dirige con un mensaje de exito al registro de proyecto
609        """
610        # Campos para instanciar el vocero y actualizar sus campos
611        documento_identidad = forms['user_vocero'].cleaned_data['documento']
612        tipo_documento = forms['user_vocero'].cleaned_data['fk_tipo_documento']
613        organizacion_social = forms['user_vocero'].cleaned_data['organizacion']
614        comite = forms['user_vocero'].cleaned_data['comite_unidad_ejecutiva']
615
616        # Verifica si el vocero tiene registro sobre la organizacion social
617        try:
618            vocero = Vocero.objects.get(fk_org_social=organizacion_social,
619                                        fk_tipo_documento=tipo_documento,
620                                        documento_identidad=documento_identidad)
621            actualizar_vocero = self.form_classes['user_vocero'](
622                                self.request.POST,
623                                instance=vocero)
624            actualizar_vocero.save(commit=False)
625
626            # Crea el nuevo usuario a partir del formulario
627            nuevo_usuario = forms['user'].save()
628            # Agrega al grupo de voceros al nuevo usuario
629            nuevo_usuario.groups.add(Group.objects.get(pk=2))
630            # Actualiza los datos del vocero a parit de la instancia del formulario
631            vocero_actualizado = actualizar_vocero.save()
632            # Asocia el vocero con la nueva cuenta de usuario
633            asociar_voceros = self.model(fk_user=nuevo_usuario,
634                                         fk_vocero=vocero_actualizado)
635            # Si el usuario pertenece a un comite lo asocia
636            if comite is not None:
637                try:
638                    # Asocia el vocero con un comite de la unidad Ejecutiva
639                    comite_unidad = VoceroComite(fk_vocero=vocero_actualizado,
640                                                 fk_comite=comite)
641                    comite_unidad.save()
642                except:
643                    messages.warning(self.request, "Existe un problema al \
644                                                    relacionar el comite a \
645                                                    este vocero")
646            try:
647                # Crea la cuenta de usuario vocero
648                asociar_voceros.save()
649                nombre_vocero = str(vocero_actualizado.nombres) + " \
650                                " + str(vocero_actualizado.apellidos)
651                messages.success(self.request, "Se creo el usuario %s, para el \
652                                                vocero %s" % (
653                                                nuevo_usuario.username,
654                                                nombre_vocero))
655            except:
656                messages.error(self.request, "El voceros al que quieres asociar  \
657                                              a la cuenta ya existe o ya se \
658                                              encuentra asociado")
659                return redirect(self.success_url)
660
661        except:
662            messages.error(self.request, "Este Vocero %s, no se encuentra \
663                                          asociado a esta organizacion: %s" % (
664                                          documento_identidad,
665                                          organizacion_social.nombre))
666            return redirect(self.success_url)
667
668        return redirect(self.success_url)
669
670    def forms_invalid(self, forms, **kwargs):
671
672        return super(RegisterVocerosView, self).forms_invalid(forms)
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.