# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # Gestion scolarite IUT # # Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # ############################################################################## import re import requests from flask_wtf import FlaskForm from flask_wtf.file import FileField, FileAllowed, FileRequired from markupsafe import Markup from sqlalchemy import text from wtforms import ( StringField, SubmitField, TextAreaField, SelectField, HiddenField, SelectMultipleField, DateField, BooleanField, ) from wtforms.validators import ValidationError, DataRequired, Email, Optional from wtforms.widgets import ListWidget, CheckboxInput from app.entreprises.models import Entreprise, EntrepriseContact, EntreprisePreferences from app.models import Identite, Departement from app.auth.models import User CHAMP_REQUIS = "Ce champ est requis" SUBMIT_MARGE = {"style": "margin-bottom: 10px;"} def _build_string_field(label, required=True, render_kw=None): if required: return StringField( label, validators=[DataRequired(message=CHAMP_REQUIS)], render_kw=render_kw, ) else: return StringField(label, validators=[Optional()], render_kw=render_kw) class EntrepriseCreationForm(FlaskForm): siret = _build_string_field( "SIRET (*)", render_kw={"placeholder": "Numéro composé de 14 chiffres", "maxlength": "14"}, ) nom_entreprise = _build_string_field("Nom de l'entreprise (*)") adresse = _build_string_field("Adresse de l'entreprise (*)") codepostal = _build_string_field("Code postal de l'entreprise (*)") ville = _build_string_field("Ville de l'entreprise (*)") pays = _build_string_field("Pays de l'entreprise", required=False) nom_contact = _build_string_field("Nom du contact (*)") prenom_contact = _build_string_field("Prénom du contact (*)") telephone = _build_string_field("Téléphone du contact (*)", required=False) mail = StringField( "Mail du contact (*)", validators=[Optional(), Email(message="Adresse e-mail invalide")], ) poste = _build_string_field("Poste du contact", required=False) service = _build_string_field("Service du contact", required=False) submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE) def validate(self): validate = True if not FlaskForm.validate(self): validate = False if not self.telephone.data and not self.mail.data: self.telephone.errors.append( "Saisir un moyen de contact (mail ou téléphone)" ) self.mail.errors.append("Saisir un moyen de contact (mail ou téléphone)") validate = False return validate def validate_siret(self, siret): if EntreprisePreferences.get_check_siret(): siret = siret.data.strip() if re.match("^\d{14}$", siret) is None: raise ValidationError("Format incorrect") try: req = requests.get( f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret}" ) except requests.ConnectionError: print("no internet") if req.status_code != 200: raise ValidationError("SIRET inexistant") entreprise = Entreprise.query.filter_by(siret=siret).first() if entreprise is not None: lien = f'<a href="/ScoDoc/entreprises/fiche_entreprise/{entreprise.id}">ici</a>' raise ValidationError( Markup(f"Entreprise déjà présent, lien vers la fiche : {lien}") ) class EntrepriseModificationForm(FlaskForm): hidden_entreprise_siret = HiddenField() siret = StringField("SIRET (*)") nom = _build_string_field("Nom de l'entreprise (*)") adresse = _build_string_field("Adresse (*)") codepostal = _build_string_field("Code postal (*)") ville = _build_string_field("Ville (*)") pays = _build_string_field("Pays", required=False) submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.siret.render_kw = { "disabled": "", "value": self.hidden_entreprise_siret.data, } class MultiCheckboxField(SelectMultipleField): widget = ListWidget(prefix_label=False) option_widget = CheckboxInput() class OffreCreationForm(FlaskForm): intitule = _build_string_field("Intitulé (*)") description = TextAreaField( "Description (*)", validators=[DataRequired(message=CHAMP_REQUIS)] ) type_offre = SelectField( "Type de l'offre (*)", choices=[("Stage"), ("Alternance")], validators=[DataRequired(message=CHAMP_REQUIS)], ) missions = TextAreaField( "Missions (*)", validators=[DataRequired(message=CHAMP_REQUIS)] ) duree = _build_string_field("Durée (*)") depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int) expiration_date = DateField("Date expiration", validators=[Optional()]) submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.depts.choices = [ (dept.id, dept.acronym) for dept in Departement.query.all() ] class OffreModificationForm(FlaskForm): intitule = _build_string_field("Intitulé (*)") description = TextAreaField( "Description (*)", validators=[DataRequired(message=CHAMP_REQUIS)] ) type_offre = SelectField( "Type de l'offre (*)", choices=[("Stage"), ("Alternance")], validators=[DataRequired(message=CHAMP_REQUIS)], ) missions = TextAreaField( "Missions (*)", validators=[DataRequired(message=CHAMP_REQUIS)] ) duree = _build_string_field("Durée (*)") depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int) expiration_date = DateField("Date expiration", validators=[Optional()]) submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.depts.choices = [ (dept.id, dept.acronym) for dept in Departement.query.all() ] class ContactCreationForm(FlaskForm): hidden_entreprise_id = HiddenField() nom = _build_string_field("Nom (*)") prenom = _build_string_field("Prénom (*)") telephone = _build_string_field("Téléphone (*)", required=False) mail = StringField( "Mail (*)", validators=[Optional(), Email(message="Adresse e-mail invalide")], ) poste = _build_string_field("Poste", required=False) service = _build_string_field("Service", required=False) submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE) def validate(self): validate = True if not FlaskForm.validate(self): validate = False contact = EntrepriseContact.query.filter_by( entreprise_id=self.hidden_entreprise_id.data, nom=self.nom.data, prenom=self.prenom.data, ).first() if contact is not None: self.nom.errors.append("Ce contact existe déjà (même nom et prénom)") self.prenom.errors.append("") validate = False if not self.telephone.data and not self.mail.data: self.telephone.errors.append( "Saisir un moyen de contact (mail ou téléphone)" ) self.mail.errors.append("Saisir un moyen de contact (mail ou téléphone)") validate = False return validate class ContactModificationForm(FlaskForm): hidden_contact_id = HiddenField() hidden_entreprise_id = HiddenField() nom = _build_string_field("Nom (*)") prenom = _build_string_field("Prénom (*)") telephone = _build_string_field("Téléphone (*)", required=False) mail = StringField( "Mail (*)", validators=[Optional(), Email(message="Adresse e-mail invalide")], ) poste = _build_string_field("Poste", required=False) service = _build_string_field("Service", required=False) submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE) def validate(self): validate = True if not FlaskForm.validate(self): validate = False contact = EntrepriseContact.query.filter( EntrepriseContact.id != self.hidden_contact_id.data, EntrepriseContact.entreprise_id == self.hidden_entreprise_id.data, EntrepriseContact.nom == self.nom.data, EntrepriseContact.prenom == self.prenom.data, ).first() if contact is not None: self.nom.errors.append("Ce contact existe déjà (même nom et prénom)") self.prenom.errors.append("") validate = False if not self.telephone.data and not self.mail.data: self.telephone.errors.append( "Saisir un moyen de contact (mail ou téléphone)" ) self.mail.errors.append("Saisir un moyen de contact (mail ou téléphone)") validate = False return validate class HistoriqueCreationForm(FlaskForm): etudiant = _build_string_field( "Étudiant (*)", render_kw={"placeholder": "Tapez le nom de l'étudiant"}, ) type_offre = SelectField( "Type de l'offre (*)", choices=[("Stage"), ("Alternance")], validators=[DataRequired(message=CHAMP_REQUIS)], ) date_debut = DateField( "Date début (*)", validators=[DataRequired(message=CHAMP_REQUIS)] ) date_fin = DateField( "Date fin (*)", validators=[DataRequired(message=CHAMP_REQUIS)] ) submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE) def validate(self): validate = True if not FlaskForm.validate(self): validate = False if ( self.date_debut.data and self.date_fin.data and self.date_debut.data > self.date_fin.data ): self.date_debut.errors.append("Les dates sont incompatibles") self.date_fin.errors.append("Les dates sont incompatibles") validate = False return validate def validate_etudiant(self, etudiant): etudiant_data = etudiant.data.upper().strip() stm = text( "SELECT id, CONCAT(nom, ' ', prenom) as nom_prenom FROM Identite WHERE CONCAT(nom, ' ', prenom)=:nom_prenom" ) etudiant = ( Identite.query.from_statement(stm).params(nom_prenom=etudiant_data).first() ) if etudiant is None: raise ValidationError("Champ incorrect (selectionnez dans la liste)") class EnvoiOffreForm(FlaskForm): responsable = _build_string_field( "Responsable de formation (*)", render_kw={"placeholder": "Tapez le nom du responsable de formation"}, ) submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE) def validate_responsable(self, responsable): responsable_data = responsable.data.upper().strip() stm = text( "SELECT id, UPPER(CONCAT(nom, ' ', prenom, ' ', '(', user_name, ')')) FROM \"user\" WHERE UPPER(CONCAT(nom, ' ', prenom, ' ', '(', user_name, ')'))=:responsable_data" ) responsable = ( User.query.from_statement(stm) .params(responsable_data=responsable_data) .first() ) if responsable is None: raise ValidationError("Champ incorrect (selectionnez dans la liste)") class AjoutFichierForm(FlaskForm): fichier = FileField( "Fichier (*)", validators=[ FileRequired(message=CHAMP_REQUIS), FileAllowed(["pdf", "docx"], "Fichier .pdf ou .docx uniquement"), ], ) submit = SubmitField("Ajouter", render_kw=SUBMIT_MARGE) class SuppressionConfirmationForm(FlaskForm): submit = SubmitField("Supprimer", render_kw=SUBMIT_MARGE) class ValidationConfirmationForm(FlaskForm): submit = SubmitField("Valider", render_kw=SUBMIT_MARGE) class ImportForm(FlaskForm): fichier = FileField( "Fichier (*)", validators=[ FileRequired(message=CHAMP_REQUIS), FileAllowed(["xlsx"], "Fichier .xlsx uniquement"), ], ) submit = SubmitField("Importer", render_kw=SUBMIT_MARGE) class PreferencesForm(FlaskForm): mail_entreprise = StringField( "Mail notifications", validators=[Optional(), Email(message="Adresse e-mail invalide")], ) check_siret = BooleanField("Vérification SIRET") submit = SubmitField("Valider", render_kw=SUBMIT_MARGE)