API ScoDoc 7: autorise POSTs, ajoute groups_view, script exemple/test

This commit is contained in:
Emmanuel Viennet 2021-11-01 16:59:56 +01:00
parent 01a84f3b12
commit 7589d4cc34
4 changed files with 109 additions and 21 deletions

View File

@ -50,9 +50,15 @@ def scodoc(func):
@wraps(func) @wraps(func)
def scodoc_function(*args, **kwargs): def scodoc_function(*args, **kwargs):
# current_app.logger.info("@scodoc") # print("@scodoc")
# interdit les POST si pas loggué # interdit les POST si pas loggué
if request.method == "POST" and not current_user.is_authenticated: if (
request.method == "POST"
and not current_user.is_authenticated
and not request.form.get(
"__ac_password"
) # exception pour compat API ScoDoc7
):
current_app.logger.info( current_app.logger.info(
"POST by non authenticated user (request.form=%s)", "POST by non authenticated user (request.form=%s)",
str(request.form)[:2048], str(request.form)[:2048],
@ -103,7 +109,7 @@ def permission_required_compat_scodoc7(permission):
@wraps(f) @wraps(f)
def decorated_function(*args, **kwargs): def decorated_function(*args, **kwargs):
# cherche les paramètre d'auth: # cherche les paramètre d'auth:
# current_app.logger.info("@permission_required_compat_scodoc7") # print("@permission_required_compat_scodoc7")
auth_ok = False auth_ok = False
if request.method == "GET": if request.method == "GET":
user_name = request.args.get("__ac_name") user_name = request.args.get("__ac_name")
@ -154,7 +160,7 @@ def scodoc7func(func):
2. or be called directly from Python. 2. or be called directly from Python.
""" """
# current_app.logger.info("@scodoc7func") # print("@scodoc7func")
# 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.
top_level = not hasattr(g, "scodoc7_decorated") top_level = not hasattr(g, "scodoc7_decorated")

View File

@ -1058,7 +1058,8 @@ def AddBilletAbsence(
code_nip=None, code_nip=None,
code_ine=None, code_ine=None,
justified=True, justified=True,
xml_reply=True, format="json",
xml_reply=True, # deprecated
): ):
"""Mémorise un "billet" """Mémorise un "billet"
begin et end sont au format ISO (eg "1999-01-08 04:05:06") begin et end sont au format ISO (eg "1999-01-08 04:05:06")
@ -1082,6 +1083,7 @@ def AddBilletAbsence(
raise ValueError("invalid dates") raise ValueError("invalid dates")
# #
justified = bool(justified) justified = bool(justified)
xml_reply = bool(xml_reply)
# #
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
billet_id = sco_abs.billet_absence_create( billet_id = sco_abs.billet_absence_create(
@ -1095,14 +1097,14 @@ def AddBilletAbsence(
"justified": justified, "justified": justified,
}, },
) )
if xml_reply: if xml_reply: # backward compat
# Renvoie le nouveau billet en XML format = "xml"
# Renvoie le nouveau billet au format demandé
billets = sco_abs.billet_absence_list(cnx, {"billet_id": billet_id}) billets = sco_abs.billet_absence_list(cnx, {"billet_id": billet_id})
tab = _tableBillets(billets, etud=etud) tab = _tableBillets(billets, etud=etud)
log("AddBilletAbsence: new billet_id=%s (%gs)" % (billet_id, time.time() - t0)) log("AddBilletAbsence: new billet_id=%s (%gs)" % (billet_id, time.time() - t0))
return tab.make_page(format="xml") return tab.make_page(format=format)
else:
return billet_id
@bp.route("/AddBilletAbsenceForm", methods=["GET", "POST"]) @bp.route("/AddBilletAbsenceForm", methods=["GET", "POST"])

View File

@ -302,7 +302,34 @@ sco_publish(
methods=["GET", "POST"], methods=["GET", "POST"],
) )
sco_publish("/groups_view", sco_groups_view.groups_view, Permission.ScoView)
@bp.route("/groups_view")
@scodoc
@permission_required_compat_scodoc7(Permission.ScoView)
@scodoc7func
def groups_view(
group_ids=(),
format="html",
# Options pour listes:
with_codes=0,
etat=None,
with_paiement=0, # si vrai, ajoute colonnes infos paiement droits et finalisation inscription (lent car interrogation portail)
with_archives=0, # ajoute colonne avec noms fichiers archivés
with_annotations=0,
formsemestre_id=None,
):
return sco_groups_view.groups_view(
group_ids=(),
format=format,
# Options pour listes:
with_codes=with_codes,
etat=etat,
with_paiement=with_paiement, # si vrai, ajoute colonnes infos paiement droits et finalisation inscription (lent car interrogation portail)
with_archives=with_archives, # ajoute colonne avec noms fichiers archivés
with_annotations=with_annotations,
formsemestre_id=formsemestre_id,
)
sco_publish( sco_publish(
"/export_groups_as_moodle_csv", "/export_groups_as_moodle_csv",

View File

@ -6,7 +6,7 @@
à la mode "PHP": les gens passaient directement __ac_name et __ac_password à la mode "PHP": les gens passaient directement __ac_name et __ac_password
dans chaque requête, en POST ou en GET. dans chaque requête, en POST ou en GET.
Cela n'a jamais été documenté mais était implitement supporté. C'est "deprecated" Cela n'a jamais été documenté mais était implicitement supporté. C'est "deprecated"
et ne sera plus supporté à partir de juillet 2022. et ne sera plus supporté à partir de juillet 2022.
Ce script va tester: Ce script va tester:
@ -27,6 +27,7 @@ export CHECK_CERTIFICATE=0 # ou 1 si serveur de production avec certif SSL valid
""" """
from dotenv import load_dotenv from dotenv import load_dotenv
import json
import os import os
import pdb import pdb
import requests import requests
@ -66,12 +67,10 @@ def GET(path: str, params=None, errmsg=None):
def POST(path: str, data: dict, errmsg=None): def POST(path: str, data: dict, errmsg=None):
"""Post""" """Post"""
data["__ac_name"] = SCODOC_USER data["__ac_name"] = data.get("__ac_name", SCODOC_USER)
data["__ac_password"] = SCODOC_PASSWORD data["__ac_password"] = data.get("__ac_password", SCODOC_PASSWORD)
r = requests.post(DEPT_URL + "/" + path, data=data, verify=CHECK_CERTIFICATE) r = requests.post(DEPT_URL + "/" + path, data=data, verify=CHECK_CERTIFICATE)
if r.status_code != 200: return r
raise ScoError(errmsg or "erreur !")
return r.text
# --- # ---
@ -91,7 +90,61 @@ if sem["etat"] == "0":
# Affiche le semestre trouvé: # Affiche le semestre trouvé:
pp(sem) pp(sem)
# Les fonctions ci-dessous ne fonctionne plus en ScoDoc 9 # Liste des étudiants dans le 1er semestre non verrouillé:
group_list = GET(
"groups_view",
params={
"formsemestre_id": sem["formsemestre_id"],
"with_codes": 1,
"format": "json",
},
)
if not group_list:
# config inadaptée pour les tests...
raise ScoError("aucun étudiant inscrit dans le semestre")
etud = group_list[0] # le premier étudiant inscrit ici
# test un POST
r = POST(
"Absences/AddBilletAbsence",
{
"begin": "2021-10-25",
"end": "2021-10-26",
"description": "test API scodoc7",
"etudid": etud["etudid"],
},
)
assert r.status_code == 200
assert r.text.startswith('<?xml version="1.0" encoding="utf-8"?>')
assert "billet_id" in r.text
# Essai avec un compte invalide
r_invalid = POST(
"Absences/AddBilletAbsence",
{
"__ac_name": "xxx",
"begin": "2021-10-25",
"end": "2021-10-26",
"description": "test API scodoc7",
"etudid": etud["etudid"],
},
)
assert r_invalid.status_code == 403 # compte invalide => not authorized
# AddBilletAbsence en json
r = POST(
"Absences/AddBilletAbsence",
{
"begin": "2021-10-25",
"end": "2021-10-26",
"description": "test API scodoc7",
"etudid": etud["etudid"],
"xml_reply": 0,
},
)
assert r.status_code == 200
assert isinstance(json.loads(r.text)[0]["billet_id"], int)
# Les fonctions ci-dessous ne fonctionnent plus en ScoDoc 9
# Voir https://scodoc.org/git/viennet/ScoDoc/issues/149 # Voir https://scodoc.org/git/viennet/ScoDoc/issues/149
# # ---- Liste les modules et prend le premier # # ---- Liste les modules et prend le premier