diff --git a/app/scodoc/TrivialFormulator.py b/app/scodoc/TrivialFormulator.py index acbe8d8ca9..722b7ec9a6 100644 --- a/app/scodoc/TrivialFormulator.py +++ b/app/scodoc/TrivialFormulator.py @@ -9,6 +9,12 @@ v 1.3 (python3) """ import html +import re + +# re validant dd/mm/yyyy +DMY_REGEXP = re.compile( + r"^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[13-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$" +) def TrivialFormulator( @@ -66,8 +72,8 @@ def TrivialFormulator( HTML elements: input_type : 'text', 'textarea', 'password', 'radio', 'menu', 'checkbox', - 'hidden', 'separator', 'file', 'date', 'boolcheckbox', - 'text_suggest' + 'hidden', 'separator', 'file', 'date', 'datedmy' (avec validation), + 'boolcheckbox', 'text_suggest' (default text) size : text field width rows, cols: textarea geometry @@ -243,6 +249,8 @@ class TF(object): "Le champ '%s' doit être renseigné" % descr.get("title", field) ) ok = 0 + elif val == "" or val == None: + continue # allowed empty field, skip # type typ = descr.get("type", "string") if val != "" and val != None: @@ -300,6 +308,10 @@ class TF(object): if not descr["validator"](val, field): msg.append("valeur invalide (%s) pour le champ '%s'" % (val, field)) ok = 0 + elif descr.get("input_type") == "datedmy": + if not DMY_REGEXP.match(val): + msg.append("valeur invalide (%s) pour la date '%s'" % (val, field)) + ok = 0 # boolean checkbox if descr.get("input_type", None) == "boolcheckbox": if int(val): @@ -564,7 +576,9 @@ class TF(object): '' % (field, size, values[field], attribs) ) - elif input_type == "date": # JavaScript widget for date input + elif ( + input_type == "date" or input_type == "datedmy" + ): # JavaScript widget for date input lem.append( '' % (field, values[field]) diff --git a/app/scodoc/sco_evaluation_edit.py b/app/scodoc/sco_evaluation_edit.py index 583ac5c442..c324a89be2 100644 --- a/app/scodoc/sco_evaluation_edit.py +++ b/app/scodoc/sco_evaluation_edit.py @@ -170,7 +170,7 @@ def evaluation_create_form( ( "jour", { - "input_type": "date", + "input_type": "datedmy", "title": "Date", "size": 12, "explanation": "date de l'examen, devoir ou contrôle", diff --git a/app/scodoc/sco_exceptions.py b/app/scodoc/sco_exceptions.py index 1099986bf0..c563c93e6b 100644 --- a/app/scodoc/sco_exceptions.py +++ b/app/scodoc/sco_exceptions.py @@ -96,6 +96,28 @@ class ScoNonEmptyFormationObject(ScoValueError): super().__init__(msg=msg, dest_url=dest_url) +class ScoInvalidIdType(ScoValueError): + """Pour les clients qui s'obstinnent à utiliser des bookmarks ou + historiques anciens avec des ID ScoDoc7""" + + def __init__(self, msg=""): + import app.scodoc.sco_utils as scu + + msg = f"""
+ Vous utilisez un lien invalide, qui correspond probablement
+ à une ancienne version du logiciel.
+ Au besoin, mettre à jour vos marque-pages.
+
Si le problème persiste, merci de contacter l'assistance + via la liste de diffusion Notes + ou le salon Discord. +
+Message serveur: {msg}
+ """ + super().__init__(msg) + + class ScoGenError(ScoException): "exception avec affichage d'une page explicative ad-hoc" diff --git a/app/scodoc/sco_formsemestre.py b/app/scodoc/sco_formsemestre.py index 272c5c3831..35336ccf21 100644 --- a/app/scodoc/sco_formsemestre.py +++ b/app/scodoc/sco_formsemestre.py @@ -27,21 +27,22 @@ """Operations de base sur les formsemestres """ -from app.scodoc.sco_exceptions import ScoValueError -import time from operator import itemgetter +import time from flask import g, request import app +from app import log from app.models import Departement + from app.scodoc import sco_codes_parcours from app.scodoc import sco_cache from app.scodoc import sco_formations from app.scodoc import sco_preferences from app.scodoc.gen_tables import GenTable -from app import log from app.scodoc.sco_codes_parcours import NO_SEMESTRE_ID +from app.scodoc.sco_exceptions import ScoValueError, ScoInvalidIdType from app.scodoc.sco_vdi import ApoEtapeVDI import app.scodoc.notesdb as ndb import app.scodoc.sco_utils as scu @@ -97,7 +98,7 @@ def get_formsemestre(formsemestre_id, raise_soft_exc=False): if formsemestre_id in g.stored_get_formsemestre: return g.stored_get_formsemestre[formsemestre_id] if not isinstance(formsemestre_id, int): - raise ValueError("formsemestre_id must be an integer !") + raise ScoInvalidIdType("formsemestre_id must be an integer !") sems = do_formsemestre_list(args={"formsemestre_id": formsemestre_id}) if not sems: log("get_formsemestre: invalid formsemestre_id (%s)" % formsemestre_id) diff --git a/app/scodoc/sco_formsemestre_edit.py b/app/scodoc/sco_formsemestre_edit.py index 060289e95f..e321191302 100644 --- a/app/scodoc/sco_formsemestre_edit.py +++ b/app/scodoc/sco_formsemestre_edit.py @@ -254,7 +254,7 @@ def do_formsemestre_createwithmodules(edit=False): "date_debut", { "title": "Date de début", # j/m/a - "input_type": "date", + "input_type": "datedmy", "explanation": "j/m/a", "size": 9, "allow_null": False, @@ -264,7 +264,7 @@ def do_formsemestre_createwithmodules(edit=False): "date_fin", { "title": "Date de fin", # j/m/a - "input_type": "date", + "input_type": "datedmy", "explanation": "j/m/a", "size": 9, "allow_null": False, @@ -914,7 +914,7 @@ def formsemestre_clone(formsemestre_id): "date_debut", { "title": "Date de début", # j/m/a - "input_type": "date", + "input_type": "datedmy", "explanation": "j/m/a", "size": 9, "allow_null": False, @@ -924,7 +924,7 @@ def formsemestre_clone(formsemestre_id): "date_fin", { "title": "Date de fin", # j/m/a - "input_type": "date", + "input_type": "datedmy", "explanation": "j/m/a", "size": 9, "allow_null": False, diff --git a/app/scodoc/sco_formsemestre_exterieurs.py b/app/scodoc/sco_formsemestre_exterieurs.py index b3d601de77..7e4e3da891 100644 --- a/app/scodoc/sco_formsemestre_exterieurs.py +++ b/app/scodoc/sco_formsemestre_exterieurs.py @@ -154,7 +154,7 @@ def formsemestre_ext_create_form(etudid, formsemestre_id): "date_debut", { "title": "Date de début", # j/m/a - "input_type": "date", + "input_type": "datedmy", "explanation": "j/m/a (peut être approximatif)", "size": 9, "allow_null": False, @@ -164,7 +164,7 @@ def formsemestre_ext_create_form(etudid, formsemestre_id): "date_fin", { "title": "Date de fin", # j/m/a - "input_type": "date", + "input_type": "datedmy", "explanation": "j/m/a (peut être approximatif)", "size": 9, "allow_null": False, diff --git a/app/static/js/releve-but.js b/app/static/js/releve-but.js index 68918448b4..ea9f8bc6c2 100644 --- a/app/static/js/releve-but.js +++ b/app/static/js/releve-but.js @@ -1,42 +1,42 @@ /* Module par Seb. L. */ class releveBUT extends HTMLElement { - constructor(){ + constructor() { super(); - this.shadow = this.attachShadow({mode: 'open'}); + this.shadow = this.attachShadow({ mode: 'open' }); /* Config par defaut */ this.config = { showURL: true }; - + /* Template du module */ this.shadow.innerHTML = this.template(); - + /* Style du module */ const styles = document.createElement('link'); styles.setAttribute('rel', 'stylesheet'); styles.setAttribute('href', '/ScoDoc/static/css/releve-but.css'); - this.shadow.appendChild(styles); + this.shadow.appendChild(styles); } listeOnOff() { this.parentElement.parentElement.classList.toggle("listeOff"); - this.parentElement.parentElement.querySelectorAll(".moduleOnOff").forEach(e=>{ + this.parentElement.parentElement.querySelectorAll(".moduleOnOff").forEach(e => { e.classList.remove("moduleOnOff") }) } - moduleOnOff(){ + moduleOnOff() { this.parentElement.classList.toggle("moduleOnOff"); } - goTo(){ + goTo() { let module = this.dataset.module; this.parentElement.parentElement.parentElement.parentElement.querySelector("#Module_" + module).scrollIntoView(); } - set setConfig(config){ + set setConfig(config) { this.config.showURL = config.showURL ?? this.config.showURL; } - set showData(data) { + set showData(data) { this.showInformations(data); this.showSemestre(data); this.showSynthese(data); @@ -46,7 +46,7 @@ class releveBUT extends HTMLElement { this.shadow.querySelectorAll(".CTA_Liste").forEach(e => { e.addEventListener("click", this.listeOnOff) - }) + }) this.shadow.querySelectorAll(".ue, .module").forEach(e => { e.addEventListener("click", this.moduleOnOff) }) @@ -57,7 +57,7 @@ class releveBUT extends HTMLElement { this.shadow.children[0].classList.add("ready"); } - template(){ + template() { return `