Base multi-départements. En cours

This commit is contained in:
Emmanuel Viennet 2021-08-13 00:34:58 +02:00
parent 317d60d447
commit 486f20d7f7
34 changed files with 471 additions and 110 deletions

View File

@ -23,9 +23,6 @@ from flask_caching import Cache
from config import DevConfig from config import DevConfig
from app.scodoc import notesdb as ndb
from app.scodoc import sco_cache
db = SQLAlchemy() db = SQLAlchemy()
migrate = Migrate() migrate = Migrate()
login = LoginManager() login = LoginManager()
@ -131,6 +128,18 @@ def create_app(config_class=DevConfig):
return app return app
def set_sco_dept(scodoc_dept: str):
"""Set global g object to given dept and open db connection if needed"""
# Check that dept exists
dept = Departement.query.filter_by(acronym=scodoc_dept).first()
if not dept:
raise ScoValueError(f"Invalid dept: {scodoc_dept}")
g.scodoc_dept = scodoc_dept # l'acronyme
g.scodoc_dept_id = dept.id # l'id
if not hasattr(g, "db_conn"):
ndb.open_db_connection()
def user_db_init(): def user_db_init():
"""Initialize the users database.""" """Initialize the users database."""
from app.auth.models import User, Role from app.auth.models import User, Role
@ -214,8 +223,14 @@ def clear_scodoc_cache():
r = redis.Redis() r = redis.Redis()
r.flushall() r.flushall()
# Also clear local caches:
sco_preferences.clear_base_preferences()
from app.models import Departement
from app.scodoc import notesdb as ndb, sco_preferences
from app.scodoc import sco_cache
# admin_role = Role.query.filter_by(name="SuperAdmin").first() # admin_role = Role.query.filter_by(name="SuperAdmin").first()
# if admin_role: # if admin_role:
# admin = ( # admin = (

View File

@ -98,10 +98,37 @@ class ZResponse(object):
self.headers[header.lower()] = value self.headers[header.lower()] = value
def scodoc(func):
"""Décorateur pour toutes les fonctions ScoDoc
Affecte le département à g
et ouvre la connexion à la base
Set `g.scodoc_dept` and `g.scodoc_dept_id` if `scodoc_dept` is present
in the argument (for routes like
`/<scodoc_dept>/Scolarite/sco_exemple`).
"""
@wraps(func)
def scodoc_function(*args, **kwargs):
if "scodoc_dept" in kwargs:
dept_acronym = kwargs["scodoc_dept"]
current_app.logger.info("setting dept to " + dept_acronym)
app.set_sco_dept(dept_acronym)
del kwargs["scodoc_dept"]
elif not hasattr(g, "scodoc_dept"):
current_app.logger.info("setting dept to None")
g.scodoc_dept = None
g.scodoc_dept_id = -1 # invalide
return func(*args, **kwargs)
return scodoc_function
def permission_required(permission): def permission_required(permission):
def decorator(f): def decorator(f):
@wraps(f) @wraps(f)
def decorated_function(*args, **kwargs): def decorated_function(*args, **kwargs):
# current_app.logger.info("PERMISSION; kwargs=%s" % str(kwargs))
if "scodoc_dept" in kwargs: if "scodoc_dept" in kwargs:
g.scodoc_dept = kwargs["scodoc_dept"] g.scodoc_dept = kwargs["scodoc_dept"]
del kwargs["scodoc_dept"] del kwargs["scodoc_dept"]
@ -142,7 +169,6 @@ def scodoc7func(context):
2. or be called directly from Python. 2. or be called directly from Python.
If called via a route, this decorator setups a REQUEST object (emulating Zope2 REQUEST) If called via a route, this decorator setups a REQUEST object (emulating Zope2 REQUEST)
and `g.scodoc_dept` if present in the argument (for routes like `/<scodoc_dept>/Scolarite/sco_exemple`).
""" """
# Détermine si on est appelé via une route ("toplevel") # Détermine si on est appelé via une route ("toplevel")
# ou par un appel de fonction python normal. # ou par un appel de fonction python normal.
@ -150,14 +176,6 @@ def scodoc7func(context):
if not top_level: if not top_level:
# ne "redécore" pas # ne "redécore" pas
return func(*args, **kwargs) return func(*args, **kwargs)
#
if "scodoc_dept" in kwargs:
g.scodoc_dept = kwargs["scodoc_dept"]
del kwargs["scodoc_dept"]
elif not hasattr(g, "scodoc_dept"):
g.scodoc_dept = None
# --- Open DB connection
app.views.open_dept_db_connection()
# --- Emulate Zope's REQUEST # --- Emulate Zope's REQUEST
REQUEST = ZRequest() REQUEST = ZRequest()
g.zrequest = REQUEST g.zrequest = REQUEST

View File

@ -11,6 +11,9 @@ APO_CODE_STR_LEN = 16 # nb de car max d'un code Apogée
from app.models.raw_sql_init import create_database_functions from app.models.raw_sql_init import create_database_functions
from app.models.absences import Absence, AbsenceNotification, BilletAbsence from app.models.absences import Absence, AbsenceNotification, BilletAbsence
from app.models.departements import Departement
from app.models.entreprises import ( from app.models.entreprises import (
Entreprise, Entreprise,
EntrepriseCorrespondant, EntrepriseCorrespondant,
@ -56,4 +59,4 @@ from app.models.notes import (
NotesNotes, NotesNotes,
NotesNotesLog, NotesNotesLog,
) )
from app.models.preferences import ScoPreferences from app.models.preferences import ScoPreference

View File

@ -0,0 +1,36 @@
# -*- coding: UTF-8 -*
"""ScoDoc8 models : departements
"""
from typing import Any
from app import db
from app.models import SHORT_STR_LEN
class Departement(db.Model):
"""Un département ScoDoc"""
id = db.Column(db.Integer, primary_key=True)
acronym = db.Column(db.String(SHORT_STR_LEN), nullable=False, index=True)
description = db.Column(db.Text())
date_creation = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
visible = db.Column(
db.Boolean(), nullable=False, default=True, server_default="true"
) # sur page d'accueil
entreprises = db.relationship("Entreprise", lazy="dynamic", backref="departement")
etudiants = db.relationship("Identite", lazy="dynamic", backref="departement")
formations = db.relationship(
"NotesFormation", lazy="dynamic", backref="departement"
)
formsemestres = db.relationship(
"FormSemestre", lazy="dynamic", backref="departement"
)
preferences = db.relationship(
"ScoPreference", lazy="dynamic", backref="departement"
)
semsets = db.relationship("NotesSemSet", lazy="dynamic", backref="departement")
def __repr__(self):
return f"<Departement {self.acronym}>"

View File

@ -15,7 +15,7 @@ class Entreprise(db.Model):
__tablename__ = "entreprises" __tablename__ = "entreprises"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
entreprise_id = db.synonym("id") entreprise_id = db.synonym("id")
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True)
nom = db.Column(db.Text) nom = db.Column(db.Text)
adresse = db.Column(db.Text) adresse = db.Column(db.Text)
ville = db.Column(db.Text) ville = db.Column(db.Text)

View File

@ -17,6 +17,7 @@ class Identite(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
etudid = db.synonym("id") etudid = db.synonym("id")
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True)
nom = db.Column(db.Text()) nom = db.Column(db.Text())
prenom = db.Column(db.Text()) prenom = db.Column(db.Text())

View File

@ -15,6 +15,8 @@ class NotesFormation(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
formation_id = db.synonym("id") formation_id = db.synonym("id")
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True)
acronyme = db.Column(db.String(SHORT_STR_LEN), nullable=False) acronyme = db.Column(db.String(SHORT_STR_LEN), nullable=False)
titre = db.Column(db.Text(), nullable=False) titre = db.Column(db.Text(), nullable=False)
titre_officiel = db.Column(db.Text(), nullable=False) titre_officiel = db.Column(db.Text(), nullable=False)
@ -28,6 +30,8 @@ class NotesFormation(db.Model):
type_parcours = db.Column(db.Integer, default=0, server_default="0") type_parcours = db.Column(db.Integer, default=0, server_default="0")
code_specialite = db.Column(db.String(SHORT_STR_LEN)) code_specialite = db.Column(db.String(SHORT_STR_LEN))
formsemestres = db.relationship("FormSemestre", lazy="dynamic", backref="formation")
class NotesUE(db.Model): class NotesUE(db.Model):
"""Unité d'Enseignement""" """Unité d'Enseignement"""
@ -106,6 +110,8 @@ class NotesTag(db.Model):
__tablename__ = "notes_tags" __tablename__ = "notes_tags"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True)
tag_id = db.synonym("id") tag_id = db.synonym("id")
title = db.Column(db.String(SHORT_STR_LEN), nullable=False, unique=True) title = db.Column(db.String(SHORT_STR_LEN), nullable=False, unique=True)

View File

@ -19,6 +19,9 @@ class FormSemestre(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
formsemestre_id = db.synonym("id") formsemestre_id = db.synonym("id")
# dept_id est aussi dans la formation, ajpouté ici pour
# simplifier et accélérer les selects dans notesdb
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True)
formation_id = db.Column(db.Integer, db.ForeignKey("notes_formations.id")) formation_id = db.Column(db.Integer, db.ForeignKey("notes_formations.id"))
semestre_id = db.Column(db.Integer, nullable=False, default=1, server_default="1") semestre_id = db.Column(db.Integer, nullable=False, default=1, server_default="1")
titre = db.Column(db.Text()) titre = db.Column(db.Text())
@ -309,6 +312,8 @@ class NotesSemSet(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
semset_id = db.synonym("id") semset_id = db.synonym("id")
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"))
title = db.Column(db.Text) title = db.Column(db.Text)
annee_scolaire = db.Column(db.Integer, nullable=True, default=None) annee_scolaire = db.Column(db.Integer, nullable=True, default=None)
# periode: 0 (année), 1 (Simpair), 2 (Spair) # periode: 0 (année), 1 (Simpair), 2 (Spair)

View File

@ -2,17 +2,18 @@
"""Model : preferences """Model : preferences
""" """
from app import db from app import db
class ScoPreferences(db.Model): class ScoPreference(db.Model):
"""ScoDoc preferences""" """ScoDoc preferences"""
__tablename__ = "sco_prefs" __tablename__ = "sco_prefs"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
pref_id = db.synonym("id") pref_id = db.synonym("id")
dept = db.Column(db.String(16), index=True)
name = db.Column(db.String(128), nullable=False) dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"))
name = db.Column(db.String(128), nullable=False, index=True)
value = db.Column(db.Text()) value = db.Column(db.Text())
formsemestre_id = db.Column(db.Integer, db.ForeignKey("notes_formsemestre.id")) formsemestre_id = db.Column(db.Integer, db.ForeignKey("notes_formsemestre.id"))

View File

@ -7,8 +7,9 @@ import psycopg2
import psycopg2.pool import psycopg2.pool
import psycopg2.extras import psycopg2.extras
from flask import g from flask import g, current_app
import app
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc.notes_log import log from app.scodoc.notes_log import log
from app.scodoc.sco_exceptions import ScoException, ScoValueError, NoteProcessError from app.scodoc.sco_exceptions import ScoException, ScoValueError, NoteProcessError
@ -33,28 +34,17 @@ def unquote(s):
return s.replace("&amp;", "&") return s.replace("&amp;", "&")
def open_dept_connection(scodoc_dept=None): def open_db_connection():
"""Open a connection to the current dept db (g.scodoc_dept) """Open a connection to the database"""
or to the argument scodoc_dept g.db_conn = psycopg2.connect(current_app.config["SQLALCHEMY_DATABASE_URI"])
"""
return psycopg2.connect(scu.get_db_cnx_string(scodoc_dept))
def close_dept_connection(): def close_db_connection():
"""Commit and close dept db.""" """Commit and close database."""
# log("close_dept_connection to " + scu.get_db_cnx_string()) if hasattr(g, "db_conn"):
g.db_conn.commit() g.db_conn.commit()
g.db_conn.close() g.db_conn.close()
del g.db_conn
def set_sco_dept(scodoc_dept):
"""Set "context" to given dept
open db connection
"""
g.scodoc_dept = scodoc_dept
if hasattr(g, "db_conn"):
close_dept_connection()
g.db_conn = open_dept_connection()
def GetDBConnexion(autocommit=True): # on n'utilise plus autocommit def GetDBConnexion(autocommit=True): # on n'utilise plus autocommit
@ -277,6 +267,7 @@ class EditableTable(object):
html_quote=True, html_quote=True,
fields_creators={}, # { field : [ sql_command_to_create_it ] } fields_creators={}, # { field : [ sql_command_to_create_it ] }
filter_nulls=True, # dont allow to set fields to null filter_nulls=True, # dont allow to set fields to null
filter_dept=False, # ajoute selection sur g.scodoc_dept_id
): ):
self.table_name = table_name self.table_name = table_name
self.id_name = id_name self.id_name = id_name
@ -295,6 +286,7 @@ class EditableTable(object):
self.html_quote = html_quote self.html_quote = html_quote
self.fields_creators = fields_creators self.fields_creators = fields_creators
self.filter_nulls = filter_nulls self.filter_nulls = filter_nulls
self.filter_dept = filter_dept
self.sql_default_values = None self.sql_default_values = None
def create(self, cnx, args): def create(self, cnx, args):
@ -304,6 +296,8 @@ class EditableTable(object):
del vals[self.id_name] del vals[self.id_name]
if "id" in vals: if "id" in vals:
del vals["id"] del vals["id"]
if self.filter_dept:
vals["dept_id"] = g.scodoc_dept_id
if self.html_quote: if self.html_quote:
quote_dict(vals) # quote all HTML markup quote_dict(vals) # quote all HTML markup
# format value # format value
@ -334,6 +328,8 @@ class EditableTable(object):
vals = dictfilter(args, self.dbfields, self.filter_nulls) vals = dictfilter(args, self.dbfields, self.filter_nulls)
if (id_value is not None) and (not "id" in vals): if (id_value is not None) and (not "id" in vals):
vals["id"] = id_value vals["id"] = id_value
if self.filter_dept:
vals["dept_id"] = g.scodoc_dept_id
if not sortkey: if not sortkey:
sortkey = self.sortkey sortkey = self.sortkey
res = DBSelectArgs( res = DBSelectArgs(

View File

@ -118,7 +118,10 @@ def abs_notify_send(
msg["To"] = email msg["To"] = email
sco_emails.sendEmail(context, msg) sco_emails.sendEmail(context, msg)
ndb.SimpleQuery( ndb.SimpleQuery(
"""insert into absences_notifications (etudid, email, nbabs, nbabsjust, formsemestre_id) values (%(etudid)s, %(email)s, %(nbabs)s, %(nbabsjust)s, %(formsemestre_id)s)""", """insert into absences_notifications
(etudid, email, nbabs, nbabsjust, formsemestre_id)
VALUES (%(etudid)s, %(email)s, %(nbabs)s, %(nbabsjust)s, %(formsemestre_id)s)
""",
vars(), vars(),
cursor=cursor, cursor=cursor,
) )

View File

@ -138,9 +138,18 @@ class EvaluationCache(ScoDocCache):
@classmethod @classmethod
def invalidate_all_sems(cls): def invalidate_all_sems(cls):
"delete all evaluations from cache" "delete all evaluations in current dept from cache"
evaluation_ids = [ evaluation_ids = [
x[0] for x in ndb.SimpleQuery("SELECT id FROM notes_evaluation", "") x[0]
for x in ndb.SimpleQuery(
"""SELECT e.id
FROM notes_evaluation e, notes_moduleimpl mi, notes_formsemestre s
WHERE s.dept_id=%(dept_id)s
AND s.id = mi.formsemestre_id
AND mi.id = e.moduleimpl_id;
""",
{"dept_id": g.scodoc_dept_id},
)
] ]
cls.delete_many(evaluation_ids) cls.delete_many(evaluation_ids)
@ -243,7 +252,13 @@ def invalidate_formsemestre( # was inval_cache( context, formsemestre_id=None,
# clear all caches # clear all caches
log("----- invalidate_formsemestre: clearing all caches -----") log("----- invalidate_formsemestre: clearing all caches -----")
formsemestre_ids = [ formsemestre_ids = [
x[0] for x in ndb.SimpleQuery("SELECT id FROM notes_formsemestre", "") x[0]
for x in ndb.SimpleQuery(
"""SELECT id FROM notes_formsemestre s
WHERE s.dept_id=%(dept_id)s
""",
{"dept_id": g.scodoc_dept_id},
)
] ]
else: else:
formsemestre_ids = [ formsemestre_ids = [

View File

@ -65,7 +65,7 @@ SCO_DUMP_LOCK = "/tmp/scodump.lock"
def sco_dump_and_send_db(context, REQUEST=None): def sco_dump_and_send_db(context, REQUEST=None):
"""Dump base de données du département courant et l'envoie anonymisée pour debug""" """Dump base de données et l'envoie anonymisée pour debug"""
H = [html_sco_header.sco_header(page_title="Assistance technique")] H = [html_sco_header.sco_header(page_title="Assistance technique")]
# get currect (dept) DB name: # get currect (dept) DB name:
cursor = ndb.SimpleQuery("SELECT current_database()", {}) cursor = ndb.SimpleQuery("SELECT current_database()", {})
@ -75,7 +75,7 @@ def sco_dump_and_send_db(context, REQUEST=None):
try: try:
x = open(SCO_DUMP_LOCK, "w+") x = open(SCO_DUMP_LOCK, "w+")
fcntl.flock(x, fcntl.LOCK_EX | fcntl.LOCK_NB) fcntl.flock(x, fcntl.LOCK_EX | fcntl.LOCK_NB)
except (IOError, OSError): # exception changed from Python 2 to 3 except (IOError, OSError):
raise ScoValueError( raise ScoValueError(
"Un envoi de la base " "Un envoi de la base "
+ db_name + db_name

View File

@ -148,6 +148,7 @@ _entreprisesEditor = EntreprisesEditor(
"note", "note",
"date_creation", "date_creation",
), ),
filter_dept=True,
sortkey="nom", sortkey="nom",
input_formators={ input_formators={
"nom": _format_nom, "nom": _format_nom,

View File

@ -258,6 +258,7 @@ _identiteEditor = ndb.EditableTable(
"code_ine", "code_ine",
"code_nip", "code_nip",
), ),
filter_dept=True,
sortkey="nom", sortkey="nom",
input_formators={ input_formators={
"nom": force_uppercase, "nom": force_uppercase,

View File

@ -32,6 +32,7 @@ from flask import url_for, g
from flask_login import current_user from flask_login import current_user
from scodoc_manager import sco_mgr from scodoc_manager import sco_mgr
import app
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app.scodoc.gen_tables import GenTable from app.scodoc.gen_tables import GenTable
@ -48,7 +49,7 @@ def form_search_etud(
dest_url=None, dest_url=None,
parameters=None, parameters=None,
parameters_keys=None, parameters_keys=None,
title="Rechercher un &eacute;tudiant par nom&nbsp;: ", title="Rechercher un étudiant par nom&nbsp;: ",
add_headers=False, # complete page add_headers=False, # complete page
): ):
"form recherche par nom" "form recherche par nom"
@ -274,7 +275,7 @@ def search_etud_in_accessible_depts(expnom=None, code_nip=None):
if current_user.has_permission(Permission.ScoView, dept=dept): if current_user.has_permission(Permission.ScoView, dept=dept):
if expnom or code_nip: if expnom or code_nip:
accessible_depts.append(dept) accessible_depts.append(dept)
ndb.set_sco_dept(dept) app.set_sco_dept(dept)
etuds = search_etuds_infos(expnom=expnom, code_nip=code_nip) etuds = search_etuds_infos(expnom=expnom, code_nip=code_nip)
else: else:
etuds = [] etuds = []

View File

@ -64,6 +64,7 @@ _formationEditor = ndb.EditableTable(
"type_parcours", "type_parcours",
"code_specialite", "code_specialite",
), ),
filter_dept=True,
sortkey="acronyme", sortkey="acronyme",
) )

View File

@ -65,6 +65,7 @@ _formsemestreEditor = ndb.EditableTable(
"elt_sem_apo", "elt_sem_apo",
"elt_annee_apo", "elt_annee_apo",
), ),
filter_dept=True,
sortkey="date_debut", sortkey="date_debut",
output_formators={ output_formators={
"date_debut": ndb.DateISOtoDMY, "date_debut": ndb.DateISOtoDMY,

View File

@ -113,6 +113,7 @@ get_base_preferences(formsemestre_id)
import flask import flask
from flask import g from flask import g
from app.models import Departement
from app.scodoc import sco_cache from app.scodoc import sco_cache
from app.scodoc.notes_log import log from app.scodoc.notes_log import log
from app.scodoc.sco_exceptions import ScoValueError, ScoException from app.scodoc.sco_exceptions import ScoValueError, ScoException
@ -120,15 +121,22 @@ from app.scodoc.TrivialFormulator import TrivialFormulator
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
_SCO_BASE_PREFERENCES = {} # { URL: BasePreferences instance } _SCO_BASE_PREFERENCES = {} # { dept_acronym: BasePreferences instance }
def clear_base_preferences():
"""Clear cached preferences"""
# usefull only for tests, where the same process may run
# successively on several databases
_SCO_BASE_PREFERENCES.clear()
def get_base_preferences(): def get_base_preferences():
"""Return global preferences for the current department""" """Return global preferences for the current department"""
dept = g.scodoc_dept dept_acronym = g.scodoc_dept
if not dept in _SCO_BASE_PREFERENCES: if not dept_acronym in _SCO_BASE_PREFERENCES:
_SCO_BASE_PREFERENCES[dept] = BasePreferences() _SCO_BASE_PREFERENCES[dept_acronym] = BasePreferences(dept_acronym)
return _SCO_BASE_PREFERENCES[dept] return _SCO_BASE_PREFERENCES[dept_acronym]
def get_preference(name, formsemestre_id=None): def get_preference(name, formsemestre_id=None):
@ -198,7 +206,8 @@ class BasePreferences(object):
_editor = ndb.EditableTable( _editor = ndb.EditableTable(
"sco_prefs", "sco_prefs",
"pref_id", "pref_id",
("pref_id", "name", "value", "formsemestre_id"), ("pref_id", "dept_id", "name", "value", "formsemestre_id"),
filter_dept=True,
sortkey="name", sortkey="name",
convert_null_outputs_to_empty=False, convert_null_outputs_to_empty=False,
# allow_set_id=True, #sco8 # allow_set_id=True, #sco8
@ -206,7 +215,11 @@ class BasePreferences(object):
filter_nulls=False, filter_nulls=False,
) )
def __init__(self): def __init__(self, dept_acronym: str):
dept = Departement.query.filter_by(acronym=dept_acronym).first()
if not dept:
raise ScoValueError(f"Invalid departement: {dept_acronym}")
self.dept_id = dept.id
self.init() self.init()
self.load() self.load()
@ -1785,11 +1798,11 @@ class BasePreferences(object):
def load(self): def load(self):
"""Load all preferences from db""" """Load all preferences from db"""
log("loading preferences") log(f"loading preferences for dept_id={self.dept_id}")
try: try:
scu.GSL.acquire() scu.GSL.acquire()
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
preflist = self._editor.list(cnx) preflist = self._editor.list(cnx, {"dept_id": self.dept_id})
self.prefs = {None: {}} # { formsemestre_id (or None) : { name : value } } self.prefs = {None: {}} # { formsemestre_id (or None) : { name : value } }
self.default = {} # { name : default_value } self.default = {} # { name : default_value }
for p in preflist: for p in preflist:
@ -1850,7 +1863,9 @@ class BasePreferences(object):
self.prefs[None][name] = value self.prefs[None][name] = value
log("creating missing preference for %s=%s" % (name, value)) log("creating missing preference for %s=%s" % (name, value))
# add to db table # add to db table
self._editor.create(cnx, {"name": name, "value": value}) self._editor.create(
cnx, {"dept_id": self.dept_id, "name": name, "value": value}
)
finally: finally:
scu.GSL.release() scu.GSL.release()
@ -1898,14 +1913,20 @@ class BasePreferences(object):
value = "1" if value else "0" value = "1" if value else "0"
# existe deja ? # existe deja ?
pdb = self._editor.list( pdb = self._editor.list(
cnx, args={"formsemestre_id": formsemestre_id, "name": name} cnx,
args={
"dept_id": self.dept_id,
"formsemestre_id": formsemestre_id,
"name": name,
},
) )
if not pdb: if not pdb:
# cree preference # crée préférence
log("create pref sem=%s %s=%s" % (formsemestre_id, name, value)) log("create pref sem=%s %s=%s" % (formsemestre_id, name, value))
self._editor.create( self._editor.create(
cnx, cnx,
{ {
"dept_id": self.dept_id,
"name": name, "name": name,
"value": value, "value": value,
"formsemestre_id": formsemestre_id, "formsemestre_id": formsemestre_id,
@ -1959,6 +1980,7 @@ class BasePreferences(object):
) )
if pdb: if pdb:
log("deleting pref sem=%s %s" % (formsemestre_id, name)) log("deleting pref sem=%s %s" % (formsemestre_id, name))
assert pdb[0]["dept_id"] == self.dept_id
self._editor.delete(cnx, pdb[0]["pref_id"]) self._editor.delete(cnx, pdb[0]["pref_id"])
sco_cache.invalidate_formsemestre() # > modif preferences sco_cache.invalidate_formsemestre() # > modif preferences
finally: finally:

View File

@ -40,6 +40,7 @@ sem_set_list(context)
""" """
import flask import flask
from flask import g
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import sco_cache from app.scodoc import sco_cache
@ -58,7 +59,10 @@ import app.scodoc.sco_utils as scu
_semset_editor = ndb.EditableTable( _semset_editor = ndb.EditableTable(
"notes_semset", "semset_id", ("semset_id", "title", "annee_scolaire", "sem_id") "notes_semset",
"semset_id",
("semset_id", "title", "annee_scolaire", "sem_id"),
filter_dept=True,
) )
semset_create = _semset_editor.create semset_create = _semset_editor.create
@ -156,14 +160,24 @@ class SemSet(dict):
) )
ndb.SimpleQuery( ndb.SimpleQuery(
"INSERT INTO notes_semset_formsemestre (formsemestre_id, semset_id) VALUES (%(formsemestre_id)s, %(semset_id)s)", """INSERT INTO notes_semset_formsemestre
{"formsemestre_id": formsemestre_id, "semset_id": self.semset_id}, (dept_id, id, semset_id)
VALUES (%(dept_id)s, %(formsemestre_id)s, %(semset_id)s)
""",
{
"dept_id": g.scodoc_dept_id,
"formsemestre_id": formsemestre_id,
"semset_id": self.semset_id,
},
) )
self.load_sems() # update our list self.load_sems() # update our list
def remove(self, formsemestre_id): def remove(self, formsemestre_id):
ndb.SimpleQuery( ndb.SimpleQuery(
"DELETE FROM notes_semset_formsemestre WHERE semset_id=%(semset_id)s AND formsemestre_id=%(formsemestre_id)s", """DELETE FROM notes_semset_formsemestre
WHERE id=%(semset_id)s
AND formsemestre_id=%(formsemestre_id)s
""",
{"formsemestre_id": formsemestre_id, "semset_id": self.semset_id}, {"formsemestre_id": formsemestre_id, "semset_id": self.semset_id},
) )
self.load_sems() # update our list self.load_sems() # update our list

View File

@ -75,8 +75,8 @@ class ScoTag(object):
r = ndb.SimpleDictFetch( r = ndb.SimpleDictFetch(
"SELECT id as tag_id, * FROM " "SELECT id as tag_id, * FROM "
+ self.tag_table + self.tag_table
+ " WHERE title = %(title)s", + " WHERE dept_id=%(dept_id) AND title = %(title)s",
{"title": self.title}, {"dept_id": g.scodoc_dept_id, "title": self.title},
) )
if r: if r:
self.tag_id = r[0]["tag_id"] self.tag_id = r[0]["tag_id"]

View File

@ -52,7 +52,7 @@ STRING_TYPES = six.string_types
from PIL import Image as PILImage from PIL import Image as PILImage
from flask import g, url_for, request, current_app from flask import g, url_for, request
from scodoc_manager import sco_mgr from scodoc_manager import sco_mgr
@ -319,19 +319,10 @@ BULLETINS_VERSIONS = ("short", "selectedevals", "long")
# Support for ScoDoc7 compatibility # Support for ScoDoc7 compatibility
def get_dept_id(): def get_dept_id():
"acronyme du dept courant"
return g.scodoc_dept # en scodoc 8.1 #sco8 return g.scodoc_dept # en scodoc 8.1 #sco8
# if g.scodoc_dept in sco_mgr.get_dept_ids():
# return g.scodoc_dept
# raise sco_exceptions.ScoInvalidDept("département invalide: %s" % g.scodoc_dept)
def get_db_cnx_string(scodoc_dept=None):
return current_app.config["SQLALCHEMY_DATABASE_URI"]
# return "dbname=SCO" + (scodoc_dept or g.scodoc_dept)
def ScoURL(): def ScoURL():
"""base URL for this sco instance. """base URL for this sco instance.
e.g. https://scodoc.xxx.fr/ScoDoc/DEPT/Scolarite e.g. https://scodoc.xxx.fr/ScoDoc/DEPT/Scolarite

View File

@ -2,7 +2,7 @@
"""ScoDoc Flask views """ScoDoc Flask views
""" """
from flask import Blueprint from flask import Blueprint
from flask import g from flask import g, current_app
from app.scodoc import notesdb as ndb from app.scodoc import notesdb as ndb
scodoc_bp = Blueprint("scodoc", __name__) scodoc_bp = Blueprint("scodoc", __name__)
@ -12,19 +12,18 @@ users_bp = Blueprint("users", __name__)
absences_bp = Blueprint("absences", __name__) absences_bp = Blueprint("absences", __name__)
essais_bp = Blueprint("essais", __name__) essais_bp = Blueprint("essais", __name__)
from app.views import scodoc, notes, scolar, absences, users, essais
# Cette fonction est bien appelée avant toutes les requêtes
# de tous les blueprints
# mais apparemment elle n'a pas acces aux arguments
@scodoc_bp.before_app_request @scodoc_bp.before_app_request
def open_dept_db_connection(): def start_scodoc_request():
# current_app.logger.info("open_dept_db_connection") """Affecte toutes les requêtes, de tous les blueprints"""
if hasattr(g, "scodoc_dept") and not hasattr(g, "db_conn") and g.scodoc_dept: ndb.open_db_connection()
g.db_conn = ndb.open_dept_connection()
@scodoc_bp.teardown_app_request @scodoc_bp.teardown_app_request
def close_dept_db_connection(arg): def close_dept_db_connection(arg):
# current_app.logger.info("close_dept_db_connection") # current_app.logger.info("close_db_connection")
if hasattr(g, "db_conn"): ndb.close_db_connection()
ndb.close_dept_connection()
from app.views import scodoc, notes, scolar, absences, users, essais

View File

@ -63,6 +63,7 @@ from flask import url_for
from flask import current_app from flask import current_app
from app.decorators import ( from app.decorators import (
scodoc,
scodoc7func, scodoc7func,
ScoDoc7Context, ScoDoc7Context,
permission_required, permission_required,
@ -109,7 +110,7 @@ def sco_publish(route, function, permission, methods=["GET"]):
protected by permission and called following ScoDoc 7 Zope standards. protected by permission and called following ScoDoc 7 Zope standards.
""" """
return bp.route(route, methods=methods)( return bp.route(route, methods=methods)(
permission_required(permission)(scodoc7func(context)(function)) permission_required(permission)(scodoc7func(context)(scodoc(function)))
) )
@ -127,6 +128,7 @@ def _toboolean(x):
@bp.route("/") @bp.route("/")
@bp.route("/index_html") @bp.route("/index_html")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def index_html(context, REQUEST=None): def index_html(context, REQUEST=None):
@ -267,6 +269,7 @@ sco_publish("/CountAbsJust", sco_abs.count_abs_just, Permission.ScoView)
@bp.route("/doSignaleAbsenceGrSemestre", methods=["GET", "POST"]) @bp.route("/doSignaleAbsenceGrSemestre", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoAbsChange) @permission_required(Permission.ScoAbsChange)
@scodoc7func(context) @scodoc7func(context)
def doSignaleAbsenceGrSemestre( def doSignaleAbsenceGrSemestre(
@ -310,6 +313,7 @@ def doSignaleAbsenceGrSemestre(
# ------------ HTML Interfaces # ------------ HTML Interfaces
@bp.route("/SignaleAbsenceGrHebdo", methods=["GET", "POST"]) @bp.route("/SignaleAbsenceGrHebdo", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoAbsChange) @permission_required(Permission.ScoAbsChange)
@scodoc7func(context) @scodoc7func(context)
def SignaleAbsenceGrHebdo( def SignaleAbsenceGrHebdo(
@ -473,6 +477,7 @@ def SignaleAbsenceGrHebdo(
@bp.route("/SignaleAbsenceGrSemestre", methods=["GET", "POST"]) @bp.route("/SignaleAbsenceGrSemestre", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoAbsChange) @permission_required(Permission.ScoAbsChange)
@scodoc7func(context) @scodoc7func(context)
def SignaleAbsenceGrSemestre( def SignaleAbsenceGrSemestre(
@ -846,6 +851,7 @@ def _gen_form_saisie_groupe(
@bp.route("/EtatAbsencesGr") @bp.route("/EtatAbsencesGr")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) # ported from dtml @scodoc7func(context) # ported from dtml
def EtatAbsencesGr( def EtatAbsencesGr(
@ -984,6 +990,7 @@ ou entrez une date pour visualiser les absents un jour donné&nbsp;:
@bp.route("/EtatAbsencesDate") @bp.route("/EtatAbsencesDate")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def EtatAbsencesDate( def EtatAbsencesDate(
@ -1068,6 +1075,7 @@ def EtatAbsencesDate(
# ----- Gestion des "billets d'absence": signalement par les etudiants eux mêmes (à travers le portail) # ----- Gestion des "billets d'absence": signalement par les etudiants eux mêmes (à travers le portail)
@bp.route("/AddBilletAbsence") @bp.route("/AddBilletAbsence")
@scodoc
@permission_required(Permission.ScoAbsAddBillet) @permission_required(Permission.ScoAbsAddBillet)
@scodoc7func(context) @scodoc7func(context)
def AddBilletAbsence( def AddBilletAbsence(
@ -1127,6 +1135,7 @@ def AddBilletAbsence(
@bp.route("/AddBilletAbsenceForm") @bp.route("/AddBilletAbsenceForm")
@scodoc
@permission_required(Permission.ScoAbsAddBillet) @permission_required(Permission.ScoAbsAddBillet)
@scodoc7func(context) @scodoc7func(context)
def AddBilletAbsenceForm(context, etudid, REQUEST=None): def AddBilletAbsenceForm(context, etudid, REQUEST=None):
@ -1239,6 +1248,7 @@ def _tableBillets(context, billets, etud=None, title=""):
@bp.route("/listeBilletsEtud") @bp.route("/listeBilletsEtud")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def listeBilletsEtud(context, etudid=False, REQUEST=None, format="html"): def listeBilletsEtud(context, etudid=False, REQUEST=None, format="html"):
@ -1255,6 +1265,7 @@ def listeBilletsEtud(context, etudid=False, REQUEST=None, format="html"):
@bp.route("/XMLgetBilletsEtud") @bp.route("/XMLgetBilletsEtud")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def XMLgetBilletsEtud(context, etudid=False, REQUEST=None): def XMLgetBilletsEtud(context, etudid=False, REQUEST=None):
@ -1268,6 +1279,7 @@ def XMLgetBilletsEtud(context, etudid=False, REQUEST=None):
@bp.route("/listeBillets") @bp.route("/listeBillets")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def listeBillets(context, REQUEST=None): def listeBillets(context, REQUEST=None):
@ -1296,6 +1308,7 @@ def listeBillets(context, REQUEST=None):
@bp.route("/deleteBilletAbsence") @bp.route("/deleteBilletAbsence")
@scodoc
@permission_required(Permission.ScoAbsChange) @permission_required(Permission.ScoAbsChange)
@scodoc7func(context) @scodoc7func(context)
def deleteBilletAbsence(context, billet_id, REQUEST=None, dialog_confirmed=False): def deleteBilletAbsence(context, billet_id, REQUEST=None, dialog_confirmed=False):
@ -1390,6 +1403,7 @@ def _ProcessBilletAbsence(context, billet, estjust, description, REQUEST):
@bp.route("/ProcessBilletAbsenceForm") @bp.route("/ProcessBilletAbsenceForm")
@scodoc
@permission_required(Permission.ScoAbsChange) @permission_required(Permission.ScoAbsChange)
@scodoc7func(context) @scodoc7func(context)
def ProcessBilletAbsenceForm(context, billet_id, REQUEST=None): def ProcessBilletAbsenceForm(context, billet_id, REQUEST=None):
@ -1480,6 +1494,7 @@ def ProcessBilletAbsenceForm(context, billet_id, REQUEST=None):
@bp.route("/XMLgetAbsEtud") @bp.route("/XMLgetAbsEtud")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def XMLgetAbsEtud(context, beg_date="", end_date="", REQUEST=None): def XMLgetAbsEtud(context, beg_date="", end_date="", REQUEST=None):

View File

@ -14,6 +14,7 @@ from flask import request
from flask import url_for from flask import url_for
from app.decorators import ( from app.decorators import (
scodoc,
scodoc7func, scodoc7func,
ScoDoc7Context, ScoDoc7Context,
permission_required, permission_required,
@ -31,6 +32,7 @@ context = ScoDoc7Context(globals())
@bp.route("/<scodoc_dept>/Scolarite/sco_exemple") @bp.route("/<scodoc_dept>/Scolarite/sco_exemple")
@scodoc
@scodoc7func(context) @scodoc7func(context)
def sco_exemple(etudid="NON"): def sco_exemple(etudid="NON"):
"""Un exemple de fonction ScoDoc 7""" """Un exemple de fonction ScoDoc 7"""
@ -56,6 +58,7 @@ def sco_exemple(etudid="NON"):
@bp.route("/<scodoc_dept>/Scolarite/sco_exemple3") @bp.route("/<scodoc_dept>/Scolarite/sco_exemple3")
@scodoc
@login_required @login_required
@scodoc7func(context) @scodoc7func(context)
def sco_exemple3(toto): def sco_exemple3(toto):
@ -63,6 +66,7 @@ def sco_exemple3(toto):
@bp.route("/<scodoc_dept>/Scolarite/sco_exemple4") @bp.route("/<scodoc_dept>/Scolarite/sco_exemple4")
@scodoc
@login_required @login_required
@scodoc7func(context) @scodoc7func(context)
def sco_exemple4(toto): def sco_exemple4(toto):
@ -71,6 +75,7 @@ def sco_exemple4(toto):
# Test avec un seul argument REQUEST positionnel # Test avec un seul argument REQUEST positionnel
@bp.route("/<scodoc_dept>/Scolarite/sco_get_version") @bp.route("/<scodoc_dept>/Scolarite/sco_get_version")
@scodoc
@scodoc7func(context) @scodoc7func(context)
def sco_get_version(REQUEST): def sco_get_version(REQUEST):
return "ok" return "ok"
@ -78,8 +83,9 @@ def sco_get_version(REQUEST):
# Fonction ressemblant à une méthode Zope protégée # Fonction ressemblant à une méthode Zope protégée
@bp.route("/<scodoc_dept>/Scolarite/sco_test_view") @bp.route("/<scodoc_dept>/Scolarite/sco_test_view")
@scodoc7func(context) @scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context)
def sco_test_view(REQUEST=None): def sco_test_view(REQUEST=None):
return """Vous avez vu sco_test_view !""" return """Vous avez vu sco_test_view !"""

View File

@ -48,6 +48,7 @@ import scodoc_manager
from app.auth.models import User from app.auth.models import User
from app.decorators import ( from app.decorators import (
scodoc,
scodoc7func, scodoc7func,
ScoDoc7Context, ScoDoc7Context,
permission_required, permission_required,
@ -150,6 +151,7 @@ def sco_publish(route, function, permission, methods=["GET"]):
# --------------------- Quelques essais élémentaires: # --------------------- Quelques essais élémentaires:
@bp.route("/essai") @bp.route("/essai")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def essai(context, REQUEST=None): def essai(context, REQUEST=None):
@ -380,6 +382,7 @@ sco_publish(
# #
@bp.route("/") @bp.route("/")
@bp.route("/index_html") @bp.route("/index_html")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def index_html(context, REQUEST=None): def index_html(context, REQUEST=None):
@ -432,6 +435,7 @@ sco_publish(
@bp.route("/formation_list") @bp.route("/formation_list")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formation_list(context, format=None, REQUEST=None, formation_id=None, args={}): def formation_list(context, format=None, REQUEST=None, formation_id=None, args={}):
@ -443,6 +447,7 @@ def formation_list(context, format=None, REQUEST=None, formation_id=None, args={
@bp.route("/formation_export") @bp.route("/formation_export")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formation_export( def formation_export(
@ -455,6 +460,7 @@ def formation_export(
@bp.route("/formation_import_xml") @bp.route("/formation_import_xml")
@scodoc
@permission_required(Permission.ScoChangeFormation) @permission_required(Permission.ScoChangeFormation)
@scodoc7func(context) @scodoc7func(context)
def formation_import_xml(context, file): def formation_import_xml(context, file):
@ -465,6 +471,7 @@ def formation_import_xml(context, file):
@bp.route("/formation_import_xml_form", methods=["GET", "POST"]) @bp.route("/formation_import_xml_form", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoChangeFormation) @permission_required(Permission.ScoChangeFormation)
@scodoc7func(context) @scodoc7func(context)
def formation_import_xml_form(context, REQUEST): def formation_import_xml_form(context, REQUEST):
@ -546,6 +553,7 @@ sco_publish(
@bp.route("/formation_count_sems") @bp.route("/formation_count_sems")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formation_count_sems(context, formation_id): def formation_count_sems(context, formation_id):
@ -578,6 +586,7 @@ sco_publish("/ue_move", sco_edit_formation.ue_move, Permission.ScoChangeFormatio
@bp.route("/formsemestre_list") @bp.route("/formsemestre_list")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_list( def formsemestre_list(
@ -604,6 +613,7 @@ def formsemestre_list(
@bp.route("/XMLgetFormsemestres") @bp.route("/XMLgetFormsemestres")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def XMLgetFormsemestres(context, etape_apo=None, formsemestre_id=None, REQUEST=None): def XMLgetFormsemestres(context, etape_apo=None, formsemestre_id=None, REQUEST=None):
@ -656,6 +666,7 @@ sco_publish(
@bp.route("/formsemestre_custommenu_edit", methods=["GET", "POST"]) @bp.route("/formsemestre_custommenu_edit", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_custommenu_edit(context, REQUEST, formsemestre_id): def formsemestre_custommenu_edit(context, REQUEST, formsemestre_id):
@ -668,6 +679,7 @@ def formsemestre_custommenu_edit(context, REQUEST, formsemestre_id):
# --- dialogue modif enseignants/moduleimpl # --- dialogue modif enseignants/moduleimpl
@bp.route("/edit_enseignants_form", methods=["GET", "POST"]) @bp.route("/edit_enseignants_form", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def edit_enseignants_form(context, REQUEST, moduleimpl_id): def edit_enseignants_form(context, REQUEST, moduleimpl_id):
@ -778,6 +790,7 @@ def edit_enseignants_form(context, REQUEST, moduleimpl_id):
@bp.route("/edit_moduleimpl_resp", methods=["GET", "POST"]) @bp.route("/edit_moduleimpl_resp", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def edit_moduleimpl_resp(context, REQUEST, moduleimpl_id): def edit_moduleimpl_resp(context, REQUEST, moduleimpl_id):
@ -885,6 +898,7 @@ _EXPR_HELP = """<p class="help">Expérimental: formule de calcul de la moyenne %
@bp.route("/edit_moduleimpl_expr", methods=["GET", "POST"]) @bp.route("/edit_moduleimpl_expr", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def edit_moduleimpl_expr(context, REQUEST, moduleimpl_id): def edit_moduleimpl_expr(context, REQUEST, moduleimpl_id):
@ -953,6 +967,7 @@ def edit_moduleimpl_expr(context, REQUEST, moduleimpl_id):
@bp.route("/view_module_abs") @bp.route("/view_module_abs")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def view_module_abs(context, REQUEST, moduleimpl_id, format="html"): def view_module_abs(context, REQUEST, moduleimpl_id, format="html"):
@ -1033,6 +1048,7 @@ def view_module_abs(context, REQUEST, moduleimpl_id, format="html"):
@bp.route("/edit_ue_expr", methods=["GET", "POST"]) @bp.route("/edit_ue_expr", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def edit_ue_expr(context, REQUEST, formsemestre_id, ue_id): def edit_ue_expr(context, REQUEST, formsemestre_id, ue_id):
@ -1107,6 +1123,7 @@ def edit_ue_expr(context, REQUEST, formsemestre_id, ue_id):
@bp.route("/formsemestre_enseignants_list") @bp.route("/formsemestre_enseignants_list")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_enseignants_list(context, REQUEST, formsemestre_id, format="html"): def formsemestre_enseignants_list(context, REQUEST, formsemestre_id, format="html"):
@ -1191,6 +1208,7 @@ def formsemestre_enseignants_list(context, REQUEST, formsemestre_id, format="htm
@bp.route("/edit_enseignants_form_delete", methods=["GET", "POST"]) @bp.route("/edit_enseignants_form_delete", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def edit_enseignants_form_delete(context, REQUEST, moduleimpl_id, ens_id): def edit_enseignants_form_delete(context, REQUEST, moduleimpl_id, ens_id):
@ -1230,6 +1248,7 @@ sco_publish(
@bp.route("/do_formsemestre_inscription_listinscrits") @bp.route("/do_formsemestre_inscription_listinscrits")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def do_formsemestre_inscription_listinscrits( def do_formsemestre_inscription_listinscrits(
@ -1243,6 +1262,7 @@ def do_formsemestre_inscription_listinscrits(
@bp.route("/formsemestre_desinscription") @bp.route("/formsemestre_desinscription")
@scodoc
@permission_required(Permission.ScoImplement) @permission_required(Permission.ScoImplement)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_desinscription( def formsemestre_desinscription(
@ -1329,6 +1349,7 @@ sco_publish(
@bp.route("/etud_desinscrit_ue") @bp.route("/etud_desinscrit_ue")
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def etud_desinscrit_ue(context, etudid, formsemestre_id, ue_id, REQUEST=None): def etud_desinscrit_ue(context, etudid, formsemestre_id, ue_id, REQUEST=None):
@ -1344,6 +1365,7 @@ def etud_desinscrit_ue(context, etudid, formsemestre_id, ue_id, REQUEST=None):
@bp.route("/etud_inscrit_ue") @bp.route("/etud_inscrit_ue")
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def etud_inscrit_ue(context, etudid, formsemestre_id, ue_id, REQUEST=None): def etud_inscrit_ue(context, etudid, formsemestre_id, ue_id, REQUEST=None):
@ -1407,6 +1429,7 @@ sco_publish(
@bp.route("/evaluation_delete", methods=["GET", "POST"]) @bp.route("/evaluation_delete", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEnsView) @permission_required(Permission.ScoEnsView)
@scodoc7func(context) @scodoc7func(context)
def evaluation_delete(context, REQUEST, evaluation_id): def evaluation_delete(context, REQUEST, evaluation_id):
@ -1490,6 +1513,7 @@ sco_publish(
@bp.route("/evaluation_edit", methods=["GET", "POST"]) @bp.route("/evaluation_edit", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEnsView) @permission_required(Permission.ScoEnsView)
@scodoc7func(context) @scodoc7func(context)
def evaluation_edit(evaluation_id, REQUEST): def evaluation_edit(evaluation_id, REQUEST):
@ -1500,6 +1524,7 @@ def evaluation_edit(evaluation_id, REQUEST):
@bp.route("/evaluation_create", methods=["GET", "POST"]) @bp.route("/evaluation_create", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEnsView) @permission_required(Permission.ScoEnsView)
@scodoc7func(context) @scodoc7func(context)
def evaluation_create(moduleimpl_id, REQUEST): def evaluation_create(moduleimpl_id, REQUEST):
@ -1510,6 +1535,7 @@ def evaluation_create(moduleimpl_id, REQUEST):
@bp.route("/evaluation_listenotes") @bp.route("/evaluation_listenotes")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def evaluation_listenotes(context, REQUEST=None): def evaluation_listenotes(context, REQUEST=None):
@ -1591,6 +1617,7 @@ sco_publish(
# --- Bulletins # --- Bulletins
@bp.route("/formsemestre_bulletins_pdf") @bp.route("/formsemestre_bulletins_pdf")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_bulletins_pdf( def formsemestre_bulletins_pdf(
@ -1607,6 +1634,7 @@ _EXPL_BULL = """Versions des bulletins:<ul><li><bf>courte</bf>: moyennes des mod
@bp.route("/formsemestre_bulletins_pdf_choice") @bp.route("/formsemestre_bulletins_pdf_choice")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_bulletins_pdf_choice(context, REQUEST, formsemestre_id, version=None): def formsemestre_bulletins_pdf_choice(context, REQUEST, formsemestre_id, version=None):
@ -1626,6 +1654,7 @@ def formsemestre_bulletins_pdf_choice(context, REQUEST, formsemestre_id, version
@bp.route("/etud_bulletins_pdf") @bp.route("/etud_bulletins_pdf")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def etud_bulletins_pdf(context, etudid, REQUEST, version="selectedevals"): def etud_bulletins_pdf(context, etudid, REQUEST, version="selectedevals"):
@ -1637,6 +1666,7 @@ def etud_bulletins_pdf(context, etudid, REQUEST, version="selectedevals"):
@bp.route("/formsemestre_bulletins_mailetuds_choice") @bp.route("/formsemestre_bulletins_mailetuds_choice")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_bulletins_mailetuds_choice( def formsemestre_bulletins_mailetuds_choice(
@ -1703,6 +1733,7 @@ def formsemestre_bulletins_choice(
@bp.route("/formsemestre_bulletins_mailetuds") @bp.route("/formsemestre_bulletins_mailetuds")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_bulletins_mailetuds( def formsemestre_bulletins_mailetuds(
@ -1766,6 +1797,7 @@ sco_publish(
@bp.route("/appreciation_add_form", methods=["GET", "POST"]) @bp.route("/appreciation_add_form", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEnsView) @permission_required(Permission.ScoEnsView)
@scodoc7func(context) @scodoc7func(context)
def appreciation_add_form( def appreciation_add_form(
@ -1875,6 +1907,7 @@ def appreciation_add_form(
@bp.route("/formsemestre_validation_etud_form") @bp.route("/formsemestre_validation_etud_form")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_validation_etud_form( def formsemestre_validation_etud_form(
@ -1903,6 +1936,7 @@ def formsemestre_validation_etud_form(
@bp.route("/formsemestre_validation_etud") @bp.route("/formsemestre_validation_etud")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_validation_etud( def formsemestre_validation_etud(
@ -1934,6 +1968,7 @@ def formsemestre_validation_etud(
@bp.route("/formsemestre_validation_etud_manu") @bp.route("/formsemestre_validation_etud_manu")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_validation_etud_manu( def formsemestre_validation_etud_manu(
@ -1971,6 +2006,7 @@ def formsemestre_validation_etud_manu(
@bp.route("/formsemestre_validate_previous_ue") @bp.route("/formsemestre_validate_previous_ue")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_validate_previous_ue( def formsemestre_validate_previous_ue(
@ -1997,6 +2033,7 @@ sco_publish(
@bp.route("/formsemestre_ext_edit_ue_validations", methods=["GET", "POST"]) @bp.route("/formsemestre_ext_edit_ue_validations", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_ext_edit_ue_validations( def formsemestre_ext_edit_ue_validations(
@ -2022,6 +2059,7 @@ sco_publish(
@bp.route("/etud_ue_suppress_validation") @bp.route("/etud_ue_suppress_validation")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def etud_ue_suppress_validation(context, etudid, formsemestre_id, ue_id, REQUEST=None): def etud_ue_suppress_validation(context, etudid, formsemestre_id, ue_id, REQUEST=None):
@ -2038,6 +2076,7 @@ def etud_ue_suppress_validation(context, etudid, formsemestre_id, ue_id, REQUEST
@bp.route("/formsemestre_validation_auto") @bp.route("/formsemestre_validation_auto")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_validation_auto(context, formsemestre_id, REQUEST): def formsemestre_validation_auto(context, formsemestre_id, REQUEST):
@ -2055,6 +2094,7 @@ def formsemestre_validation_auto(context, formsemestre_id, REQUEST):
@bp.route("/do_formsemestre_validation_auto") @bp.route("/do_formsemestre_validation_auto")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def do_formsemestre_validation_auto(context, formsemestre_id, REQUEST): def do_formsemestre_validation_auto(context, formsemestre_id, REQUEST):
@ -2072,6 +2112,7 @@ def do_formsemestre_validation_auto(context, formsemestre_id, REQUEST):
@bp.route("/formsemestre_validation_suppress_etud", methods=["GET", "POST"]) @bp.route("/formsemestre_validation_suppress_etud", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_validation_suppress_etud( def formsemestre_validation_suppress_etud(
@ -2312,6 +2353,7 @@ sco_publish(
@bp.route("/check_sem_integrity") @bp.route("/check_sem_integrity")
@scodoc
@permission_required(Permission.ScoImplement) @permission_required(Permission.ScoImplement)
@scodoc7func(context) @scodoc7func(context)
def check_sem_integrity(context, formsemestre_id, REQUEST, fix=False): def check_sem_integrity(context, formsemestre_id, REQUEST, fix=False):
@ -2384,6 +2426,7 @@ def check_sem_integrity(context, formsemestre_id, REQUEST, fix=False):
@bp.route("/check_form_integrity") @bp.route("/check_form_integrity")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def check_form_integrity(context, formation_id, fix=False, REQUEST=None): def check_form_integrity(context, formation_id, fix=False, REQUEST=None):
@ -2423,6 +2466,7 @@ def check_form_integrity(context, formation_id, fix=False, REQUEST=None):
@bp.route("/check_formsemestre_integrity") @bp.route("/check_formsemestre_integrity")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def check_formsemestre_integrity(context, formsemestre_id, REQUEST=None): def check_formsemestre_integrity(context, formsemestre_id, REQUEST=None):
@ -2473,6 +2517,7 @@ def check_formsemestre_integrity(context, formsemestre_id, REQUEST=None):
@bp.route("/check_integrity_all") @bp.route("/check_integrity_all")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def check_integrity_all(context, REQUEST=None): def check_integrity_all(context, REQUEST=None):

View File

@ -45,7 +45,7 @@ from app.scodoc.sco_permissions import Permission
@bp.route("/ScoDoc") @bp.route("/ScoDoc")
@bp.route("/ScoDoc/index") @bp.route("/ScoDoc/index")
def index(): def index(): # XXX TODO A REECRIRE
dept_ids = sco_mgr.get_dept_ids() dept_ids = sco_mgr.get_dept_ids()
return render_template( return render_template(
"scodoc.html", "scodoc.html",

View File

@ -48,6 +48,7 @@ from flask_login import current_user
from config import Config from config import Config
import scodoc_manager import scodoc_manager
from app.decorators import ( from app.decorators import (
scodoc,
scodoc7func, scodoc7func,
ScoDoc7Context, ScoDoc7Context,
permission_required, permission_required,
@ -120,7 +121,7 @@ def sco_publish(route, function, permission, methods=("GET",)):
protected by permission and called following ScoDoc 7 Zope standards. protected by permission and called following ScoDoc 7 Zope standards.
""" """
return bp.route(route, methods=methods)( return bp.route(route, methods=methods)(
permission_required(permission)(scodoc7func(context)(function)) permission_required(permission)(scodoc7func(context)(scodoc(function)))
) )
@ -135,6 +136,7 @@ log("ScoDoc8 restarting...")
@bp.route("/about") @bp.route("/about")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def about(context, REQUEST): def about(context, REQUEST):
@ -169,6 +171,7 @@ def about(context, REQUEST):
@bp.route("/edit_preferences", methods=["GET", "POST"]) @bp.route("/edit_preferences", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoChangePreferences) @permission_required(Permission.ScoChangePreferences)
@scodoc7func(context) @scodoc7func(context)
def edit_preferences(context, REQUEST): def edit_preferences(context, REQUEST):
@ -177,6 +180,7 @@ def edit_preferences(context, REQUEST):
@bp.route("/formsemestre_edit_preferences", methods=["GET", "POST"]) @bp.route("/formsemestre_edit_preferences", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_edit_preferences(context, formsemestre_id, REQUEST): def formsemestre_edit_preferences(context, formsemestre_id, REQUEST):
@ -196,6 +200,7 @@ def formsemestre_edit_preferences(context, formsemestre_id, REQUEST):
@bp.route("/doc_preferences") @bp.route("/doc_preferences")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def doc_preferences(REQUEST): def doc_preferences(REQUEST):
@ -212,6 +217,7 @@ def doc_preferences(REQUEST):
@bp.route("/showEtudLog") @bp.route("/showEtudLog")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def showEtudLog(context, etudid, format="html", REQUEST=None): def showEtudLog(context, etudid, format="html", REQUEST=None):
@ -248,8 +254,22 @@ def showEtudLog(context, etudid, format="html", REQUEST=None):
# ---------- PAGE ACCUEIL (listes) -------------- # ---------- PAGE ACCUEIL (listes) --------------
@bp.route("/") # @bp.route("/")
@bp.route("/index_html") @bp.route("/kimo")
@scodoc
@scodoc
@permission_required(Permission.ScoView)
@scodoc7func(context)
def kimo(context, REQUEST=None, showcodes=0, showsemtable=0):
import time
return f"{time.time()} := {g.scodoc_dept}"
# @bp.route("/")
@bp.route("/index_html2")
@scodoc
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def index_html(context, REQUEST=None, showcodes=0, showsemtable=0): def index_html(context, REQUEST=None, showcodes=0, showsemtable=0):
@ -287,6 +307,7 @@ sco_publish(
# -------------------------- INFOS SUR ETUDIANTS -------------------------- # -------------------------- INFOS SUR ETUDIANTS --------------------------
@bp.route("/getEtudInfo") @bp.route("/getEtudInfo")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def getEtudInfo( def getEtudInfo(
@ -321,6 +342,7 @@ sco_publish(
# XMLgetEtudInfos était le nom dans l'ancienne API ScoDoc 6 # XMLgetEtudInfos était le nom dans l'ancienne API ScoDoc 6
@bp.route("/etud_info") @bp.route("/etud_info")
@bp.route("/XMLgetEtudInfos") @bp.route("/XMLgetEtudInfos")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def etud_info(context, etudid=None, format="xml", REQUEST=None): def etud_info(context, etudid=None, format="xml", REQUEST=None):
@ -494,6 +516,7 @@ sco_publish(
@bp.route("/doAddAnnotation", methods=["GET", "POST"]) @bp.route("/doAddAnnotation", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEtudAddAnnotations) @permission_required(Permission.ScoEtudAddAnnotations)
@scodoc7func(context) @scodoc7func(context)
def doAddAnnotation(etudid, comment): def doAddAnnotation(etudid, comment):
@ -514,6 +537,7 @@ def doAddAnnotation(etudid, comment):
@bp.route("/doSuppressAnnotation", methods=["GET", "POST"]) @bp.route("/doSuppressAnnotation", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def doSuppressAnnotation(context, etudid, annotation_id, REQUEST): def doSuppressAnnotation(context, etudid, annotation_id, REQUEST):
@ -541,6 +565,7 @@ def doSuppressAnnotation(context, etudid, annotation_id, REQUEST):
@bp.route("/formChangeCoordonnees", methods=["GET", "POST"]) @bp.route("/formChangeCoordonnees", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEtudChangeAdr) @permission_required(Permission.ScoEtudChangeAdr)
@scodoc7func(context) @scodoc7func(context)
def formChangeCoordonnees(context, etudid, REQUEST): def formChangeCoordonnees(context, etudid, REQUEST):
@ -704,6 +729,7 @@ sco_publish(
methods=["GET", "POST"], methods=["GET", "POST"],
) )
# @bp.route("/partition_create", methods=["GET", "POST"]) # @bp.route("/partition_create", methods=["GET", "POST"])
# @scodoc
# @permission_required(Permission.ScoView) # @permission_required(Permission.ScoView)
# @scodoc7func(context) # @scodoc7func(context)
# def partition_create( # def partition_create(
@ -725,6 +751,7 @@ sco_publish("/etud_photo_html", sco_photos.etud_photo_html, Permission.ScoView)
@bp.route("/etud_photo_orig_page") @bp.route("/etud_photo_orig_page")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def etud_photo_orig_page(context, etudid=None, REQUEST=None): def etud_photo_orig_page(context, etudid=None, REQUEST=None):
@ -743,6 +770,7 @@ def etud_photo_orig_page(context, etudid=None, REQUEST=None):
@bp.route("/formChangePhoto", methods=["GET", "POST"]) @bp.route("/formChangePhoto", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEtudChangeAdr) @permission_required(Permission.ScoEtudChangeAdr)
@scodoc7func(context) @scodoc7func(context)
def formChangePhoto(context, etudid=None, REQUEST=None): def formChangePhoto(context, etudid=None, REQUEST=None):
@ -802,6 +830,7 @@ def formChangePhoto(context, etudid=None, REQUEST=None):
@bp.route("/formSuppressPhoto") @bp.route("/formSuppressPhoto")
@scodoc
@permission_required(Permission.ScoEtudChangeAdr) @permission_required(Permission.ScoEtudChangeAdr)
@scodoc7func(context) @scodoc7func(context)
def formSuppressPhoto(context, etudid=None, REQUEST=None, dialog_confirmed=False): def formSuppressPhoto(context, etudid=None, REQUEST=None, dialog_confirmed=False):
@ -826,6 +855,7 @@ def formSuppressPhoto(context, etudid=None, REQUEST=None, dialog_confirmed=False
# #
@bp.route("/formDem") @bp.route("/formDem")
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def formDem(context, etudid, formsemestre_id, REQUEST): def formDem(context, etudid, formsemestre_id, REQUEST):
@ -841,6 +871,7 @@ def formDem(context, etudid, formsemestre_id, REQUEST):
@bp.route("/formDef") @bp.route("/formDef")
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def formDef(context, etudid, formsemestre_id, REQUEST): def formDef(context, etudid, formsemestre_id, REQUEST):
@ -902,6 +933,7 @@ def _formDem_of_Def(
@bp.route("/doDemEtudiant") @bp.route("/doDemEtudiant")
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def doDemEtudiant(context, etudid, formsemestre_id, event_date=None, REQUEST=None): def doDemEtudiant(context, etudid, formsemestre_id, event_date=None, REQUEST=None):
@ -919,6 +951,7 @@ def doDemEtudiant(context, etudid, formsemestre_id, event_date=None, REQUEST=Non
@bp.route("/doDefEtudiant") @bp.route("/doDefEtudiant")
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def doDefEtudiant(context, etudid, formsemestre_id, event_date=None, REQUEST=None): def doDefEtudiant(context, etudid, formsemestre_id, event_date=None, REQUEST=None):
@ -980,6 +1013,7 @@ def _do_dem_or_def_etud(
@bp.route("/doCancelDem", methods=["GET", "POST"]) @bp.route("/doCancelDem", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def doCancelDem( def doCancelDem(
@ -1002,6 +1036,7 @@ def doCancelDem(
@bp.route("/doCancelDef", methods=["GET", "POST"]) @bp.route("/doCancelDef", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def doCancelDef( def doCancelDef(
@ -1087,6 +1122,7 @@ def _do_cancel_dem_or_def(
@bp.route("/etudident_create_form", methods=["GET", "POST"]) @bp.route("/etudident_create_form", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def etudident_create_form(context, REQUEST=None): def etudident_create_form(context, REQUEST=None):
@ -1095,6 +1131,7 @@ def etudident_create_form(context, REQUEST=None):
@bp.route("/etudident_edit_form", methods=["GET", "POST"]) @bp.route("/etudident_edit_form", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def etudident_edit_form(context, REQUEST=None): def etudident_edit_form(context, REQUEST=None):
@ -1501,6 +1538,7 @@ def _etudident_create_or_edit_form(context, REQUEST, edit):
@bp.route("/etudident_delete", methods=["GET", "POST"]) @bp.route("/etudident_delete", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def etudident_delete(context, etudid, dialog_confirmed=False, REQUEST=None): def etudident_delete(context, etudid, dialog_confirmed=False, REQUEST=None):
@ -1573,6 +1611,7 @@ def etudident_delete(context, etudid, dialog_confirmed=False, REQUEST=None):
@bp.route("/check_group_apogee") @bp.route("/check_group_apogee")
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def check_group_apogee( def check_group_apogee(
@ -1724,6 +1763,7 @@ def check_group_apogee(
@bp.route("/form_students_import_excel") @bp.route("/form_students_import_excel")
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def form_students_import_excel(context, REQUEST, formsemestre_id=None): def form_students_import_excel(context, REQUEST, formsemestre_id=None):
@ -1864,6 +1904,7 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
@bp.route("/import_generate_excel_sample") @bp.route("/import_generate_excel_sample")
@scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func(context) @scodoc7func(context)
def import_generate_excel_sample(context, REQUEST, with_codesemestre="1"): def import_generate_excel_sample(context, REQUEST, with_codesemestre="1"):
@ -1881,6 +1922,7 @@ def import_generate_excel_sample(context, REQUEST, with_codesemestre="1"):
# --- Données admission # --- Données admission
@bp.route("/import_generate_admission_sample") @bp.route("/import_generate_admission_sample")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def import_generate_admission_sample(context, REQUEST, formsemestre_id): def import_generate_admission_sample(context, REQUEST, formsemestre_id):
@ -1902,6 +1944,7 @@ def import_generate_admission_sample(context, REQUEST, formsemestre_id):
# --- Données admission depuis fichier excel (version nov 2016) # --- Données admission depuis fichier excel (version nov 2016)
@bp.route("/form_students_import_infos_admissions", methods=["GET", "POST"]) @bp.route("/form_students_import_infos_admissions", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def form_students_import_infos_admissions(context, REQUEST, formsemestre_id=None): def form_students_import_infos_admissions(context, REQUEST, formsemestre_id=None):
@ -2009,6 +2052,7 @@ def form_students_import_infos_admissions(context, REQUEST, formsemestre_id=None
@bp.route("/formsemestre_import_etud_admission") @bp.route("/formsemestre_import_etud_admission")
@scodoc
@permission_required(Permission.ScoEtudChangeAdr) @permission_required(Permission.ScoEtudChangeAdr)
@scodoc7func(context) @scodoc7func(context)
def formsemestre_import_etud_admission( def formsemestre_import_etud_admission(
@ -2057,6 +2101,7 @@ sco_publish(
# --- Statistiques # --- Statistiques
@bp.route("/stat_bac") @bp.route("/stat_bac")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def stat_bac(context, formsemestre_id): def stat_bac(context, formsemestre_id):

View File

@ -48,6 +48,7 @@ from app.auth.models import User
from app.auth.models import Role from app.auth.models import Role
from app.auth.models import UserRole from app.auth.models import UserRole
from app.decorators import ( from app.decorators import (
scodoc,
scodoc7func, scodoc7func,
ScoDoc7Context, ScoDoc7Context,
permission_required, permission_required,
@ -71,6 +72,7 @@ context = ScoDoc7Context("users") # sco8
@bp.route("/") @bp.route("/")
@bp.route("/index_html") @bp.route("/index_html")
@scodoc
@permission_required(Permission.ScoUsersView) @permission_required(Permission.ScoUsersView)
@scodoc7func(context) @scodoc7func(context)
def index_html(context, REQUEST, all_depts=False, with_inactives=False, format="html"): def index_html(context, REQUEST, all_depts=False, with_inactives=False, format="html"):
@ -84,6 +86,7 @@ def index_html(context, REQUEST, all_depts=False, with_inactives=False, format="
@bp.route("/user_info") @bp.route("/user_info")
@scodoc
@permission_required(Permission.ScoUsersView) @permission_required(Permission.ScoUsersView)
@scodoc7func(context) @scodoc7func(context)
def user_info(user_name, format="json", REQUEST=None): def user_info(user_name, format="json", REQUEST=None):
@ -92,6 +95,7 @@ def user_info(user_name, format="json", REQUEST=None):
@bp.route("/create_user_form", methods=["GET", "POST"]) @bp.route("/create_user_form", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoUsersAdmin) @permission_required(Permission.ScoUsersAdmin)
@scodoc7func(context) @scodoc7func(context)
def create_user_form(context, REQUEST, user_name=None, edit=0): def create_user_form(context, REQUEST, user_name=None, edit=0):
@ -464,6 +468,7 @@ def import_users_form():
@bp.route("/user_info_page") @bp.route("/user_info_page")
@scodoc
@permission_required(Permission.ScoUsersView) @permission_required(Permission.ScoUsersView)
@scodoc7func(context) @scodoc7func(context)
def user_info_page(user_name, REQUEST=None): def user_info_page(user_name, REQUEST=None):
@ -471,6 +476,7 @@ def user_info_page(user_name, REQUEST=None):
@bp.route("/get_user_list_xml") @bp.route("/get_user_list_xml")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def get_user_list_xml(dept=None, start="", limit=25, REQUEST=None): def get_user_list_xml(dept=None, start="", limit=25, REQUEST=None):
@ -496,6 +502,7 @@ def get_user_list_xml(dept=None, start="", limit=25, REQUEST=None):
@bp.route("/form_change_password") @bp.route("/form_change_password")
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def form_change_password(REQUEST, user_name=None): def form_change_password(REQUEST, user_name=None):
@ -534,6 +541,7 @@ def form_change_password(REQUEST, user_name=None):
@bp.route("/change_password", methods=["POST"]) @bp.route("/change_password", methods=["POST"])
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def change_password(user_name, password, password2, REQUEST): def change_password(user_name, password, password2, REQUEST):
@ -593,6 +601,7 @@ def change_password(user_name, password, password2, REQUEST):
@bp.route("/delete_user_form", methods=["GET", "POST"]) @bp.route("/delete_user_form", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoUsersAdmin) @permission_required(Permission.ScoUsersAdmin)
@scodoc7func(context) @scodoc7func(context)
def delete_user_form(REQUEST, user_name, dialog_confirmed=False): def delete_user_form(REQUEST, user_name, dialog_confirmed=False):

View File

@ -146,11 +146,22 @@ def user_password(username, password=None): # user-password
@app.cli.command() @app.cli.command()
@click.argument("dept") @click.argument("dept")
def sco_delete_dept(dept): # sco-delete-dept def sco_delete_dept(dept): # sco-delete-dept
"Delete existing departement" """Delete existing departement"""
raise NotImplementedError() click.confirm(
if os.system('tools/delete_dept.sh -n "{}"'.format(dept)): f"""Attention: Cela va effacer toutes les données du département {dept}
sys.stderr.write("error deleting dept " + dept) (étudiants, notes, formations, etc)
return 1 Voulez-vous vraiment continuer ?
""",
abort=True,
)
db.reflect()
d = models.Departement.query.filter_by(acronym=dept).first()
if d is None:
sys.stderr.write(f"Erreur: le departement {dept} n'existe pas !")
return 2
# XXX TODO: détruire les objets du département !
db.session.delete(d)
db.session.commit()
return 0 return 0
@ -158,10 +169,9 @@ def sco_delete_dept(dept): # sco-delete-dept
@click.argument("dept") @click.argument("dept")
def sco_create_dept(dept): # sco-create-dept def sco_create_dept(dept): # sco-create-dept
"Create new departement" "Create new departement"
raise NotImplementedError() d = models.Departement(acronym=dept)
if os.system(f'tools/create_dept.sh -n "{dept}"'): db.session.add(d)
sys.stderr.write(f"error creating dept {dept}\n") db.session.commit()
return 1
return 0 return 0

View File

@ -4,6 +4,7 @@ from flask import g
from flask_login import login_user, logout_user, current_user from flask_login import login_user, logout_user, current_user
from config import TestConfig from config import TestConfig
import app
from app import db, create_app from app import db, create_app
from app import initialize_scodoc_database, clear_scodoc_cache from app import initialize_scodoc_database, clear_scodoc_cache
from app import models from app import models
@ -44,9 +45,13 @@ def test_client():
u.add_role(admin_role, TestConfig.DEPT_TEST) u.add_role(admin_role, TestConfig.DEPT_TEST)
db.session.add(u) db.session.add(u)
db.session.commit() db.session.commit()
ndb.set_sco_dept(TestConfig.DEPT_TEST) # set db connection # Creation département de Test
d = models.Departement(acronym=TestConfig.DEPT_TEST)
db.session.add(d)
db.session.commit()
app.set_sco_dept(TestConfig.DEPT_TEST) # set db connection
yield client yield client
# ndb.close_dept_connection() ndb.close_db_connection()
# Teardown: # Teardown:
db.session.commit() db.session.commit()
db.session.remove() db.session.remove()

View File

@ -11,6 +11,7 @@ Usage: pytest tests/unit/test_caches.py
from flask import current_app, g from flask import current_app, g
import app
from app import db from app import db
from app.scodoc import sco_cache from app.scodoc import sco_cache
from app.scodoc import sco_evaluations from app.scodoc import sco_evaluations
@ -25,7 +26,7 @@ context = None # #context
def test_notes_table(test_client): def test_notes_table(test_client):
"""Test construction et cache de NotesTable.""" """Test construction et cache de NotesTable."""
ndb.set_sco_dept(DEPT) app.set_sco_dept(DEPT)
assert g.scodoc_dept == DEPT assert g.scodoc_dept == DEPT
# prépare le département avec quelques semestres: # prépare le département avec quelques semestres:
run_sco_basic() run_sco_basic()
@ -49,7 +50,7 @@ def test_notes_table(test_client):
def test_cache_evaluations(test_client): def test_cache_evaluations(test_client):
"""""" """"""
# cherche un semestre ayant des evaluations # cherche un semestre ayant des evaluations
ndb.set_sco_dept(DEPT) app.set_sco_dept(DEPT)
# prépare le département avec quelques semestres: # prépare le département avec quelques semestres:
run_sco_basic() run_sco_basic()
# #

View File

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
"""Test ORM departement/formation/preferences
Utiliser comme:
pytest tests/unit/test_departements.py
"""
from flask import g
import app
from app import db
from app.models import Departement, ScoPreference, FormSemestre, formsemestre
from app.scodoc import notesdb as ndb
from app.scodoc import sco_formsemestre
from app.scodoc import sco_preferences
from tests.unit import test_sco_basic
def test_preferences_orm(test_client):
"""preferences, via ORM and legacy ScoDoc"""
d = Departement(acronym="TT")
p1 = ScoPreference(name="temperature", value="24", departement=d)
p2 = ScoPreference(name="couleur", value="bleue", departement=d)
db.session.add(d)
db.session.add(p1)
db.session.add(p2)
db.session.commit()
prefs = d.preferences.all()
assert isinstance(prefs, list)
assert len(prefs) == 2
def test_preferences(test_client):
"""ScoDoc preferences"""
# preferences "globales" d'un département:
current_dept = Departement.query.filter_by(acronym=g.scodoc_dept).first()
prefs = sco_preferences.get_base_preferences()
assert isinstance(prefs, sco_preferences.BasePreferences)
assert prefs.dept_id == current_dept.id
# Compare nombre de d'items
assert len(ScoPreference.query.filter_by(dept_id=current_dept.id).all()) == len(
prefs
)
# Accès à une valeur via ORM
assert (
len(
ScoPreference.query.filter_by(
dept_id=current_dept.id, name="abs_notification_mail_tmpl"
).all()
)
== 1
)
orm_val = (
ScoPreference.query.filter_by(
dept_id=current_dept.id, name="abs_notification_mail_tmpl"
)
.first()
.value
)
# Compare valeurs
sco_val = prefs.get(None, "abs_notification_mail_tmpl")
assert orm_val.strip() == sco_val.strip()
# nb: I don't understand why SQLAlchemy strips the string ?!
# --- Charge dans un autre département
# departement fictif créé ici:
d = Departement(acronym="D2")
db.session.add(d)
db.session.commit()
app.set_sco_dept("D2")
prefs2 = sco_preferences.get_base_preferences()
assert len(prefs2) == len(prefs)
prefs2.set(None, "abs_notification_mail_tmpl", "toto")
assert prefs2.get(None, "abs_notification_mail_tmpl") == "toto"
assert prefs.get(None, "abs_notification_mail_tmpl") != "toto"
orm_val = (
ScoPreference.query.filter_by(dept_id=d.id, name="abs_notification_mail_tmpl")
.first()
.value
)
assert orm_val == "toto"
# --- Preferences d'un semestre
# rejoure ce test pour avoir un semestre créé
test_sco_basic.run_sco_basic()
sem = sco_formsemestre.do_formsemestre_list(None)[0]
formsemestre_id = sem["formsemestre_id"]
semp = sco_preferences.SemPreferences(formsemestre_id=formsemestre_id)
assert semp["abs_notification_mail_tmpl"] == "toto"
assert semp.is_global("abs_notification_mail_tmpl")
# donne une valeur pour le semestre:
prefs2.set(formsemestre_id, "abs_notification_mail_tmpl", "foo")
assert not semp.is_global("abs_notification_mail_tmpl")
assert semp["abs_notification_mail_tmpl"] == "foo"

View File

@ -7,8 +7,8 @@
Utiliser comme: Utiliser comme:
pytest tests/unit/test_sco_basic.py pytest tests/unit/test_sco_basic.py
Au préalable, créer un département de test neuf: Au besoin, créer un base de test neuve:
flask sco-delete-dept TEST00 && flask sco-create-dept TEST00 ./tools/create_database.sh SCODOC_TEST
""" """
import random import random
@ -18,6 +18,7 @@ from flask import g
from config import TestConfig from config import TestConfig
from tests.unit import sco_fake_gen from tests.unit import sco_fake_gen
import app
from app.scodoc import notesdb as ndb from app.scodoc import notesdb as ndb
from app.scodoc import sco_abs from app.scodoc import sco_abs
from app.scodoc import sco_abs_views from app.scodoc import sco_abs_views
@ -38,7 +39,7 @@ def test_sco_basic(test_client):
Création 10 étudiants, formation, semestre, inscription etudiant, Création 10 étudiants, formation, semestre, inscription etudiant,
creation 1 evaluation, saisie 10 notes. creation 1 evaluation, saisie 10 notes.
""" """
ndb.set_sco_dept(DEPT) app.set_sco_dept(DEPT)
run_sco_basic() run_sco_basic()