forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -3,9 +3,11 @@
|
|||||||
from flask_json import as_json
|
from flask_json import as_json
|
||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
from flask import request, g
|
from flask import request, g
|
||||||
|
from flask_login import current_user
|
||||||
from app import db
|
from app import db
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
from app.scodoc.sco_exceptions import AccessDenied, ScoException
|
from app.scodoc.sco_exceptions import AccessDenied, ScoException
|
||||||
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
|
||||||
api_bp = Blueprint("api", __name__)
|
api_bp = Blueprint("api", __name__)
|
||||||
api_web_bp = Blueprint("apiweb", __name__)
|
api_web_bp = Blueprint("apiweb", __name__)
|
||||||
@ -48,13 +50,21 @@ def requested_format(default_format="json", allowed_formats=None):
|
|||||||
|
|
||||||
|
|
||||||
@as_json
|
@as_json
|
||||||
def get_model_api_object(model_cls: db.Model, model_id: int, join_cls: db.Model = None):
|
def get_model_api_object(
|
||||||
|
model_cls: db.Model,
|
||||||
|
model_id: int,
|
||||||
|
join_cls: db.Model = None,
|
||||||
|
restrict: bool | None = None,
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Retourne une réponse contenant la représentation api de l'objet "Model[model_id]"
|
Retourne une réponse contenant la représentation api de l'objet "Model[model_id]"
|
||||||
|
|
||||||
Filtrage du département en fonction d'une classe de jointure (eg: Identite, Formsemestre) -> join_cls
|
Filtrage du département en fonction d'une classe de jointure (eg: Identite, Formsemestre) -> join_cls
|
||||||
|
|
||||||
exemple d'utilisation : fonction "justificatif()" -> app/api/justificatifs.py
|
exemple d'utilisation : fonction "justificatif()" -> app/api/justificatifs.py
|
||||||
|
|
||||||
|
L'agument restrict est passé to_dict, est signale que l'on veut une version restreinte
|
||||||
|
(sans données personnelles, ou sans informations sur le justificatif d'absence)
|
||||||
"""
|
"""
|
||||||
query = model_cls.query.filter_by(id=model_id)
|
query = model_cls.query.filter_by(id=model_id)
|
||||||
if g.scodoc_dept and join_cls is not None:
|
if g.scodoc_dept and join_cls is not None:
|
||||||
@ -66,8 +76,9 @@ def get_model_api_object(model_cls: db.Model, model_id: int, join_cls: db.Model
|
|||||||
404,
|
404,
|
||||||
message=f"{model_cls.__name__} inexistant(e)",
|
message=f"{model_cls.__name__} inexistant(e)",
|
||||||
)
|
)
|
||||||
|
if restrict is None:
|
||||||
return unique.to_dict(format_api=True)
|
return unique.to_dict(format_api=True)
|
||||||
|
return unique.to_dict(format_api=True, restrict=restrict)
|
||||||
|
|
||||||
|
|
||||||
from app.api import tokens
|
from app.api import tokens
|
||||||
|
@ -53,14 +53,19 @@ def justificatif(justif_id: int = None):
|
|||||||
"date_fin": "2022-10-31T10:00+01:00",
|
"date_fin": "2022-10-31T10:00+01:00",
|
||||||
"etat": "valide",
|
"etat": "valide",
|
||||||
"fichier": "archive_id",
|
"fichier": "archive_id",
|
||||||
"raison": "une raison",
|
"raison": "une raison", // VIDE si pas le droit
|
||||||
"entry_date": "2022-10-31T08:00+01:00",
|
"entry_date": "2022-10-31T08:00+01:00",
|
||||||
"user_id": 1 or null,
|
"user_id": 1 or null,
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return get_model_api_object(Justificatif, justif_id, Identite)
|
return get_model_api_object(
|
||||||
|
Justificatif,
|
||||||
|
justif_id,
|
||||||
|
Identite,
|
||||||
|
restrict=not current_user.has_permission(Permission.AbsJustifView),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# etudid
|
# etudid
|
||||||
@ -133,8 +138,9 @@ def justificatifs(etudid: int = None, nip=None, ine=None, with_query: bool = Fal
|
|||||||
|
|
||||||
# Mise en forme des données puis retour en JSON
|
# Mise en forme des données puis retour en JSON
|
||||||
data_set: list[dict] = []
|
data_set: list[dict] = []
|
||||||
|
restrict = not current_user.has_permission(Permission.AbsJustifView)
|
||||||
for just in justificatifs_query.all():
|
for just in justificatifs_query.all():
|
||||||
data = just.to_dict(format_api=True)
|
data = just.to_dict(format_api=True, restrict=restrict)
|
||||||
data_set.append(data)
|
data_set.append(data)
|
||||||
|
|
||||||
return data_set
|
return data_set
|
||||||
@ -172,14 +178,15 @@ def justificatifs_dept(dept_id: int = None, with_query: bool = False):
|
|||||||
justificatifs_query: Query = _filter_manager(request, justificatifs_query)
|
justificatifs_query: Query = _filter_manager(request, justificatifs_query)
|
||||||
|
|
||||||
# Mise en forme des données et retour JSON
|
# Mise en forme des données et retour JSON
|
||||||
|
restrict = not current_user.has_permission(Permission.AbsJustifView)
|
||||||
data_set: list[dict] = []
|
data_set: list[dict] = []
|
||||||
for just in justificatifs_query:
|
for just in justificatifs_query:
|
||||||
data_set.append(_set_sems(just))
|
data_set.append(_set_sems(just, restrict=restrict))
|
||||||
|
|
||||||
return data_set
|
return data_set
|
||||||
|
|
||||||
|
|
||||||
def _set_sems(justi: Justificatif) -> dict:
|
def _set_sems(justi: Justificatif, restrict: bool) -> dict:
|
||||||
"""
|
"""
|
||||||
_set_sems Ajoute le formsemestre associé au justificatif s'il existe
|
_set_sems Ajoute le formsemestre associé au justificatif s'il existe
|
||||||
|
|
||||||
@ -192,7 +199,7 @@ def _set_sems(justi: Justificatif) -> dict:
|
|||||||
dict: La représentation de l'assiduité en dictionnaire
|
dict: La représentation de l'assiduité en dictionnaire
|
||||||
"""
|
"""
|
||||||
# Conversion du justificatif en dictionnaire
|
# Conversion du justificatif en dictionnaire
|
||||||
data = justi.to_dict(format_api=True)
|
data = justi.to_dict(format_api=True, restrict=restrict)
|
||||||
|
|
||||||
# Récupération du formsemestre de l'assiduité
|
# Récupération du formsemestre de l'assiduité
|
||||||
formsemestre: FormSemestre = get_formsemestre_from_data(justi.to_dict())
|
formsemestre: FormSemestre = get_formsemestre_from_data(justi.to_dict())
|
||||||
@ -246,9 +253,10 @@ def justificatifs_formsemestre(formsemestre_id: int, with_query: bool = False):
|
|||||||
justificatifs_query: Query = _filter_manager(request, justificatifs_query)
|
justificatifs_query: Query = _filter_manager(request, justificatifs_query)
|
||||||
|
|
||||||
# Retour des justificatifs en JSON
|
# Retour des justificatifs en JSON
|
||||||
|
restrict = not current_user.has_permission(Permission.AbsJustifView)
|
||||||
data_set: list[dict] = []
|
data_set: list[dict] = []
|
||||||
for justi in justificatifs_query.all():
|
for justi in justificatifs_query.all():
|
||||||
data = justi.to_dict(format_api=True)
|
data = justi.to_dict(format_api=True, restrict=restrict)
|
||||||
data_set.append(data)
|
data_set.append(data)
|
||||||
|
|
||||||
return data_set
|
return data_set
|
||||||
|
@ -88,8 +88,10 @@ class Assiduite(ScoDocModel):
|
|||||||
lazy="select",
|
lazy="select",
|
||||||
)
|
)
|
||||||
|
|
||||||
def to_dict(self, format_api=True) -> dict:
|
def to_dict(self, format_api=True, restrict: bool | None = None) -> dict:
|
||||||
"""Retourne la représentation json de l'assiduité"""
|
"""Retourne la représentation json de l'assiduité
|
||||||
|
restrict n'est pas utilisé ici.
|
||||||
|
"""
|
||||||
etat = self.etat
|
etat = self.etat
|
||||||
user: User | None = None
|
user: User | None = None
|
||||||
if format_api:
|
if format_api:
|
||||||
@ -453,8 +455,10 @@ class Justificatif(ScoDocModel):
|
|||||||
query = query.join(Identite).filter_by(dept_id=g.scodoc_dept_id)
|
query = query.join(Identite).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
return query.first_or_404()
|
return query.first_or_404()
|
||||||
|
|
||||||
def to_dict(self, format_api: bool = False) -> dict:
|
def to_dict(self, format_api: bool = False, restrict: bool = False) -> dict:
|
||||||
"""transformation de l'objet en dictionnaire sérialisable"""
|
"""L'objet en dictionnaire sérialisable.
|
||||||
|
Si restrict, ne donne par la raison et les fichiers et external_data
|
||||||
|
"""
|
||||||
|
|
||||||
etat = self.etat
|
etat = self.etat
|
||||||
user: User = self.user if self.user_id is not None else None
|
user: User = self.user if self.user_id is not None else None
|
||||||
@ -469,13 +473,13 @@ class Justificatif(ScoDocModel):
|
|||||||
"date_debut": self.date_debut,
|
"date_debut": self.date_debut,
|
||||||
"date_fin": self.date_fin,
|
"date_fin": self.date_fin,
|
||||||
"etat": etat,
|
"etat": etat,
|
||||||
"raison": self.raison,
|
"raison": None if restrict else self.raison,
|
||||||
"fichier": self.fichier,
|
"fichier": None if restrict else self.fichier,
|
||||||
"entry_date": self.entry_date,
|
"entry_date": self.entry_date,
|
||||||
"user_id": None if user is None else user.id, # l'uid
|
"user_id": None if user is None else user.id, # l'uid
|
||||||
"user_name": None if user is None else user.user_name, # le login
|
"user_name": None if user is None else user.user_name, # le login
|
||||||
"user_nom_complet": None if user is None else user.get_nomcomplet(),
|
"user_nom_complet": None if user is None else user.get_nomcomplet(),
|
||||||
"external_data": self.external_data,
|
"external_data": None if restrict else self.external_data,
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@ -145,7 +145,9 @@ def sco_header(
|
|||||||
etudid=None,
|
etudid=None,
|
||||||
formsemestre_id=None,
|
formsemestre_id=None,
|
||||||
):
|
):
|
||||||
"Main HTML page header for ScoDoc"
|
"""Main HTML page header for ScoDoc
|
||||||
|
Utilisé dans les anciennes pages. Les nouvelles pages utilisent le template Jinja.
|
||||||
|
"""
|
||||||
from app.scodoc.sco_formsemestre_status import formsemestre_page_title
|
from app.scodoc.sco_formsemestre_status import formsemestre_page_title
|
||||||
|
|
||||||
if etudid is not None:
|
if etudid is not None:
|
||||||
|
@ -32,12 +32,66 @@ from flask import render_template, url_for
|
|||||||
from flask import g, request
|
from flask import g, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
|
from app import db
|
||||||
|
from app.models import Evaluation, GroupDescr, ModuleImpl, Partition
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
from sco_version import SCOVERSION
|
from sco_version import SCOVERSION
|
||||||
|
|
||||||
|
|
||||||
|
def retreive_formsemestre_from_request() -> int:
|
||||||
|
"""Cherche si on a de quoi déduire le semestre affiché à partir des
|
||||||
|
arguments de la requête:
|
||||||
|
formsemestre_id ou moduleimpl ou evaluation ou group_id ou partition_id
|
||||||
|
Returns None si pas défini.
|
||||||
|
"""
|
||||||
|
if request.method == "GET":
|
||||||
|
args = request.args
|
||||||
|
elif request.method == "POST":
|
||||||
|
args = request.form
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
formsemestre_id = None
|
||||||
|
# Search formsemestre
|
||||||
|
group_ids = args.get("group_ids", [])
|
||||||
|
if "formsemestre_id" in args:
|
||||||
|
formsemestre_id = args["formsemestre_id"]
|
||||||
|
elif "moduleimpl_id" in args and args["moduleimpl_id"]:
|
||||||
|
modimpl = db.session.get(ModuleImpl, args["moduleimpl_id"])
|
||||||
|
if not modimpl:
|
||||||
|
return None # suppressed ?
|
||||||
|
formsemestre_id = modimpl.formsemestre_id
|
||||||
|
elif "evaluation_id" in args:
|
||||||
|
evaluation = db.session.get(Evaluation, args["evaluation_id"])
|
||||||
|
if not evaluation:
|
||||||
|
return None # evaluation suppressed ?
|
||||||
|
formsemestre_id = evaluation.moduleimpl.formsemestre_id
|
||||||
|
elif "group_id" in args:
|
||||||
|
group = db.session.get(GroupDescr, args["group_id"])
|
||||||
|
if not group:
|
||||||
|
return None
|
||||||
|
formsemestre_id = group.partition.formsemestre_id
|
||||||
|
elif group_ids:
|
||||||
|
if isinstance(group_ids, str):
|
||||||
|
group_ids = group_ids.split(",")
|
||||||
|
group_id = group_ids[0]
|
||||||
|
group = db.session.get(GroupDescr, group_id)
|
||||||
|
if not group:
|
||||||
|
return None
|
||||||
|
formsemestre_id = group.partition.formsemestre_id
|
||||||
|
elif "partition_id" in args:
|
||||||
|
partition = db.session.get(Partition, args["partition_id"])
|
||||||
|
if not partition:
|
||||||
|
return None
|
||||||
|
formsemestre_id = partition.formsemestre_id
|
||||||
|
|
||||||
|
if formsemestre_id is None:
|
||||||
|
return None # no current formsemestre
|
||||||
|
|
||||||
|
return int(formsemestre_id)
|
||||||
|
|
||||||
|
|
||||||
def sidebar_common():
|
def sidebar_common():
|
||||||
"partie commune à toutes les sidebar"
|
"partie commune à toutes les sidebar"
|
||||||
home_link = url_for("scodoc.index", scodoc_dept=g.scodoc_dept)
|
home_link = url_for("scodoc.index", scodoc_dept=g.scodoc_dept)
|
||||||
@ -129,13 +183,17 @@ def sidebar(etudid: int = None):
|
|||||||
)
|
)
|
||||||
H.append("<ul>")
|
H.append("<ul>")
|
||||||
if current_user.has_permission(Permission.AbsChange):
|
if current_user.has_permission(Permission.AbsChange):
|
||||||
|
# essaie de conserver le semestre actuellement en vue
|
||||||
|
cur_formsemestre_id = retreive_formsemestre_from_request()
|
||||||
H.append(
|
H.append(
|
||||||
f"""
|
f"""
|
||||||
<li><a href="{ url_for('assiduites.ajout_assiduite_etud',
|
<li><a href="{ url_for('assiduites.ajout_assiduite_etud',
|
||||||
scodoc_dept=g.scodoc_dept, etudid=etudid)
|
scodoc_dept=g.scodoc_dept, etudid=etudid)
|
||||||
}">Ajouter</a></li>
|
}">Ajouter</a></li>
|
||||||
<li><a href="{ url_for('assiduites.ajout_justificatif_etud',
|
<li><a href="{ url_for('assiduites.ajout_justificatif_etud',
|
||||||
scodoc_dept=g.scodoc_dept, etudid=etudid)
|
scodoc_dept=g.scodoc_dept, etudid=etudid,
|
||||||
|
formsemestre_id=cur_formsemestre_id,
|
||||||
|
)
|
||||||
}">Justifier</a></li>
|
}">Justifier</a></li>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@ -76,6 +76,7 @@ from app.scodoc import sco_moduleimpl
|
|||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc import sco_users
|
from app.scodoc import sco_users
|
||||||
from app.scodoc.gen_tables import GenTable
|
from app.scodoc.gen_tables import GenTable
|
||||||
|
from app.scodoc.html_sidebar import retreive_formsemestre_from_request
|
||||||
from app.scodoc.sco_formsemestre_custommenu import formsemestre_custommenu_html
|
from app.scodoc.sco_formsemestre_custommenu import formsemestre_custommenu_html
|
||||||
import sco_version
|
import sco_version
|
||||||
|
|
||||||
@ -476,57 +477,6 @@ def formsemestre_status_menubar(formsemestre: FormSemestre) -> str:
|
|||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
def retreive_formsemestre_from_request() -> int:
|
|
||||||
"""Cherche si on a de quoi déduire le semestre affiché à partir des
|
|
||||||
arguments de la requête:
|
|
||||||
formsemestre_id ou moduleimpl ou evaluation ou group_id ou partition_id
|
|
||||||
Returns None si pas défini.
|
|
||||||
"""
|
|
||||||
if request.method == "GET":
|
|
||||||
args = request.args
|
|
||||||
elif request.method == "POST":
|
|
||||||
args = request.form
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
formsemestre_id = None
|
|
||||||
# Search formsemestre
|
|
||||||
group_ids = args.get("group_ids", [])
|
|
||||||
if "formsemestre_id" in args:
|
|
||||||
formsemestre_id = args["formsemestre_id"]
|
|
||||||
elif "moduleimpl_id" in args and args["moduleimpl_id"]:
|
|
||||||
modimpl = sco_moduleimpl.moduleimpl_list(moduleimpl_id=args["moduleimpl_id"])
|
|
||||||
if not modimpl:
|
|
||||||
return None # suppressed ?
|
|
||||||
modimpl = modimpl[0]
|
|
||||||
formsemestre_id = modimpl["formsemestre_id"]
|
|
||||||
elif "evaluation_id" in args:
|
|
||||||
E = sco_evaluation_db.get_evaluations_dict(
|
|
||||||
{"evaluation_id": args["evaluation_id"]}
|
|
||||||
)
|
|
||||||
if not E:
|
|
||||||
return None # evaluation suppressed ?
|
|
||||||
E = E[0]
|
|
||||||
modimpl = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
|
||||||
formsemestre_id = modimpl["formsemestre_id"]
|
|
||||||
elif "group_id" in args:
|
|
||||||
group = sco_groups.get_group(args["group_id"])
|
|
||||||
formsemestre_id = group["formsemestre_id"]
|
|
||||||
elif group_ids:
|
|
||||||
if isinstance(group_ids, str):
|
|
||||||
group_ids = group_ids.split(",")
|
|
||||||
group_id = group_ids[0]
|
|
||||||
group = sco_groups.get_group(group_id)
|
|
||||||
formsemestre_id = group["formsemestre_id"]
|
|
||||||
elif "partition_id" in args:
|
|
||||||
partition = sco_groups.get_partition(args["partition_id"])
|
|
||||||
formsemestre_id = partition["formsemestre_id"]
|
|
||||||
|
|
||||||
if not formsemestre_id:
|
|
||||||
return None # no current formsemestre
|
|
||||||
|
|
||||||
return int(formsemestre_id)
|
|
||||||
|
|
||||||
|
|
||||||
# Element HTML decrivant un semestre (barre de menu et infos)
|
# Element HTML decrivant un semestre (barre de menu et infos)
|
||||||
def formsemestre_page_title(formsemestre_id=None):
|
def formsemestre_page_title(formsemestre_id=None):
|
||||||
"""Element HTML decrivant un semestre (barre de menu et infos)
|
"""Element HTML decrivant un semestre (barre de menu et infos)
|
||||||
|
@ -46,11 +46,11 @@ from app.scodoc import (
|
|||||||
sco_bac,
|
sco_bac,
|
||||||
sco_cursus,
|
sco_cursus,
|
||||||
sco_etud,
|
sco_etud,
|
||||||
sco_formsemestre_status,
|
|
||||||
sco_groups,
|
sco_groups,
|
||||||
sco_permissions_check,
|
sco_permissions_check,
|
||||||
sco_report,
|
sco_report,
|
||||||
)
|
)
|
||||||
|
from app.scodoc.html_sidebar import retreive_formsemestre_from_request
|
||||||
from app.scodoc.sco_bulletins import etud_descr_situation_semestre
|
from app.scodoc.sco_bulletins import etud_descr_situation_semestre
|
||||||
from app.scodoc.sco_exceptions import ScoValueError
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
from app.scodoc.sco_formsemestre_validation import formsemestre_recap_parcours_table
|
from app.scodoc.sco_formsemestre_validation import formsemestre_recap_parcours_table
|
||||||
@ -751,7 +751,7 @@ def etud_info_html(etudid, with_photo="1", debug=False):
|
|||||||
"""An HTML div with basic information and links about this etud.
|
"""An HTML div with basic information and links about this etud.
|
||||||
Used for popups information windows.
|
Used for popups information windows.
|
||||||
"""
|
"""
|
||||||
formsemestre_id = sco_formsemestre_status.retreive_formsemestre_from_request()
|
formsemestre_id = retreive_formsemestre_from_request()
|
||||||
with_photo = int(with_photo)
|
with_photo = int(with_photo)
|
||||||
etud = Identite.get_etud(etudid)
|
etud = Identite.get_etud(etudid)
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ _SCO_PERMISSIONS = (
|
|||||||
(1 << 10, "EditAllNotes", "Modifier toutes les notes"),
|
(1 << 10, "EditAllNotes", "Modifier toutes les notes"),
|
||||||
(1 << 11, "EditAllEvals", "Modifier toutes les évaluations"),
|
(1 << 11, "EditAllEvals", "Modifier toutes les évaluations"),
|
||||||
(1 << 12, "EditFormSemestre", "Mettre en place une formation (créer un semestre)"),
|
(1 << 12, "EditFormSemestre", "Mettre en place une formation (créer un semestre)"),
|
||||||
(1 << 13, "AbsChange", "Saisir des absences"),
|
(1 << 13, "AbsChange", "Saisir des absences ou justificatifs"),
|
||||||
(1 << 14, "AbsAddBillet", "Saisir des billets d'absences"),
|
(1 << 14, "AbsAddBillet", "Saisir des billets d'absences"),
|
||||||
# changer adresse/photo ou pour envoyer bulletins par mail ou pour debouche
|
# changer adresse/photo ou pour envoyer bulletins par mail ou pour debouche
|
||||||
(1 << 15, "EtudChangeAdr", "Changer les adresses d'étudiants"),
|
(1 << 15, "EtudChangeAdr", "Changer les adresses d'étudiants"),
|
||||||
@ -63,7 +63,11 @@ _SCO_PERMISSIONS = (
|
|||||||
#
|
#
|
||||||
# XXX inutilisée ? (1 << 40, "EtudChangePhoto", "Modifier la photo d'un étudiant"),
|
# XXX inutilisée ? (1 << 40, "EtudChangePhoto", "Modifier la photo d'un étudiant"),
|
||||||
# Permissions du module Assiduité)
|
# Permissions du module Assiduité)
|
||||||
(1 << 50, "AbsJustifView", "Visualisation des fichiers justificatifs"),
|
(
|
||||||
|
1 << 50,
|
||||||
|
"AbsJustifView",
|
||||||
|
"Visualisation du détail des justificatifs (motif, fichiers)",
|
||||||
|
),
|
||||||
# Attention: les permissions sont codées sur 64 bits.
|
# Attention: les permissions sont codées sur 64 bits.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
|
from flask_login import current_user
|
||||||
from flask_sqlalchemy.query import Query
|
from flask_sqlalchemy.query import Query
|
||||||
from sqlalchemy import desc, literal, union, asc
|
from sqlalchemy import desc, literal, union, asc
|
||||||
|
|
||||||
@ -10,6 +11,7 @@ from app.models import Assiduite, Identite, Justificatif
|
|||||||
from app.scodoc.sco_utils import EtatAssiduite, EtatJustificatif, to_bool
|
from app.scodoc.sco_utils import EtatAssiduite, EtatJustificatif, to_bool
|
||||||
from app.tables import table_builder as tb
|
from app.tables import table_builder as tb
|
||||||
from app.scodoc.sco_cache import RequeteTableauAssiduiteCache
|
from app.scodoc.sco_cache import RequeteTableauAssiduiteCache
|
||||||
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
|
||||||
|
|
||||||
class Pagination:
|
class Pagination:
|
||||||
@ -107,6 +109,11 @@ class ListeAssiJusti(tb.Table):
|
|||||||
|
|
||||||
self.total_page: int = None
|
self.total_page: int = None
|
||||||
|
|
||||||
|
# Accès aux détail des justificatifs ?
|
||||||
|
self.can_view_justif_detail = current_user.has_permission(
|
||||||
|
Permission.AbsJustifView
|
||||||
|
)
|
||||||
|
|
||||||
# les lignes du tableau
|
# les lignes du tableau
|
||||||
self.rows: list["RowAssiJusti"] = []
|
self.rows: list["RowAssiJusti"] = []
|
||||||
|
|
||||||
@ -342,7 +349,7 @@ class RowAssiJusti(tb.Row):
|
|||||||
# Type d'objet
|
# Type d'objet
|
||||||
self._type()
|
self._type()
|
||||||
|
|
||||||
# En excel, on export les "vraes dates".
|
# En excel, on export les "vraies dates".
|
||||||
# En HTML, on écrit en français (on laisse les dates pour le tri)
|
# En HTML, on écrit en français (on laisse les dates pour le tri)
|
||||||
|
|
||||||
multi_days = self.ligne["date_debut"].date() != self.ligne["date_fin"].date()
|
multi_days = self.ligne["date_debut"].date() != self.ligne["date_fin"].date()
|
||||||
@ -470,10 +477,21 @@ class RowAssiJusti(tb.Row):
|
|||||||
|
|
||||||
def _optionnelles(self) -> None:
|
def _optionnelles(self) -> None:
|
||||||
if self.table.options.show_desc:
|
if self.table.options.show_desc:
|
||||||
|
if self.ligne.get("type") == "justificatif":
|
||||||
|
# protection de la "raison"
|
||||||
|
if (
|
||||||
|
self.ligne["user_id"] == current_user.id
|
||||||
|
or self.table.can_view_justif_detail
|
||||||
|
):
|
||||||
|
description = self.ligne["desc"] if self.ligne["desc"] else ""
|
||||||
|
else:
|
||||||
|
description = "(cachée)"
|
||||||
|
else:
|
||||||
|
description = self.ligne["desc"] if self.ligne["desc"] else ""
|
||||||
self.add_cell(
|
self.add_cell(
|
||||||
"description",
|
"description",
|
||||||
"Description",
|
"Description",
|
||||||
self.ligne["desc"] if self.ligne["desc"] else "",
|
description,
|
||||||
)
|
)
|
||||||
if self.table.options.show_module:
|
if self.table.options.show_module:
|
||||||
if self.ligne["type"] == "assiduite":
|
if self.ligne["type"] == "assiduite":
|
||||||
|
@ -17,6 +17,9 @@ form#ajout-justificatif-etud {
|
|||||||
form#ajout-justificatif-etud > div {
|
form#ajout-justificatif-etud > div {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
fieldset > div {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
div.fichiers {
|
div.fichiers {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
margin-bottom: 32px;
|
margin-bottom: 32px;
|
||||||
@ -33,9 +36,20 @@ div.submit {
|
|||||||
div.submit > input {
|
div.submit > input {
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
}
|
}
|
||||||
|
.info-saisie {
|
||||||
|
margin-top: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<h2>Justifier des absences ou retards</h2>
|
<h2>{{title|safe}}</h2>
|
||||||
|
|
||||||
|
{% if justif %}
|
||||||
|
<div class="info-saisie">
|
||||||
|
Saisie par {{justif.user.get_prenomnom()}} le {{justif.entry_date.strftime("%d/%m/%Y à %H:%M")}}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<section class="justi-form page">
|
<section class="justi-form page">
|
||||||
|
|
||||||
@ -72,16 +86,24 @@ div.submit > input {
|
|||||||
</div>
|
</div>
|
||||||
{# Raison #}
|
{# Raison #}
|
||||||
<div>
|
<div>
|
||||||
<div>{{ form.raison.label }}</div>
|
{% if (not justif) or can_view_justif_detail %}
|
||||||
{{ form.raison() }}
|
<div>{{ form.raison.label }}</div>
|
||||||
{{ render_field_errors(form, 'raison') }}
|
{{ form.raison() }}
|
||||||
|
{{ render_field_errors(form, 'raison') }}
|
||||||
|
<div class="help">La raison sera visible aux utilisateurs ayant le droit
|
||||||
|
<tt>AbsJustifView</tt> et à celui ayant déposé le justificatif
|
||||||
|
{%- if justif %} (<b>{{justif.user.get_prenomnom()}}</b>){%- endif -%}.
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="unauthorized">raison confidentielle</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="fichiers">
|
<div class="fichiers">
|
||||||
{# Liste des fichiers existants #}
|
{# Liste des fichiers existants #}
|
||||||
{% if justif and nb_files > 0 %}
|
{% if justif and nb_files > 0 %}
|
||||||
<div><b>{{nb_files}} fichiers justificatifs déposés
|
<div><b>{{nb_files}} fichiers justificatifs déposés
|
||||||
{% if filenames|length < nb_files %}
|
{% if filenames|length < nb_files %}
|
||||||
, dont {{filenames|length}} vous sont accessibles
|
, dont {{filenames|length}} vous {{'sont accessibles' if filenames|length > 1 else 'est accessible'}}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</b>
|
</b>
|
||||||
</div>
|
</div>
|
||||||
@ -104,6 +126,7 @@ div.submit > input {
|
|||||||
{{ form.entry_date.label }} : {{ form.entry_date }}
|
{{ form.entry_date.label }} : {{ form.entry_date }}
|
||||||
<span class="help">laisser vide pour date courante</span>
|
<span class="help">laisser vide pour date courante</span>
|
||||||
{{ render_field_errors(form, 'entry_date') }}
|
{{ render_field_errors(form, 'entry_date') }}
|
||||||
|
|
||||||
{# Submit #}
|
{# Submit #}
|
||||||
<div class="submit">
|
<div class="submit">
|
||||||
{{ form.submit }} {{ form.cancel }}
|
{{ form.submit }} {{ form.cancel }}
|
||||||
|
@ -10,11 +10,11 @@
|
|||||||
|
|
||||||
{% if action == "modifier" %}
|
{% if action == "modifier" %}
|
||||||
{% include "assiduites/widgets/tableau_actions/modifier.j2" %}
|
{% include "assiduites/widgets/tableau_actions/modifier.j2" %}
|
||||||
{% else%}
|
{% else %}
|
||||||
{% include "assiduites/widgets/tableau_actions/details.j2" %}
|
{% include "assiduites/widgets/tableau_actions/details.j2" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if not current_user.has_permission(sco.Permission.AbsJustifView)%}
|
{% if not current_user.has_permission(sco.Permission.AbsJustifView) %}
|
||||||
<div class="help fontred" style="margin-top: 16px;">
|
<div class="help fontred" style="margin-top: 16px;">
|
||||||
Vous n'avez pas la permission d'ouvrir les fichiers justificatifs
|
Vous n'avez pas la permission d'ouvrir les fichiers justificatifs
|
||||||
déposés par d'autres personnes.
|
déposés par d'autres personnes.
|
||||||
@ -22,7 +22,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div style="margin-top: 32px;">
|
<div style="margin-top: 32px;">
|
||||||
<a href="" id="lien-retour">retour</a>
|
<a class="stdlink" href="" id="lien-retour">retour</a>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
|
@ -1,13 +1,36 @@
|
|||||||
<h2>Détails {{type}}</h2>
|
<h2>Détails {{type}} concernant <span class="etudinfo"
|
||||||
|
id="etudid-{{objet.etudid}}">{{etud.html_link_fiche()|safe}}</span></h2>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.info-row {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
.info-label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.info-etat {
|
||||||
|
font-size: 110%;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: rgb(253, 234, 210);
|
||||||
|
border: 1px solid grey;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
.info-saisie {
|
||||||
|
margin-top: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<div id="informations">
|
<div id="informations">
|
||||||
<div class="info-row">
|
|
||||||
<span class="info-label">Étudiant{{etud.e}} concerné{{etud.e}}:</span> <span class="etudinfo"
|
<div class="info-saisie">
|
||||||
id="etudid-{{objet.etudid}}">{{etud.html_link_fiche()|safe}}</span>
|
<span>Saisie par {{objet.saisie_par}} le {{objet.entry_date}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="info-row">
|
<div class="info-row">
|
||||||
<span class="info-label">Période :</span> {{objet.date_debut}} au {{objet.date_fin}}
|
<span class="info-label">Période :</span> du <b>{{objet.date_debut}}</b> au <b>{{objet.date_fin}}</b>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if type == "Assiduité" %}
|
{% if type == "Assiduité" %}
|
||||||
@ -23,27 +46,27 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<span class="info-label">État de l'assiduité :</span>
|
<span class="info-label">État de l'assiduité :</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<b>{{objet.etat}}</b>
|
<span class="info-etat">{{objet.etat}}</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="info-row">
|
<div class="info-row">
|
||||||
{% if type == "Justificatif" %}
|
{% if type == "Justificatif" %}
|
||||||
<div class="info-label">Raison:</div>
|
<span class="info-label">Raison:</span>
|
||||||
{% if objet.raison != None %}
|
{% if can_view_justif_detail %}
|
||||||
<div class="text">{{objet.raison}}</div>
|
<span class="text">{{objet.raison or " "}}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text unauthorized">(cachée)</span>
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="text">/div>
|
<span class="info-label">Description:</span>
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
<div class="info-label">Description:</div>
|
|
||||||
{% if objet.description != None %}
|
{% if objet.description != None %}
|
||||||
<div class="text">{{objet.description}}</div>
|
<span class="text">{{objet.description}}</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="text"></div>
|
<span class="text"></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Affichage des justificatifs si assiduité justifiée #}
|
{# Affichage des justificatifs si assiduité justifiée #}
|
||||||
@ -54,7 +77,8 @@
|
|||||||
<span class="text">Oui</span>
|
<span class="text">Oui</span>
|
||||||
<div>
|
<div>
|
||||||
{% for justi in objet.justification.justificatifs %}
|
{% for justi in objet.justification.justificatifs %}
|
||||||
<a href="{{url_for('assiduites.tableau_assiduite_actions', type='justificatif', action='details', obj_id=justi.justif_id, scodoc_dept=g.scodoc_dept)}}"
|
<a href="{{url_for('assiduites.tableau_assiduite_actions',
|
||||||
|
type='justificatif', action='details', obj_id=justi.justif_id, scodoc_dept=g.scodoc_dept)}}"
|
||||||
target="_blank" rel="noopener noreferrer">Justificatif du {{justi.date_debut}} au {{justi.date_fin}}</a>
|
target="_blank" rel="noopener noreferrer">Justificatif du {{justi.date_debut}} au {{justi.date_fin}}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
@ -69,13 +93,15 @@
|
|||||||
<div class="info-row">
|
<div class="info-row">
|
||||||
<span class="info-label">Assiduités concernées: </span>
|
<span class="info-label">Assiduités concernées: </span>
|
||||||
{% if objet.justification.assiduites %}
|
{% if objet.justification.assiduites %}
|
||||||
<div>
|
<ul>
|
||||||
{% for assi in objet.justification.assiduites %}
|
{% for assi in objet.justification.assiduites %}
|
||||||
<a href="{{url_for('assiduites.tableau_assiduite_actions', type='assiduite', action='details', obj_id=assi.assiduite_id, scodoc_dept=g.scodoc_dept)}}"
|
<li><a href="{{url_for('assiduites.tableau_assiduite_actions',
|
||||||
target="_blank">Assiduité {{assi.etat}} du {{assi.date_debut}} au
|
type='assiduite', action='details', obj_id=assi.assiduite_id, scodoc_dept=g.scodoc_dept)
|
||||||
|
}}" target="_blank">Assiduité {{assi.etat}} du {{assi.date_debut}} au
|
||||||
{{assi.date_fin}}</a>
|
{{assi.date_fin}}</a>
|
||||||
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</ul>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="text">Aucune</span>
|
<span class="text">Aucune</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -84,27 +110,31 @@
|
|||||||
|
|
||||||
{# Affichage des fichiers des justificatifs #}
|
{# Affichage des fichiers des justificatifs #}
|
||||||
{% if type == "Justificatif"%}
|
{% if type == "Justificatif"%}
|
||||||
<div class="info-row">
|
<div class="info-row">
|
||||||
<span class="info-label">Fichiers enregistrés: </span>
|
<span class="info-label">Fichiers enregistrés: </span>
|
||||||
{% if objet.justification.fichiers.total != 0 %}
|
{% if objet.justification.fichiers.total != 0 %}
|
||||||
<div>Total : {{objet.justification.fichiers.total}} </div>
|
<div>Total : {{objet.justification.fichiers.total}} </div>
|
||||||
<ul>
|
<ul>
|
||||||
{% for filename in objet.justification.fichiers.filenames %}
|
{% for filename in objet.justification.fichiers.filenames %}
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="{{url_for('apiweb.justif_export',justif_id=objet.justif_id,filename=filename, scodoc_dept=g.scodoc_dept)}}">{{filename}}</a>
|
href="{{url_for('apiweb.justif_export',justif_id=objet.justif_id,
|
||||||
</li>
|
filename=filename, scodoc_dept=g.scodoc_dept)}}">{{filename}}</a>
|
||||||
{% endfor %}
|
</li>
|
||||||
{% if not objet.justification.fichiers.filenames %}
|
{% endfor %}
|
||||||
<li class="fontred">fichiers non visibles</li>
|
{% if not objet.justification.fichiers.filenames %}
|
||||||
|
<li class="fontred">fichiers non visibles</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<span class="text">Aucun</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</div>
|
||||||
{% else %}
|
{% if current_user.has_permission(sco.Permission.AbsChange) %}
|
||||||
<span class="text">Aucun</span>
|
<div><a class="stdlink" href="{{
|
||||||
|
url_for('assiduites.edit_justificatif_etud', scodoc_dept=g.scodoc_dept, justif_id=obj_id)
|
||||||
|
}}">modifier ce justificatif</a>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</div>
|
||||||
<div class="info-row">
|
|
||||||
<span>Saisie par {{objet.saisie_par}} le {{objet.entry_date}}</span>
|
|
||||||
</div>
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<h2>Modifier {{objet_name}} de {{ etud.html_link_fiche() | safe }}</h2>
|
<h2>Modifier {{objet_name}} de {{ etud.html_link_fiche() | safe }}</h2>
|
||||||
|
|
||||||
|
{# XXX cette page ne semble plus utile ! remplacée par edit_justificatif_etud #}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
Actuellement noté{{etud.e}} en <b>{{objet_name|lower()}}</b> du {{objet.date_debut}} au {{objet.date_fin}}
|
Actuellement noté{{etud.e}} en <b>{{objet_name|lower()}}</b> du {{objet.date_debut}} au {{objet.date_fin}}
|
||||||
</div>
|
</div>
|
||||||
@ -39,8 +41,12 @@ Actuellement noté{{etud.e}} en <b>{{objet_name|lower()}}</b> du {{objet.date_de
|
|||||||
<option value="modifie">Modifié</option>
|
<option value="modifie">Modifié</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<legend for="raison">Raison</legend>
|
{% if current_user.has_permission(sco.Permission.AbsJustifView) %}
|
||||||
<textarea name="raison" id="raison" cols="50" rows="5">{{objet.raison}}</textarea>
|
<legend for="raison">Raison</legend>
|
||||||
|
<textarea name="raison" id="raison" cols="50" rows="5">{{objet.raison}}</textarea>
|
||||||
|
{% else %}
|
||||||
|
<div class="unauthorized">(raison non visible ni modifiable)</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<legend>Fichiers</legend>
|
<legend>Fichiers</legend>
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{# -*- mode: jinja-html -*- #}
|
{# -*- mode: jinja-html -*- #}
|
||||||
<h2 class="insidebar"><a href="{{
|
<h2 class="insidebar"><a href="{{
|
||||||
url_for('scolar.index_html', scodoc_dept=g.scodoc_dept)
|
url_for('scolar.index_html', scodoc_dept=g.scodoc_dept)
|
||||||
}}">Dépt. {{ prefs["DeptName"] }}</a>
|
}}">Dépt. {{ prefs["DeptName"] }}</a>
|
||||||
</h2>
|
</h2>
|
||||||
{% if prefs["DeptIntranetURL"] %}
|
{% if prefs["DeptIntranetURL"] %}
|
||||||
@ -8,8 +8,3 @@
|
|||||||
{{ prefs["DeptIntranetTitle"] }}</a>
|
{{ prefs["DeptIntranetTitle"] }}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
{#
|
|
||||||
# Entreprises pas encore supporté en ScoDoc8
|
|
||||||
# <br /><a href="%(ScoURL)s/Entreprises" class="sidebar">Entreprises</a> <br />
|
|
||||||
#}
|
|
@ -14,6 +14,7 @@ from app.scodoc import notesdb as ndb
|
|||||||
from app.scodoc import sco_assiduites
|
from app.scodoc import sco_assiduites
|
||||||
from app.scodoc import sco_formsemestre_status
|
from app.scodoc import sco_formsemestre_status
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
|
from app.scodoc.html_sidebar import retreive_formsemestre_from_request
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
import sco_version
|
import sco_version
|
||||||
@ -90,9 +91,7 @@ class ScoData:
|
|||||||
self.etud = None
|
self.etud = None
|
||||||
# --- Informations sur semestre courant, si sélectionné
|
# --- Informations sur semestre courant, si sélectionné
|
||||||
if formsemestre is None:
|
if formsemestre is None:
|
||||||
formsemestre_id = (
|
formsemestre_id = retreive_formsemestre_from_request()
|
||||||
sco_formsemestre_status.retreive_formsemestre_from_request()
|
|
||||||
)
|
|
||||||
if formsemestre_id is not None:
|
if formsemestre_id is not None:
|
||||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||||
if formsemestre is None:
|
if formsemestre is None:
|
||||||
|
@ -31,6 +31,7 @@ from typing import Any
|
|||||||
from flask import g, request, render_template, flash
|
from flask import g, request, render_template, flash
|
||||||
from flask import abort, url_for, redirect, Response
|
from flask import abort, url_for, redirect, Response
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
from flask_sqlalchemy.query import Query
|
||||||
|
|
||||||
from app import db, log
|
from app import db, log
|
||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
@ -81,7 +82,6 @@ from app.scodoc.sco_exceptions import ScoValueError
|
|||||||
from app.tables.visu_assiduites import TableAssi, etuds_sorted_from_ids
|
from app.tables.visu_assiduites import TableAssi, etuds_sorted_from_ids
|
||||||
from app.scodoc.sco_archives_justificatifs import JustificatifArchiver
|
from app.scodoc.sco_archives_justificatifs import JustificatifArchiver
|
||||||
|
|
||||||
from flask_sqlalchemy.query import Query
|
|
||||||
|
|
||||||
CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS
|
CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS
|
||||||
|
|
||||||
@ -663,7 +663,9 @@ def bilan_etud():
|
|||||||
@permission_required(Permission.AbsChange)
|
@permission_required(Permission.AbsChange)
|
||||||
def edit_justificatif_etud(justif_id: int):
|
def edit_justificatif_etud(justif_id: int):
|
||||||
"""
|
"""
|
||||||
Edition d'un justificatif
|
Edition d'un justificatif.
|
||||||
|
Il faut de plus la permission pour voir/modifier la raison.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
justif_id (int): l'identifiant du justificatif
|
justif_id (int): l'identifiant du justificatif
|
||||||
|
|
||||||
@ -704,21 +706,21 @@ def edit_justificatif_etud(justif_id: int):
|
|||||||
"assi_limit_annee",
|
"assi_limit_annee",
|
||||||
dept_id=g.scodoc_dept_id,
|
dept_id=g.scodoc_dept_id,
|
||||||
),
|
),
|
||||||
|
can_view_justif_detail=current_user.has_permission(Permission.AbsJustifView)
|
||||||
|
or current_user.id == justif.user_id,
|
||||||
etud=justif.etudiant,
|
etud=justif.etudiant,
|
||||||
filenames=filenames,
|
filenames=filenames,
|
||||||
form=form,
|
form=form,
|
||||||
justif=justif,
|
justif=justif,
|
||||||
nb_files=nb_files,
|
nb_files=nb_files,
|
||||||
page_title="Modification justificatif",
|
title=f"Modification justificatif absence de {justif.etudiant.html_link_fiche()}",
|
||||||
redirect_url=redirect_url,
|
redirect_url=redirect_url,
|
||||||
sco=ScoData(justif.etudiant),
|
sco=ScoData(justif.etudiant),
|
||||||
scu=scu,
|
scu=scu,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route(
|
@bp.route("/ajout_justificatif_etud", methods=["GET", "POST"])
|
||||||
"/ajout_justificatif_etud", methods=["GET", "POST"]
|
|
||||||
) # was AjoutJustificatifEtud
|
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.AbsChange)
|
@permission_required(Permission.AbsChange)
|
||||||
def ajout_justificatif_etud():
|
def ajout_justificatif_etud():
|
||||||
@ -766,7 +768,7 @@ def ajout_justificatif_etud():
|
|||||||
),
|
),
|
||||||
etud=etud,
|
etud=etud,
|
||||||
form=form,
|
form=form,
|
||||||
page_title="Justificatifs",
|
title=f"Ajout justificatif absence pour {etud.html_link_fiche()}",
|
||||||
redirect_url=redirect_url,
|
redirect_url=redirect_url,
|
||||||
sco=ScoData(etud),
|
sco=ScoData(etud),
|
||||||
scu=scu,
|
scu=scu,
|
||||||
@ -1642,15 +1644,18 @@ def tableau_assiduite_actions():
|
|||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"assiduites/pages/tableau_assiduite_actions.j2",
|
"assiduites/pages/tableau_assiduite_actions.j2",
|
||||||
|
action=action,
|
||||||
|
can_view_justif_detail=current_user.has_permission(Permission.AbsJustifView)
|
||||||
|
or (obj_type == "justificatif" and current_user.id == objet.user_id),
|
||||||
|
etud=objet.etudiant,
|
||||||
|
moduleimpl=module,
|
||||||
|
obj_id=obj_id,
|
||||||
|
objet_name=objet_name,
|
||||||
|
objet=_preparer_objet(obj_type, objet),
|
||||||
sco=ScoData(etud=objet.etudiant),
|
sco=ScoData(etud=objet.etudiant),
|
||||||
|
title=f"Assiduité {objet.etudiant.nom_short}",
|
||||||
# type utilisé dans les actions modifier / détails (modifier.j2, details.j2)
|
# type utilisé dans les actions modifier / détails (modifier.j2, details.j2)
|
||||||
type="Justificatif" if obj_type == "justificatif" else "Assiduité",
|
type="Justificatif" if obj_type == "justificatif" else "Assiduité",
|
||||||
action=action,
|
|
||||||
etud=objet.etudiant,
|
|
||||||
objet=_preparer_objet(obj_type, objet),
|
|
||||||
objet_name=objet_name,
|
|
||||||
obj_id=obj_id,
|
|
||||||
moduleimpl=module,
|
|
||||||
)
|
)
|
||||||
# ----- Cas POST
|
# ----- Cas POST
|
||||||
if obj_type == "assiduite":
|
if obj_type == "assiduite":
|
||||||
@ -2446,12 +2451,12 @@ class Jour:
|
|||||||
self, matin: bool, show_pres: bool = False, show_reta: bool = False
|
self, matin: bool, show_pres: bool = False, show_reta: bool = False
|
||||||
) -> str:
|
) -> str:
|
||||||
# Transformation d'une heure "HH:MM" en time(h,m)
|
# Transformation d'une heure "HH:MM" en time(h,m)
|
||||||
STR_TIME = lambda x: datetime.time(*list(map(int, x.split(":"))))
|
str2time = lambda x: datetime.time(*list(map(int, x.split(":"))))
|
||||||
|
|
||||||
heure_midi = STR_TIME(ScoDocSiteConfig.get("assi_lunch_time", "13:00"))
|
heure_midi = str2time(ScoDocSiteConfig.get("assi_lunch_time", "13:00"))
|
||||||
|
|
||||||
if matin:
|
if matin:
|
||||||
heure_matin = STR_TIME(ScoDocSiteConfig.get("assi_morning_time", "08:00"))
|
heure_matin = str2time(ScoDocSiteConfig.get("assi_morning_time", "08:00"))
|
||||||
matin = (
|
matin = (
|
||||||
# date debut
|
# date debut
|
||||||
scu.localize_datetime(
|
scu.localize_datetime(
|
||||||
@ -2483,7 +2488,7 @@ class Jour:
|
|||||||
|
|
||||||
return f"color {etat} {est_just}"
|
return f"color {etat} {est_just}"
|
||||||
|
|
||||||
heure_soir = STR_TIME(ScoDocSiteConfig.get("assi_afternoon_time", "17:00"))
|
heure_soir = str2time(ScoDocSiteConfig.get("assi_afternoon_time", "17:00"))
|
||||||
|
|
||||||
# séparation en demi journées
|
# séparation en demi journées
|
||||||
aprem = (
|
aprem = (
|
||||||
@ -2522,17 +2527,17 @@ class Jour:
|
|||||||
|
|
||||||
def generate_minitimeline(self) -> str:
|
def generate_minitimeline(self) -> str:
|
||||||
# Récupérer le référenciel de la timeline
|
# Récupérer le référenciel de la timeline
|
||||||
STR_TIME = lambda x: _time_to_timedelta(
|
str2time = lambda x: _time_to_timedelta(
|
||||||
datetime.time(*list(map(int, x.split(":"))))
|
datetime.time(*list(map(int, x.split(":"))))
|
||||||
)
|
)
|
||||||
|
|
||||||
heure_matin: datetime.timedelta = STR_TIME(
|
heure_matin: datetime.timedelta = str2time(
|
||||||
ScoDocSiteConfig.get("assi_morning_time", "08:00")
|
ScoDocSiteConfig.get("assi_morning_time", "08:00")
|
||||||
)
|
)
|
||||||
heure_midi: datetime.timedelta = STR_TIME(
|
heure_midi: datetime.timedelta = str2time(
|
||||||
ScoDocSiteConfig.get("assi_lun_time", "13:00")
|
ScoDocSiteConfig.get("assi_lun_time", "13:00")
|
||||||
)
|
)
|
||||||
heure_soir: datetime.timedelta = STR_TIME(
|
heure_soir: datetime.timedelta = str2time(
|
||||||
ScoDocSiteConfig.get("assi_afternoon_time", "17:00")
|
ScoDocSiteConfig.get("assi_afternoon_time", "17:00")
|
||||||
)
|
)
|
||||||
# longueur_timeline = heure_soir - heure_matin
|
# longueur_timeline = heure_soir - heure_matin
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.6.79"
|
SCOVERSION = "9.6.80"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user