1
0
forked from ScoDoc/ScoDoc
This commit is contained in:
Emmanuel Viennet 2022-01-04 20:03:38 +01:00
parent a65e9f9e08
commit 82e3de02f6
19 changed files with 249 additions and 125 deletions

View File

@ -190,6 +190,7 @@ def create_app(config_class=DevConfig):
app.register_error_handler(ScoGenError, handle_sco_value_error)
app.register_error_handler(ScoValueError, handle_sco_value_error)
app.register_error_handler(AccessDenied, handle_access_denied)
app.register_error_handler(500, internal_server_error)
app.register_error_handler(503, postgresql_server_error)

View File

@ -11,7 +11,7 @@ from time import time
from typing import Optional
import cracklib # pylint: disable=import-error
from flask import current_app, url_for, g
from flask import current_app, g
from flask_login import UserMixin, AnonymousUserMixin
from werkzeug.security import generate_password_hash, check_password_hash
@ -136,6 +136,7 @@ class User(UserMixin, db.Model):
return check_password_hash(self.password_hash, password)
def get_reset_password_token(self, expires_in=600):
"Un token pour réinitialiser son mot de passe"
return jwt.encode(
{"reset_password": self.id, "exp": time() + expires_in},
current_app.config["SECRET_KEY"],
@ -144,15 +145,17 @@ class User(UserMixin, db.Model):
@staticmethod
def verify_reset_password_token(token):
"Vérification du token de reéinitialisation du mot de passe"
try:
id = jwt.decode(
user_id = jwt.decode(
token, current_app.config["SECRET_KEY"], algorithms=["HS256"]
)["reset_password"]
except:
return
return User.query.get(id)
return User.query.get(user_id)
def to_dict(self, include_email=True):
"""l'utilisateur comme un dict, avec des champs supplémentaires"""
data = {
"date_expiration": self.date_expiration.isoformat() + "Z"
if self.date_expiration
@ -472,5 +475,5 @@ def get_super_admin():
@login.user_loader
def load_user(id):
return User.query.get(int(id))
def load_user(uid):
return User.query.get(int(uid))

View File

@ -72,7 +72,7 @@ def bulletin_but_xml_compat(
etud = Identite.query.get_or_404(etudid)
results = bulletin_but.ResultatsSemestreBUT(sem)
nb_inscrits = len(results.etuds)
if sem.bul_hide_xml or force_publishing:
if (not sem.bul_hide_xml) or force_publishing:
published = "1"
else:
published = "0"

View File

@ -245,7 +245,7 @@ class DeptForm(FlaskForm):
def _make_dept_id_name():
"""Cette section assute que tous les départements sont traités (y compris ceux qu'ont pas de logo au départ)
"""Cette section assure que tous les départements sont traités (y compris ceux qu'ont pas de logo au départ)
et détermine l'ordre d'affichage des DeptForm (GLOBAL d'abord, puis par ordre alpha de nom de département)
-> [ (None, None), (dept_id, dept_name)... ]"""
depts = [(None, GLOBAL)]

View File

@ -31,16 +31,10 @@ Formulaires création département
from flask import flash, url_for, redirect, render_template
from flask_wtf import FlaskForm
from wtforms import SelectField, SubmitField, FormField, validators, FieldList
from wtforms.fields.simple import StringField, HiddenField
from wtforms import SubmitField, validators
from wtforms.fields.simple import StringField, BooleanField
from app import AccessDenied
from app.models import Departement
from app.models import ScoPreference
from app.models import SHORT_STR_LEN
from app.scodoc import sco_utils as scu
from flask_login import current_user
class CreateDeptForm(FlaskForm):
@ -60,5 +54,9 @@ class CreateDeptForm(FlaskForm):
validators.DataRequired("acronyme du département requis"),
],
)
visible = BooleanField(
"Visible sur page d'accueil",
default=True,
)
submit = SubmitField("Valider")
cancel = SubmitField("Annuler", render_kw={"formnovalidate": True})

View File

@ -49,11 +49,11 @@ class Departement(db.Model):
return dept
def create_dept(acronym: str) -> Departement:
def create_dept(acronym: str, visible=True) -> Departement:
"Create new departement"
from app.models import ScoPreference
departement = Departement(acronym=acronym)
departement = Departement(acronym=acronym, visible=visible)
p1 = ScoPreference(name="DeptName", value=acronym, departement=departement)
db.session.add(p1)
db.session.add(departement)

View File

@ -78,7 +78,8 @@ def html_edit_formation_apc(
alt="supprimer",
),
"delete_disabled": scu.icontag(
"delete_small_dis_img", title="Suppression impossible (module utilisé)"
"delete_small_dis_img",
title="Suppression impossible (utilisé dans des semestres)",
),
}

View File

@ -30,13 +30,18 @@
"""
import flask
from flask import g, url_for, request
from app.models.formations import Matiere
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
from app import log
from app.models import Formation
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
from app.scodoc.sco_exceptions import ScoValueError, ScoLockedFormError
from app.scodoc.sco_exceptions import (
ScoValueError,
ScoLockedFormError,
ScoNonEmptyFormationObject,
)
from app.scodoc import html_sco_header
_matiereEditor = ndb.EditableTable(
@ -156,6 +161,16 @@ associé.
return flask.redirect(dest_url)
def can_delete_matiere(matiere: Matiere) -> tuple[bool, str]:
"True si la matiere n'est pas utilisée dans des formsemestre"
locked = matiere_is_locked(matiere.id)
if locked:
return False
if any(m.modimpls.all() for m in matiere.modules):
return False
return True
def do_matiere_delete(oid):
"delete matiere and attached modules"
from app.scodoc import sco_formations
@ -165,17 +180,16 @@ def do_matiere_delete(oid):
cnx = ndb.GetDBConnexion()
# check
mat = matiere_list({"matiere_id": oid})[0]
matiere = Matiere.query.get_or_404(oid)
mat = matiere_list({"matiere_id": oid})[0] # compat sco7
ue = sco_edit_ue.ue_list({"ue_id": mat["ue_id"]})[0]
locked = matiere_is_locked(mat["matiere_id"])
if locked:
log("do_matiere_delete: mat=%s" % mat)
log("do_matiere_delete: ue=%s" % ue)
log("do_matiere_delete: locked sems: %s" % locked)
raise ScoLockedFormError()
log("do_matiere_delete: matiere_id=%s" % oid)
if not can_delete_matiere(matiere):
# il y a au moins un modimpl dans un module de cette matière
raise ScoNonEmptyFormationObject("Matière", matiere.titre)
log("do_matiere_delete: matiere_id=%s" % matiere.id)
# delete all modules in this matiere
mods = sco_edit_module.module_list({"matiere_id": oid})
mods = sco_edit_module.module_list({"matiere_id": matiere.id})
for mod in mods:
sco_edit_module.do_module_delete(mod["module_id"])
_matiereEditor.delete(cnx, oid)
@ -194,11 +208,25 @@ def matiere_delete(matiere_id=None):
"""Delete matière"""
from app.scodoc import sco_edit_ue
M = matiere_list(args={"matiere_id": matiere_id})[0]
UE = sco_edit_ue.ue_list(args={"ue_id": M["ue_id"]})[0]
matiere = Matiere.query.get_or_404(matiere_id)
if not can_delete_matiere(matiere):
# il y a au moins un modimpl dans un module de cette matière
raise ScoNonEmptyFormationObject(
"Matière",
matiere.titre,
dest_url=url_for(
"notes.ue_table",
formation_id=matiere.ue.formation_id,
semestre_idx=matiere.ue.semestre_idx,
scodoc_dept=g.scodoc_dept,
),
)
mat = matiere_list(args={"matiere_id": matiere_id})[0]
UE = sco_edit_ue.ue_list(args={"ue_id": mat["ue_id"]})[0]
H = [
html_sco_header.sco_header(page_title="Suppression d'une matière"),
"<h2>Suppression de la matière %(titre)s" % M,
"<h2>Suppression de la matière %(titre)s" % mat,
" dans l'UE (%(acronyme)s))</h2>" % UE,
]
dest_url = url_for(
@ -210,7 +238,7 @@ def matiere_delete(matiere_id=None):
request.base_url,
scu.get_request_args(),
(("matiere_id", {"input_type": "hidden"}),),
initvalues=M,
initvalues=mat,
submitlabel="Confirmer la suppression",
cancelbutton="Annuler",
)

View File

@ -43,7 +43,12 @@ from app import models
from app.models import Formation
from app.scodoc.TrivialFormulator import TrivialFormulator
from app.scodoc.sco_permissions import Permission
from app.scodoc.sco_exceptions import ScoValueError, ScoLockedFormError, ScoGenError
from app.scodoc.sco_exceptions import (
ScoValueError,
ScoLockedFormError,
ScoGenError,
ScoNonEmptyFormationObject,
)
from app.scodoc import html_sco_header
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_edit_matiere
@ -330,20 +335,37 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
)
def can_delete_module(module):
"True si le module n'est pas utilisée dans des formsemestre"
return len(module.modimpls.all()) == 0
def do_module_delete(oid):
"delete module"
from app.scodoc import sco_formations
mod = module_list({"module_id": oid})[0]
if module_is_locked(mod["module_id"]):
module = Module.query.get_or_404(oid)
mod = module_list({"module_id": oid})[0] # sco7
if module_is_locked(module.id):
raise ScoLockedFormError()
if not can_delete_module(module):
raise ScoNonEmptyFormationObject(
"Module",
msg=module.titre,
dest_url=url_for(
"notes.ue_table",
scodoc_dept=g.scodoc_dept,
formation_id=module.formation_id,
semestre_idx=module.ue.semestre_idx,
),
)
# S'il y a des moduleimpls, on ne peut pas detruire le module !
mods = sco_moduleimpl.moduleimpl_list(module_id=oid)
if mods:
err_page = f"""<h3>Destruction du module impossible car il est utilisé dans des semestres existants !</h3>
<p class="help">Il faut d'abord supprimer le semestre. Mais il est peut être préférable de
laisser ce programme intact et d'en créer une nouvelle version pour la modifier.
<p class="help">Il faut d'abord supprimer le semestre (ou en retirer ce module). Mais il est peut être préférable de
laisser ce programme intact et d'en créer une nouvelle version pour la modifier sans affecter les semestres déjà en place.
</p>
<a href="{url_for('notes.ue_table', scodoc_dept=g.scodoc_dept,
formation_id=mod["formation_id"])}">reprendre</a>
@ -365,12 +387,21 @@ def do_module_delete(oid):
def module_delete(module_id=None):
"""Delete a module"""
if not module_id:
raise ScoValueError("invalid module !")
modules = module_list(args={"module_id": module_id})
if not modules:
raise ScoValueError("Module inexistant !")
mod = modules[0]
module = Module.query.get_or_404(module_id)
mod = module_list(args={"module_id": module_id})[0] # sco7
if not can_delete_module(module):
raise ScoNonEmptyFormationObject(
"Module",
msg=module.titre,
dest_url=url_for(
"notes.ue_table",
scodoc_dept=g.scodoc_dept,
formation_id=module.formation_id,
semestre_idx=module.ue.semestre_idx,
),
)
H = [
html_sco_header.sco_header(page_title="Suppression d'un module"),
"""<h2>Suppression du module %(titre)s (%(code)s)</h2>""" % mod,

View File

@ -42,7 +42,12 @@ from app import log
from app.scodoc.TrivialFormulator import TrivialFormulator, TF
from app.scodoc.gen_tables import GenTable
from app.scodoc.sco_permissions import Permission
from app.scodoc.sco_exceptions import ScoValueError, ScoLockedFormError
from app.scodoc.sco_exceptions import (
ScoGenError,
ScoValueError,
ScoLockedFormError,
ScoNonEmptyFormationObject,
)
from app.scodoc import html_sco_header
from app.scodoc import sco_cache
@ -130,64 +135,83 @@ def do_ue_create(args):
return ue_id
def can_delete_ue(ue: UniteEns) -> bool:
"""True si l'UE n'est pas utilisée dans des formsemestre
et n'a pas de module rattachés
"""
# "pas un seul module de cette UE n'a de modimpl...""
return (not len(ue.modules.all())) and not any(m.modimpls.all() for m in ue.modules)
def do_ue_delete(ue_id, delete_validations=False, force=False):
"delete UE and attached matieres (but not modules)"
from app.scodoc import sco_formations
from app.scodoc import sco_parcours_dut
ue = UniteEns.query.get_or_404(ue_id)
if not can_delete_ue(ue):
raise ScoNonEmptyFormationObject(
"UE",
msg=ue.titre,
dest_url=url_for(
"notes.ue_table",
scodoc_dept=g.scodoc_dept,
formation_id=ue.formation_id,
semestre_idx=ue.semestre_idx,
),
)
cnx = ndb.GetDBConnexion()
log("do_ue_delete: ue_id=%s, delete_validations=%s" % (ue_id, delete_validations))
log("do_ue_delete: ue_id=%s, delete_validations=%s" % (ue.id, delete_validations))
# check
ue = ue_list({"ue_id": ue_id})
if not ue:
raise ScoValueError("UE inexistante !")
ue = ue[0]
if ue_is_locked(ue["ue_id"]):
raise ScoLockedFormError()
# if ue_is_locked(ue.id):
# raise ScoLockedFormError()
# Il y a-t-il des etudiants ayant validé cette UE ?
# si oui, propose de supprimer les validations
validations = sco_parcours_dut.scolar_formsemestre_validation_list(
cnx, args={"ue_id": ue_id}
cnx, args={"ue_id": ue.id}
)
if validations and not delete_validations and not force:
return scu.confirm_dialog(
"<p>%d étudiants ont validé l'UE %s (%s)</p><p>Si vous supprimez cette UE, ces validations vont être supprimées !</p>"
% (len(validations), ue["acronyme"], ue["titre"]),
% (len(validations), ue.acronyme, ue.titre),
dest_url="",
target_variable="delete_validations",
cancel_url=url_for(
"notes.ue_table",
scodoc_dept=g.scodoc_dept,
formation_id=str(ue["formation_id"]),
formation_id=ue.formation_id,
semestre_idx=ue.semestre_idx,
),
parameters={"ue_id": ue_id, "dialog_confirmed": 1},
parameters={"ue_id": ue.id, "dialog_confirmed": 1},
)
if delete_validations:
log("deleting all validations of UE %s" % ue_id)
log("deleting all validations of UE %s" % ue.id)
ndb.SimpleQuery(
"DELETE FROM scolar_formsemestre_validation WHERE ue_id=%(ue_id)s",
{"ue_id": ue_id},
{"ue_id": ue.id},
)
# delete all matiere in this UE
mats = sco_edit_matiere.matiere_list({"ue_id": ue_id})
mats = sco_edit_matiere.matiere_list({"ue_id": ue.id})
for mat in mats:
sco_edit_matiere.do_matiere_delete(mat["matiere_id"])
# delete uecoef and events
ndb.SimpleQuery(
"DELETE FROM notes_formsemestre_uecoef WHERE ue_id=%(ue_id)s",
{"ue_id": ue_id},
{"ue_id": ue.id},
)
ndb.SimpleQuery("DELETE FROM scolar_events WHERE ue_id=%(ue_id)s", {"ue_id": ue_id})
ndb.SimpleQuery("DELETE FROM scolar_events WHERE ue_id=%(ue_id)s", {"ue_id": ue.id})
cnx = ndb.GetDBConnexion()
_ueEditor.delete(cnx, ue_id)
# > UE delete + supr. validations associées etudiants (cas compliqué, mais rarement utilisé: acceptable de tout invalider ?):
_ueEditor.delete(cnx, ue.id)
# > UE delete + supr. validations associées etudiants (cas compliqué, mais rarement
# utilisé: acceptable de tout invalider):
sco_cache.invalidate_formsemestre()
# news
F = sco_formations.formation_list(args={"formation_id": ue["formation_id"]})[0]
F = sco_formations.formation_list(args={"formation_id": ue.formation_id})[0]
sco_news.add(
typ=sco_news.NEWS_FORM,
object=ue["formation_id"],
object=ue.formation_id,
text="Modification de la formation %(acronyme)s" % F,
max_frequency=3,
)
@ -197,11 +221,11 @@ def do_ue_delete(ue_id, delete_validations=False, force=False):
url_for(
"notes.ue_table",
scodoc_dept=g.scodoc_dept,
formation_id=ue["formation_id"],
formation_id=ue.formation_id,
semestre_idx=ue.semestre_idx,
)
)
else:
return None
return None
def ue_create(formation_id=None):
@ -211,8 +235,6 @@ def ue_create(formation_id=None):
def ue_edit(ue_id=None, create=False, formation_id=None):
"""Modification ou création d'une UE"""
from app.scodoc import sco_formations
create = int(create)
if not create:
U = ue_list(args={"ue_id": ue_id})
@ -444,24 +466,38 @@ def next_ue_numero(formation_id, semestre_id=None):
def ue_delete(ue_id=None, delete_validations=False, dialog_confirmed=False):
"""Delete an UE"""
ues = ue_list(args={"ue_id": ue_id})
if not ues:
raise ScoValueError("UE inexistante !")
ue = ues[0]
if not dialog_confirmed:
return scu.confirm_dialog(
"<h2>Suppression de l'UE %(titre)s (%(acronyme)s))</h2>" % ue,
dest_url="",
parameters={"ue_id": ue_id},
cancel_url=url_for(
ue = UniteEns.query.get_or_404(ue_id)
if ue.modules.all():
raise ScoValueError(
f"""Suppression de l'UE {ue.titre} impossible car
des modules (ou SAÉ ou ressources) lui sont rattachés."""
)
if not can_delete_ue(ue):
raise ScoNonEmptyFormationObject(
"UE",
msg=ue.titre,
dest_url=url_for(
"notes.ue_table",
scodoc_dept=g.scodoc_dept,
formation_id=str(ue["formation_id"]),
formation_id=ue.formation_id,
semestre_idx=ue.semestre_idx,
),
)
return do_ue_delete(ue_id, delete_validations=delete_validations)
if not dialog_confirmed:
return scu.confirm_dialog(
f"<h2>Suppression de l'UE {ue.titre} ({ue.acronyme})</h2>",
dest_url="",
parameters={"ue_id": ue.id},
cancel_url=url_for(
"notes.ue_table",
scodoc_dept=g.scodoc_dept,
formation_id=ue.formation_id,
semestre_idx=ue.semestre_idx,
),
)
return do_ue_delete(ue.id, delete_validations=delete_validations)
def ue_table(formation_id=None, semestre_idx=1, msg=""): # was ue_list
@ -1010,12 +1046,14 @@ def _ue_table_modules(
H.append(arrow_none)
im += 1
if mod["nb_moduleimpls"] == 0 and editable:
H.append(
'<a class="smallbutton" href="module_delete?module_id=%s">%s</a>'
% (mod["module_id"], delete_icon)
)
icon = delete_icon
else:
H.append(delete_disabled_icon)
icon = delete_disabled_icon
H.append(
'<a class="smallbutton" href="module_delete?module_id=%s">%s</a>'
% (mod["module_id"], icon)
)
H.append("</span>")
mod_editable = (

View File

@ -52,7 +52,7 @@ class InvalidNoteValue(ScoException):
# Exception qui stoque dest_url, utilisee dans Zope standard_error_message
class ScoValueError(ScoException):
def __init__(self, msg, dest_url=None):
ScoException.__init__(self, msg)
super().__init__(msg)
self.dest_url = dest_url
@ -72,20 +72,35 @@ class ScoConfigurationError(ScoValueError):
pass
class ScoLockedFormError(ScoException):
def __init__(self, msg=""):
class ScoLockedFormError(ScoValueError):
"Modification d'une formation verrouillée"
def __init__(self, msg="", dest_url=None):
msg = (
"Cette formation est verrouillée (car il y a un semestre verrouillé qui s'y réfère). "
+ str(msg)
)
ScoException.__init__(self, msg)
super().__init__(msg=msg, dest_url=dest_url)
class ScoNonEmptyFormationObject(ScoValueError):
"""On ne peut pas supprimer un module/matiere ou UE si des formsemestre s'y réfèrent"""
def __init__(self, type_objet="objet'", msg="", dest_url=None):
msg = f"""<h3>{type_objet} "{msg}" utilisé dans des semestres: suppression impossible.</h3>
<p class="help">Il faut d'abord supprimer le semestre (ou en retirer ce {type_objet}).
Mais il est peut-être préférable de laisser ce programme intact et d'en créer une
nouvelle version pour la modifier sans affecter les semestres déjà en place.
</p>
"""
super().__init__(msg=msg, dest_url=dest_url)
class ScoGenError(ScoException):
"exception avec affichage d'une page explicative ad-hoc"
def __init__(self, msg=""):
ScoException.__init__(self, msg)
super().__init__(msg)
class AccessDenied(ScoGenError):
@ -101,7 +116,7 @@ class APIInvalidParams(Exception):
status_code = 400
def __init__(self, message, status_code=None, payload=None):
Exception.__init__(self)
super().__init__()
self.message = message
if status_code is not None:
self.status_code = status_code

View File

@ -198,10 +198,13 @@ def do_formsemestre_createwithmodules(edit=False):
NB_SEM = parcours.NB_SEM
else:
NB_SEM = 10 # fallback, max 10 semestres
semestre_id_list = [-1] + list(range(1, NB_SEM + 1))
if NB_SEM == 1:
semestre_id_list = [-1]
else:
semestre_id_list = [-1] + list(range(1, NB_SEM + 1))
semestre_id_labels = []
for sid in semestre_id_list:
if sid == "-1":
if sid == -1:
semestre_id_labels.append("pas de semestres")
else:
semestre_id_labels.append(f"S{sid}")
@ -329,6 +332,8 @@ def do_formsemestre_createwithmodules(edit=False):
"labels": modalites_titles,
},
),
]
modform.append(
(
"semestre_id",
{
@ -338,7 +343,7 @@ def do_formsemestre_createwithmodules(edit=False):
"labels": semestre_id_labels,
},
),
]
)
etapes = sco_portal_apogee.get_etapes_apogee_dept()
# Propose les etapes renvoyées par le portail
# et ajoute les étapes du semestre qui ne sont pas dans la liste (soit la liste a changé, soit l'étape a été ajoutée manuellement)

View File

@ -93,6 +93,7 @@ MODULE_TYPE_NAMES = {
ModuleType.MALUS: "Malus",
ModuleType.RESSOURCE: "Ressource",
ModuleType.SAE: "SAÉ",
None: "Module",
}
MALUS_MAX = 20.0

View File

@ -24,14 +24,11 @@
{{icons.arrow_none|safe}}
{% endif %}
</span>
{% if editable and not ue.modules.count() %}
<a class="smallbutton" href="{{ url_for('notes.ue_delete',
scodoc_dept=g.scodoc_dept, ue_id=ue.id)
}}">{{icons.delete|safe}}</a>
{% else %}
{{icons.delete_disabled|safe}}
{% endif %}
}}">{% if editable and not ue.modules.count() %}{{icons.delete|safe}}{% else %}{{icons.delete_disabled|safe}}{% endif %}</a>
<b>{{ue.acronyme}}</b> <a class="discretelink" href="{{
url_for('notes.ue_infos', scodoc_dept=g.scodoc_dept, ue_id=ue.id)}}"
>{{ue.titre}}</a>

View File

@ -8,10 +8,9 @@
{{ exc | safe }}
<p class="footer">
<p>
{% if g.scodoc_dept %}
<a href="{{ exc.dest_url or url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}">retour page d'accueil
departement {{ g.scodoc_dept }}</a>
<a href="{{ exc.dest_url or url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}">continuer</a>
{% else %}
<a href="{{ exc.dest_url or url_for('scodoc.index') }}">retour page d'accueil</a>
{% endif %}

View File

@ -13,11 +13,21 @@
<ul class="main">
{% for dept in depts %}
{% if dept.visible or current_user.is_administrator() %}
<li>
<a class="stdlink {{'link_accessible' if current_user.has_permission(Permission.ScoView, dept=dept.acronym) else 'link_unauthorized'}}"
href="{{url_for('scolar.index_html', scodoc_dept=dept.acronym)}}">Département
{{dept.preferences.filter_by(name="DeptName").first().value}}</a>
{% if current_user.is_administrator() %}
<span class="dept_visibility">
{% if dept.visible %}visible{% else %}caché aux utilisateurs{% endif %}
<a href="{{ url_for('scodoc.toggle_dept_vis', dept_id=dept.id) }}">
{% if dept.visible %}cacher{% else %}rendre visible{% endif %}
</a>
</span>
{% endif %}
</li>
{% endif %}
{% else %}
<li>
<b>Aucun département défini !</b>

View File

@ -53,6 +53,7 @@ from wtforms.fields.simple import BooleanField, StringField, TextAreaField, Hidd
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
import app
from app import db
from app.forms.main import config_forms
from app.forms.main.create_dept import CreateDeptForm
from app.models import Departement, Identite
@ -82,9 +83,7 @@ from PIL import Image as PILImage
@bp.route("/ScoDoc/index")
def index():
"Page d'accueil: liste des départements"
depts = (
Departement.query.filter_by(visible=True).order_by(Departement.acronym).all()
)
depts = Departement.query.filter_by().order_by(Departement.acronym).all()
return render_template(
"scodoc.html",
title=sco_version.SCONAME,
@ -108,7 +107,7 @@ def create_dept():
if request.method == "POST" and form.cancel.data: # cancel button
return redirect(url_for("scodoc.index"))
if form.validate_on_submit():
departements.create_dept(form.acronym.data)
departements.create_dept(form.acronym.data, visible=form.visible.data)
flash(f"Département {form.acronym.data} créé.")
return redirect(url_for("scodoc.index"))
return render_template(
@ -118,6 +117,17 @@ def create_dept():
)
@bp.route("/ScoDoc/toggle_dept_vis/<dept_id>", methods=["GET", "POST"])
@admin_required
def toggle_dept_vis(dept_id):
"""Cache ou rend visible un dept"""
dept = Departement.query.get_or_404(dept_id)
dept.visible = not dept.visible
db.session.add(dept)
db.session.commit()
return redirect(url_for("scodoc.index"))
@bp.route("/ScoDoc/table_etud_in_accessible_depts", methods=["POST"])
@login_required
def table_etud_in_accessible_depts():

View File

@ -152,7 +152,6 @@ def user_info(user_name, format="json"):
def create_user_form(user_name=None, edit=0, all_roles=1):
"form. création ou edition utilisateur"
auth_dept = current_user.dept
auth_username = current_user.user_name
from_mail = current_user.email
initvalues = {}
edit = int(edit)
@ -204,7 +203,7 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
administrable_dept_acronyms = sorted(
set(
[
x.dept
x.dept or ""
for x in UserRole.query.filter_by(user=current_user)
if x.role.has_permission(Permission.ScoUsersAdmin) and x.dept
]
@ -249,7 +248,7 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
r.name + "_" + (dept or "") for (r, dept) in displayed_roles
]
displayed_roles_labels = [f"{dept}: {r.name}" for (r, dept) in displayed_roles]
disabled_roles = {} # pour desactiver les roles que l'on ne peut pas editer
disabled_roles = {} # pour désactiver les roles que l'on ne peut pas éditer
for i in range(len(displayed_roles_strings)):
if displayed_roles_strings[i] not in editable_roles_strings:
disabled_roles[i] = True
@ -375,7 +374,7 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
can_choose_dept = True
else:
selectable_dept_acronyms = set(administrable_dept_acronyms)
if edit: # ajoute dept actuel de l'utilisateur
if edit and the_user.dept is not None: # ajoute dept actuel de l'utilisateur
selectable_dept_acronyms |= {the_user.dept}
if len(selectable_dept_acronyms) > 1:
can_choose_dept = True

View File

@ -274,22 +274,10 @@ def test_formations(test_client):
# --- Suppression du module, matiere et ue test du semestre 2
# on doit d'abbord supprimer le semestre
# sco_formsemestre_edit.formsemestre_delete( formsemestre_id=sem2["formsemestre_id"])
# sco_formsemestre_edit.formsemestre_createwithmodules( formsemestre_id=sem2["formsemestre_id"])
# RIEN NE SE PASSE AVEC CES FONCTIONS
sco_formsemestre_edit.do_formsemestre_delete(
formsemestre_id=sem2["formsemestre_id"]
)
# sco_edit_module.module_delete( module_id=modt["module_id"])
# sco_edit_matiere.matiere_delete( matiere_id=matt["matiere_id"])
# sco_edit_ue.ue_delete( ue_id=uet["ue_id"])
# RIEN NE SE PASSE AVEC CES FONCTIONS
li_module = sco_edit_module.module_list()
assert len(li_module) == 4
sco_edit_module.do_module_delete(oid=modt["module_id"]) # on supprime le semestre