From 9fd33cf6587f271358b9d5fe3a9d3e78eaec4898 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Thu, 9 Sep 2021 16:11:05 +0200 Subject: [PATCH] =?UTF-8?q?Acc=C3=A8s=20compatibles=20aux=20anciennes=20fo?= =?UTF-8?q?nctions=20API=20ScoDoc=207?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/sco_api.py | 10 ++++++++++ app/decorators.py | 44 +++++++++++++++++++++++++++++++++++++++++++ app/views/absences.py | 17 ++++++++++++++--- app/views/notes.py | 36 +++++++++++++++++++++++++++++------ app/views/scodoc.py | 11 ++++++++--- app/views/scolar.py | 3 ++- misc/example-api-1.py | 4 ++-- 7 files changed, 110 insertions(+), 15 deletions(-) diff --git a/app/api/sco_api.py b/app/api/sco_api.py index 02b35090d..46be85a7a 100644 --- a/app/api/sco_api.py +++ b/app/api/sco_api.py @@ -28,6 +28,16 @@ """API ScoDoc 9 """ # PAS ENCORE IMPLEMENTEE, juste un essai +# Pour P. Bouron, il faudrait en priorité l'équivalent de +# Scolarite/Notes/do_moduleimpl_withmodule_list +# Scolarite/Notes/evaluation_create +# Scolarite/Notes/evaluation_delete +# Scolarite/Notes/formation_list +# Scolarite/Notes/formsemestre_list +# Scolarite/Notes/formsemestre_partition_list +# Scolarite/Notes/groups_view +# Scolarite/Notes/moduleimpl_status +# Scolarite/setGroups from flask import jsonify, request, url_for, abort from app import db diff --git a/app/decorators.py b/app/decorators.py index a1a91f484..3696d56ca 100644 --- a/app/decorators.py +++ b/app/decorators.py @@ -16,8 +16,10 @@ from flask import request from flask_login import current_user from flask_login import login_required from flask import current_app +import flask_login import app +from app.auth.models import User class ZUser(object): @@ -141,6 +143,48 @@ def permission_required(permission): return decorator +def permission_required_compat_scodoc7(permission): + """Décorateur pour les fonctions utilisée comme API dans ScoDoc 7 + Comme @permission_required mais autorise de passer directement + les informations d'auth en paramètres: + __ac_name, __ac_password + """ + + def decorator(f): + @wraps(f) + def decorated_function(*args, **kwargs): + # current_app.logger.warning("PERMISSION; kwargs=%s" % str(kwargs)) + # cherche les paramètre d'auth: + auth_ok = False + if request.method == "GET": + user_name = request.args.get("__ac_name") + user_password = request.args.get("__ac_password") + elif request.method == "POST": + user_name = request.form.get("__ac_name") + user_password = request.form.get("__ac_password") + else: + abort(405) # method not allowed + if user_name and user_password: + u = User.query.filter_by(user_name=user_name).first() + if u and u.check_password(user_password): + auth_ok = True + flask_login.login_user(u) + + # reprend le chemin classique: + scodoc_dept = getattr(g, "scodoc_dept", None) + + if not current_user.has_permission(permission, scodoc_dept): + abort(403) + if auth_ok: + return f(*args, **kwargs) + else: + return login_required(f)(*args, **kwargs) + + return decorated_function + + return decorator + + def admin_required(f): from app.auth.models import Permission diff --git a/app/views/absences.py b/app/views/absences.py index 6216dc7ef..6c84fec8f 100644 --- a/app/views/absences.py +++ b/app/views/absences.py @@ -68,6 +68,7 @@ from app.decorators import ( permission_required, admin_required, login_required, + permission_required_compat_scodoc7, ) from app.views import absences_bp as bp @@ -1236,7 +1237,7 @@ def listeBilletsEtud(etudid=False, REQUEST=None, format="html"): @bp.route("/XMLgetBilletsEtud") @scodoc -@permission_required(Permission.ScoView) +@permission_required_compat_scodoc7(Permission.ScoView) @scodoc7func def XMLgetBilletsEtud(etudid=False, REQUEST=None): """Liste billets pour un etudiant""" @@ -1250,7 +1251,7 @@ def XMLgetBilletsEtud(etudid=False, REQUEST=None): @bp.route("/listeBillets") @scodoc -@permission_required(Permission.ScoView) +@permission_required_compat_scodoc7(Permission.ScoView) @scodoc7func def listeBillets(REQUEST=None): """Page liste des billets non traités et formulaire recherche d'un billet""" @@ -1459,9 +1460,19 @@ def ProcessBilletAbsenceForm(billet_id, REQUEST=None): return "\n".join(H) + html_sco_header.sco_footer() +# @bp.route("/essai_api7") +# @scodoc +# @permission_required_compat_scodoc7(Permission.ScoView) +# @scodoc7func +# def essai_api7(x="xxx"): +# "un essai" +# log("arfffffffffffffffffff") +# return "OK OK x=" + str(x) + + @bp.route("/XMLgetAbsEtud") @scodoc -@permission_required(Permission.ScoView) +@permission_required_compat_scodoc7(Permission.ScoView) @scodoc7func def XMLgetAbsEtud(beg_date="", end_date="", REQUEST=None): """returns list of absences in date interval""" diff --git a/app/views/notes.py b/app/views/notes.py index 7e80550b5..7fbc63184 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -50,6 +50,7 @@ from app.decorators import ( scodoc, scodoc7func, permission_required, + permission_required_compat_scodoc7, admin_required, login_required, ) @@ -252,11 +253,34 @@ sco_publish( Permission.ScoChangeFormation, methods=["GET", "POST"], ) -sco_publish( - "/formsemestre_bulletinetud", - sco_bulletins.formsemestre_bulletinetud, - Permission.ScoView, -) + + +@bp.route("formsemestre_bulletinetud") +@scodoc +@permission_required_compat_scodoc7(Permission.ScoView) +@scodoc7func +def formsemestre_bulletinetud( + etudid=None, + formsemestre_id=None, + format="html", + version="long", + xml_with_decisions=False, + force_publishing=False, + prefer_mail_perso=False, + REQUEST=None, +): + return sco_bulletins.formsemestre_bulletinetud( + etudid=etudid, + formsemestre_id=formsemestre_id, + format=format, + version=version, + xml_with_decisions=xml_with_decisions, + force_publishing=force_publishing, + prefer_mail_perso=prefer_mail_perso, + REQUEST=REQUEST, + ) + + sco_publish( "/formsemestre_evaluations_cal", sco_evaluations.formsemestre_evaluations_cal, @@ -601,7 +625,7 @@ def formsemestre_list( @bp.route("/XMLgetFormsemestres") @scodoc -@permission_required(Permission.ScoView) +@permission_required_compat_scodoc7(Permission.ScoView) @scodoc7func def XMLgetFormsemestres(etape_apo=None, formsemestre_id=None, REQUEST=None): """List all formsemestres matching etape, XML format diff --git a/app/views/scodoc.py b/app/views/scodoc.py index d2fd9f9d4..88aa7a1e7 100644 --- a/app/views/scodoc.py +++ b/app/views/scodoc.py @@ -30,6 +30,7 @@ Module main: page d'accueil, avec liste des départements Emmanuel Viennet, 2021 """ +from app.auth.models import User import os import flask @@ -53,7 +54,11 @@ import sco_version from app.scodoc import sco_logos from app.scodoc import sco_find_etud from app.scodoc import sco_utils as scu -from app.decorators import admin_required +from app.decorators import ( + admin_required, + scodoc7func, + permission_required_compat_scodoc7, +) from app.scodoc.sco_permissions import Permission from app.views import scodoc_bp as bp @@ -82,12 +87,12 @@ def table_etud_in_accessible_depts(): return sco_find_etud.table_etud_in_accessible_depts(expnom=request.form["expnom"]) +# Fonction d'API accessible sans aucun authentification @bp.route("/ScoDoc/get_etud_dept") -@login_required def get_etud_dept(): """Returns the dept acronym (eg "GEII") of an etud (identified by etudid, code_nip ou code_ine in the request). - API: ramène la chaine brute, sans JSON ou XML. + Ancienne API: ramène la chaine brute, texte sans JSON ou XML. """ if "etudid" in request.args: # zero ou une réponse: diff --git a/app/views/scolar.py b/app/views/scolar.py index 733716193..8f0267821 100644 --- a/app/views/scolar.py +++ b/app/views/scolar.py @@ -52,6 +52,7 @@ from app.decorators import ( scodoc, scodoc7func, permission_required, + permission_required_compat_scodoc7, admin_required, login_required, ) @@ -402,7 +403,7 @@ def search_etud_by_name(): @bp.route("/etud_info") @bp.route("/XMLgetEtudInfos") @scodoc -@permission_required(Permission.ScoView) +@permission_required_compat_scodoc7(Permission.ScoView) @scodoc7func def etud_info(etudid=None, format="xml", REQUEST=None): "Donne les informations sur un etudiant" diff --git a/misc/example-api-1.py b/misc/example-api-1.py index 171365e58..e79b329a3 100644 --- a/misc/example-api-1.py +++ b/misc/example-api-1.py @@ -36,7 +36,7 @@ class ScoError(Exception): def GET(s, path, errmsg=None): """Get and returns as JSON""" - r = s.get(BASEURL + "/" + path) + r = s.get(BASEURL + "/" + path, verify=CHECK_CERTIFICATE) if r.status_code != 200: raise ScoError(errmsg or "erreur !") return r.json() # decode la reponse JSON @@ -44,7 +44,7 @@ def GET(s, path, errmsg=None): def POST(s, path, data, errmsg=None): """Post""" - r = s.post(BASEURL + "/" + path, data=data) + r = s.post(BASEURL + "/" + path, data=data, verify=CHECK_CERTIFICATE) if r.status_code != 200: raise ScoError(errmsg or "erreur !") return r.text