forms.py 7.43 KB
Newer Older
1
# Standard library
2 3
from datetime import date

4 5 6 7 8
# Third-party
from social_django.models import UserSocialAuth
from social_django.utils import load_strategy

# Django
9
from django import forms
10
from django.contrib.auth.models import Group
11
from django.db.models import BLANK_CHOICE_DASH
12
from django.utils.translation import gettext_lazy as _
13

14 15 16
# Local Django
from accounts.models import CustomUser
from accounts.pipeline import get_identidad
17
from .models import Linea, ParticipanteProyecto, Programa, Proyecto, TipoParticipacion
18 19 20


class InvitacionForm(forms.ModelForm):
21
    nip = forms.IntegerField(
22
        label=_('NIP'),
23 24 25
        help_text=_(
            'Número de Identificación Personal en la Universidad de Zaragoza de la persona a invitar.'
        ),
26
    )
27 28

    def __init__(self, *args, **kwargs):
29 30
        # Override __init__ to make the "self" object have the proyecto instance
        # designated by the proyecto_id sent by the view, taken from the URL parameter.
31 32
        self.proyecto = Proyecto.objects.get(id=kwargs.pop('proyecto_id'))
        self.request = kwargs.pop('request')
33 34
        super().__init__(*args, **kwargs)

35
    def _crear_usuario(self, nip):
36
        '''Crea un registro de usuario con el nip indicado y los datos de G.I.'''
37 38 39 40 41 42 43 44

        usuario = CustomUser.objects.create_user(username=nip)
        try:
            get_identidad(load_strategy(self.request), None, usuario)
        except Exception as ex:
            # Si Gestión de Identidades devuelve un error, borramos el usuario
            # y finalizamos mostrando el mensaje de error.
            usuario.delete()
45
            raise forms.ValidationError('ERROR: ' + str(ex))
46 47

        # HACK - Indicamos que la autenticación es vía Single Sign On con SAML.
48 49 50
        usuario_social = UserSocialAuth(
            uid=f'lord:{usuario.username}', provider='saml', user=usuario
        )
51 52 53 54
        usuario_social.save()

        return usuario

55 56
    def clean(self):
        cleaned_data = super().clean()
57
        nip = cleaned_data.get('nip')
58
        # Comprobamos si el usuario ya existe en el sistema.
59
        usuario = CustomUser.objects.get_or_none(username=nip)
60 61

        # Si no existe previamente, lo creamos y actualizamos con los datos de Gestión de Identidades.
62
        if not usuario:
63
            usuario = self._crear_usuario(nip)
64

65 66 67 68 69 70 71 72
        # El usuario existe. Actualizamos sus datos con los de Gestión de Identidades.
        try:
            get_identidad(load_strategy(self.request), None, usuario)
        except Exception as ex:
            # Si Gestión de Identidades devuelve un error, y finalizamos mostrando el mensaje de error.
            raise forms.ValidationError('ERROR: ' + str(ex))

        # Si el usuario no está activo, finalizamos explicando esta circunstancia.
73
        if not usuario.is_active:
74 75 76
            raise forms.ValidationError(
                _('Usuario inactivo en el sistema de Gestión de Identidades')
            )
77 78

        # Si el usuario no tiene un email válido, finalizamos explicando esta circunstancia.
79 80 81
        if not usuario.email:
            raise forms.ValidationError(
                _(
82 83 84
                    f'No fue posible invitar al usuario «{nip}» porque no tiene '
                    'establecida ninguna dirección de correo electrónico en el sistema '
                    'de Gestión de Identidades.'
85
                )
86 87
            )

88
        cleaned_data['usuario'] = usuario
89 90 91 92
        # Si un usuario ya está vinculado al proyecto, no se le puede invitar.
        vinculados = self.proyecto.get_usuarios_vinculados()
        if usuario in vinculados:
            raise forms.ValidationError(
93 94 95 96
                _(
                    f'No puede invitar a {usuario.get_full_name()} '
                    'porque ya está vinculado a este proyecto.'
                )
97
            )
98 99
        # La participación de los estudiantes estará limitada a dos por proyecto
        # (excepto en los PIPOUZ).
100 101 102 103 104 105 106 107 108
        if (
            self.proyecto.programa.nombre_corto != 'PIPOUZ'
            and usuario.get_colectivo_principal() == 'EST'
        ):
            estudiantes = [
                vinculado
                for vinculado in vinculados
                if vinculado.get_colectivo_principal() == 'EST'
            ]
109
            if len(estudiantes) >= self.proyecto.programa.max_estudiantes:
110 111 112
                nombres_estudiantes = ', '.join(
                    list(map(lambda e: e.get_full_name(), estudiantes))
                )
113 114
                raise forms.ValidationError(
                    _(
115 116 117
                        'Ya se ha alcanzado el máximo de participación de '
                        f'{self.proyecto.programa.max_estudiantes} estudiantes '
                        f'por proyecto: {nombres_estudiantes}.'
118
                    )
119
                )
120

121 122
    def save(self, commit=True):
        invitado = super().save(commit=False)
123
        invitado.proyecto = self.proyecto
124 125
        invitado.tipo_participacion = TipoParticipacion('invitado')
        invitado.usuario = self.cleaned_data['usuario']
126
        return invitado.save()
127 128

    class Meta:
129
        fields = ['nip']
130
        model = ParticipanteProyecto
131 132 133 134 135


class ProyectoForm(forms.ModelForm):
    def clean(self):
        cleaned_data = super().clean()
136 137
        programa = cleaned_data.get('programa')
        linea = cleaned_data.get('linea')
138
        lineas_del_programa = programa.lineas.all()
139 140
        centro = cleaned_data.get('centro')
        estudio = cleaned_data.get('estudio')
141 142

        if linea and linea.programa_id != programa.id:
143 144 145
            self.add_error(
                'linea', _('La línea seleccionada no pertenece al programa seleccionado.')
            )
146 147

        if lineas_del_programa and not linea:
148
            self.add_error('linea', _('Este programa requiere seleccionar una línea.'))
149

150 151
        if programa.nombre_corto in ('PIEC', 'PRACUZ', 'PIPOUZ') and not centro:
            self.add_error('centro', _('Este programa debe estar vinculado a un centro.'))
152

153 154
        if programa.nombre_corto == 'PIET' and not estudio:
            self.add_error('estudio', _('Los PIET deben estar vinculados a un estudio.'))
155

156 157
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
158
        self.fields['programa'].widget.choices = tuple(
159
            BLANK_CHOICE_DASH
160 161 162 163 164
            + list(
                Programa.objects.filter(convocatoria_id=date.today().year)
                .values_list('id', 'nombre_corto')
                .all()
            )
165
        )
166
        self.fields['linea'].widget.choices = tuple(
167
            BLANK_CHOICE_DASH
168 169 170 171 172
            + list(
                Linea.objects.filter(programa__convocatoria_id=date.today().year)
                .values_list('id', 'nombre')
                .all()
            )
173 174
        )

175
    class Meta:
176
        fields = ['titulo', 'descripcion', 'programa', 'linea', 'centro', 'estudio']
177
        model = Proyecto
178 179 180 181 182 183 184


class EvaluadorForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['evaluador'].widget.choices = tuple(
            BLANK_CHOICE_DASH
185 186 187 188 189 190
            + [
                (u.id, u.full_name)
                for u in Group.objects.get(name="Evaluadores")
                .user_set.order_by('first_name', 'last_name', 'last_name_2')
                .all()
            ]
191 192 193 194 195
        )

    class Meta:
        fields = ('evaluador',)
        model = Proyecto
196 197 198 199 200 201


class ResolucionForm(forms.ModelForm):
    class Meta:
        fields = ('aceptacion_comision', 'ayuda_concedida', 'tipo_gasto', 'observaciones')
        model = Proyecto