From aa1ec6fd8e36d00fd592e4d76070b2f385dfb8b0 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Fri, 22 Jul 2022 16:39:21 +0200 Subject: [PATCH] =?UTF-8?q?API:=20modification=20pour=20acc=C3=A8s=20via?= =?UTF-8?q?=20cookie=20web?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/absences.py | 16 +++++-------- app/api/auth.py | 44 +++++++++++++++++++++++++++------- app/api/departements.py | 32 +++++++++---------------- app/api/errors.py | 2 ++ app/api/etudiants.py | 23 +++++++----------- app/api/evaluations.py | 8 +++---- app/api/formations.py | 20 ++++++---------- app/api/formsemestres.py | 23 +++++++----------- app/api/jury.py | 2 +- app/api/logos.py | 14 ++++------- app/api/partitions.py | 35 ++++++++++----------------- tests/api/exemple-api-basic.py | 22 +++++++++++------ 12 files changed, 114 insertions(+), 127 deletions(-) diff --git a/app/api/absences.py b/app/api/absences.py index a352bc0c..992f484f 100644 --- a/app/api/absences.py +++ b/app/api/absences.py @@ -10,20 +10,18 @@ from flask import jsonify from app.api import bp from app.api.errors import error_response -from app.api.auth import token_auth, token_permission_required +from app.api.auth import permission_required_api from app.models import Identite from app.scodoc import notesdb as ndb from app.scodoc import sco_abs -# from app.scodoc.sco_abs import annule_absence, annule_justif, add_abslist from app.scodoc.sco_groups import get_group_members from app.scodoc.sco_permissions import Permission @bp.route("/absences/etudid/", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def absences(etudid: int = None): """ Retourne la liste des absences d'un étudiant donné @@ -67,8 +65,7 @@ def absences(etudid: int = None): @bp.route("/absences/etudid//just", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def absences_just(etudid: int = None): """ Retourne la liste des absences justifiées d'un étudiant donné @@ -123,8 +120,7 @@ def absences_just(etudid: int = None): "/absences/abs_group_etat/group_id//date_debut//date_fin/", methods=["GET"], ) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def abs_groupe_etat(group_id: int, date_debut=None, date_fin=None): """ Liste des absences d'un groupe (possibilité de choisir entre deux dates) @@ -170,11 +166,11 @@ def abs_groupe_etat(group_id: int, date_debut=None, date_fin=None): data = [] # Filtre entre les deux dates renseignées for member in members: - abs = { + absence = { "etudid": member["etudid"], "list_abs": sco_abs.list_abs_date(member["etudid"], date_debut, date_fin), } - data.append(abs) + data.append(absence) return jsonify(data) diff --git a/app/api/auth.py b/app/api/auth.py index 67d6fba1..1c6738b3 100644 --- a/app/api/auth.py +++ b/app/api/auth.py @@ -26,10 +26,9 @@ from functools import wraps - -from flask import abort from flask import g from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth +from flask_login import current_user from app import log from app.auth.models import User @@ -57,7 +56,10 @@ def basic_auth_error(status): @token_auth.verify_token def verify_token(token) -> User: - "Retrouve l'utilisateur à partir du jeton" + """Retrouve l'utilisateur à partir du jeton. + Si la requête n'a pas de jeton, token == "". + """ + user = User.check_token(token) if token else None g.current_user = user return user @@ -65,7 +67,7 @@ def verify_token(token) -> User: @token_auth.error_handler def token_auth_error(status): - "rréponse en cas d'erreur d'auth." + "Réponse en cas d'erreur d'auth." return error_response(status) @@ -75,7 +77,7 @@ def get_user_roles(user): def token_permission_required(permission): - "Décorateur pour les fontions de l'API ScoDoc" + "Décorateur pour les fonctions de l'API ScoDoc" def decorator(f): @wraps(f) @@ -84,13 +86,39 @@ def token_permission_required(permission): current_user = basic_auth.current_user() if not current_user or not current_user.has_permission(permission, None): if current_user: - log(f"API permission denied (user {current_user})") + message = f"API permission denied (user {current_user})" else: - log("API permission denied (no user supplied)") - abort(403) + message = f"API permission denied (no user supplied)" + log(message) + # raise werkzeug.exceptions.Forbidden(description=message) + return error_response(403, message=None) return f(*args, **kwargs) # return decorated_function(token_auth.login_required()) return decorated_function return decorator + + +def permission_required_api(permission_web, permission_api): + """Décorateur pour les fonctions de l'API accessibles en mode jeton + ou en mode web. + Si cookie d'authentification web, utilise pour se logger et calculer les + permissions. + Sinon, tente le jeton jwt. + """ + + def decorator(f): + @wraps(f) + def decorated_function(*args, **kwargs): + scodoc_dept = getattr(g, "scodoc_dept", None) + if not current_user.has_permission(permission_web, scodoc_dept): + # try API + return token_auth.login_required( + token_permission_required(permission_api)(f) + )(*args, **kwargs) + return f(*args, **kwargs) + + return decorated_function + + return decorator diff --git a/app/api/departements.py b/app/api/departements.py index 16ad902a..12b19b0d 100644 --- a/app/api/departements.py +++ b/app/api/departements.py @@ -5,7 +5,7 @@ from flask import jsonify import app from app import models from app.api import bp -from app.api.auth import token_auth, token_permission_required +from app.api.auth import permission_required_api from app.models import Departement, FormSemestre from app.scodoc.sco_permissions import Permission @@ -22,24 +22,21 @@ def get_departement(dept_ident: str) -> Departement: @bp.route("/departements", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def departements(): """Liste les départements""" return jsonify([dept.to_dict() for dept in Departement.query]) @bp.route("/departements_ids", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def departements_ids(): """Liste des ids de départements""" return jsonify([dept.id for dept in Departement.query]) @bp.route("/departement/", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def departement(acronym: str): """ Info sur un département. Accès par acronyme. @@ -58,8 +55,7 @@ def departement(acronym: str): @bp.route("/departement/id/", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def departement_by_id(dept_id: int): """ Info sur un département. Accès par id. @@ -69,8 +65,7 @@ def departement_by_id(dept_id: int): @bp.route("/departement//etudiants", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def dept_etudiants(acronym: str): """ Retourne la liste des étudiants d'un département @@ -98,8 +93,7 @@ def dept_etudiants(acronym: str): @bp.route("/departement/id//etudiants", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def dept_etudiants_by_id(dept_id: int): """ Retourne la liste des étudiants d'un département d'id donné. @@ -109,8 +103,7 @@ def dept_etudiants_by_id(dept_id: int): @bp.route("/departement//formsemestres_ids", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def dept_formsemestres_ids(acronym: str): """liste des ids formsemestre du département""" dept = Departement.query.filter_by(acronym=acronym).first_or_404() @@ -118,8 +111,7 @@ def dept_formsemestres_ids(acronym: str): @bp.route("/departement/id//formsemestres_ids", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def dept_formsemestres_ids_by_id(dept_id: int): """liste des ids formsemestre du département""" dept = Departement.query.get_or_404(dept_id) @@ -127,8 +119,7 @@ def dept_formsemestres_ids_by_id(dept_id: int): @bp.route("/departement//formsemestres_courants", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def dept_formsemestres_courants(acronym: str): """ Liste des semestres actifs d'un département d'acronyme donné @@ -182,8 +173,7 @@ def dept_formsemestres_courants(acronym: str): @bp.route("/departement/id//formsemestres_courants", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def dept_formsemestres_courants_by_id(dept_id: int): """ Liste des semestres actifs d'un département d'id donné diff --git a/app/api/errors.py b/app/api/errors.py index b86d2b23..9bf54910 100644 --- a/app/api/errors.py +++ b/app/api/errors.py @@ -27,6 +27,7 @@ from werkzeug.http import HTTP_STATUS_CODES def error_response(status_code, message=None): + """Réponse sur erreur""" payload = {"error": HTTP_STATUS_CODES.get(status_code, "Unknown error")} if message: payload["message"] = message @@ -36,4 +37,5 @@ def error_response(status_code, message=None): def bad_request(message): + "400 Bad Request response" return error_response(400, message) diff --git a/app/api/etudiants.py b/app/api/etudiants.py index 2979ac73..c4476439 100644 --- a/app/api/etudiants.py +++ b/app/api/etudiants.py @@ -8,25 +8,23 @@ API : accès aux étudiants """ -from flask import jsonify, make_response +from flask import jsonify import app from app.api import bp from app.api.errors import error_response -from app.api.auth import token_auth, token_permission_required +from app.api.auth import permission_required_api from app.api import tools from app.models import Departement, FormSemestreInscription, FormSemestre, Identite from app.scodoc import sco_bulletins from app.scodoc import sco_groups from app.scodoc.sco_bulletins import do_formsemestre_bulletinetud from app.scodoc.sco_permissions import Permission -from app.scodoc import sco_utils as scu @bp.route("/etudiants/courants", defaults={"long": False}) @bp.route("/etudiants/courants/long", defaults={"long": True}) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def etudiants_courants(long=False): """ Liste des étudiants inscrits dans un formsemestre actuellement en cours. @@ -66,8 +64,7 @@ def etudiants_courants(long=False): @bp.route("/etudiant/etudid/", methods=["GET"]) @bp.route("/etudiant/nip/", methods=["GET"]) @bp.route("/etudiant/ine/", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def etudiant(etudid: int = None, nip: str = None, ine: str = None): """ Retourne les informations de l'étudiant correspondant, ou 404 si non trouvé. @@ -121,8 +118,7 @@ def etudiant(etudid: int = None, nip: str = None, ine: str = None): @bp.route("/etudiants/etudid/", methods=["GET"]) @bp.route("/etudiants/nip/", methods=["GET"]) @bp.route("/etudiants/ine/", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def etudiants(etudid: int = None, nip: str = None, ine: str = None): """ Info sur le ou les étudiants correspondant. Comme /etudiant mais renvoie @@ -149,8 +145,7 @@ def etudiants(etudid: int = None, nip: str = None, ine: str = None): @bp.route("/etudiant/etudid//formsemestres") @bp.route("/etudiant/nip//formsemestres") @bp.route("/etudiant/ine//formsemestres") -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def etudiant_formsemestres(etudid: int = None, nip: int = None, ine: int = None): """ Liste des semestres qu'un étudiant a suivi, triés par ordre chronologique. @@ -282,8 +277,7 @@ def etudiant_formsemestres(etudid: int = None, nip: int = None, ine: int = None) methods=["GET"], defaults={"version": "short", "pdf": True}, ) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def etudiant_bulletin_semestre( # XXX TODO Ajouter la possibilité de retourner en version pdf formsemestre_id, etudid: int = None, @@ -349,8 +343,7 @@ def etudiant_bulletin_semestre( # XXX TODO Ajouter la possibilité de retourner "/etudiant/ine//formsemestre//groups", methods=["GET"], ) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def etudiant_groups( formsemestre_id: int, etudid: int = None, nip: int = None, ine: int = None ): diff --git a/app/api/evaluations.py b/app/api/evaluations.py index b831d088..43d17722 100644 --- a/app/api/evaluations.py +++ b/app/api/evaluations.py @@ -14,7 +14,7 @@ import app from app import models from app.api import bp -from app.api.auth import token_auth, token_permission_required +from app.api.auth import permission_required_api from app.api.errors import error_response from app.models import Evaluation from app.scodoc.sco_evaluation_db import do_evaluation_get_all_notes @@ -22,8 +22,7 @@ from app.scodoc.sco_permissions import Permission @bp.route("/evaluations/", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def evaluations(moduleimpl_id: int): """ Retourne la liste des évaluations d'un moduleimpl @@ -65,8 +64,7 @@ def evaluations(moduleimpl_id: int): @bp.route("/evaluation/eval_notes/", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def evaluation_notes(evaluation_id: int): """ Retourne la liste des notes à partir de l'id d'une évaluation donnée diff --git a/app/api/formations.py b/app/api/formations.py index d0a69ab5..a851647a 100644 --- a/app/api/formations.py +++ b/app/api/formations.py @@ -14,15 +14,14 @@ import app from app import models from app.api import bp from app.api.errors import error_response -from app.api.auth import token_auth, token_permission_required +from app.api.auth import permission_required_api from app.models.formations import Formation from app.scodoc import sco_formations from app.scodoc.sco_permissions import Permission @bp.route("/formations", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def formations(): """ Retourne la liste de toutes les formations (tous départements) @@ -33,8 +32,7 @@ def formations(): @bp.route("/formations_ids", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def formations_ids(): """ Retourne la liste de toutes les id de formations (tous départements) @@ -46,8 +44,7 @@ def formations_ids(): @bp.route("/formation/", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def formation_by_id(formation_id: int): """ La formation d'id donné @@ -83,8 +80,7 @@ def formation_by_id(formation_id: int): methods=["GET"], defaults={"export_ids": True}, ) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def formation_export_by_formation_id(formation_id: int, export_ids=False): """ Retourne la formation, avec UE, matières, modules @@ -192,8 +188,7 @@ def formation_export_by_formation_id(formation_id: int, export_ids=False): @bp.route("/formation/moduleimpl/", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def moduleimpl(moduleimpl_id: int): """ Retourne un module moduleimpl en fonction de son id @@ -237,8 +232,7 @@ def moduleimpl(moduleimpl_id: int): "/formation//referentiel_competences", methods=["GET"], ) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def referentiel_competences(formation_id: int): """ Retourne le référentiel de compétences diff --git a/app/api/formsemestres.py b/app/api/formsemestres.py index d7385b28..a27a68f8 100644 --- a/app/api/formsemestres.py +++ b/app/api/formsemestres.py @@ -12,7 +12,7 @@ from flask import abort, jsonify, request import app from app import models from app.api import bp -from app.api.auth import token_auth, token_permission_required +from app.api.auth import permission_required_api from app.comp import res_sem from app.comp.moy_mod import ModuleImplResults from app.comp.res_compat import NotesTableCompat @@ -25,8 +25,7 @@ import app.scodoc.sco_utils as scu @bp.route("/formsemestre/", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def formsemestre_infos(formsemestre_id: int): """ Information sur le formsemestre indiqué. @@ -69,8 +68,7 @@ def formsemestre_infos(formsemestre_id: int): @bp.route("/formsemestres/query", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def formsemestres_query(): """ Retourne les formsemestres filtrés par @@ -115,8 +113,7 @@ def formsemestres_query(): @bp.route("/formsemestre//bulletins", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def bulletins(formsemestre_id: int): """ Retourne les bulletins d'un formsemestre donné @@ -140,8 +137,7 @@ def bulletins(formsemestre_id: int): "/formsemestre//programme", methods=["GET"], ) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def formsemestre_programme(formsemestre_id: int): """ Retourne la liste des Ues, ressources et SAE d'un semestre @@ -242,8 +238,7 @@ def formsemestre_programme(formsemestre_id: int): methods=["GET"], defaults={"etat": scu.DEF}, ) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def formsemestre_etudiants(formsemestre_id: int, etat: str): """ Retourne la liste des étudiants d'un formsemestre @@ -265,8 +260,7 @@ def formsemestre_etudiants(formsemestre_id: int, etat: str): @bp.route("/formsemestre//etat_evals", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def etat_evals(formsemestre_id: int): """ Informations sur l'état des évaluations d'un formsemestre. @@ -372,8 +366,7 @@ def etat_evals(formsemestre_id: int): @bp.route("/formsemestre//resultats", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def formsemestre_resultat(formsemestre_id: int): """Tableau récapitulatif des résultats Pour chaque étudiant, son état, ses groupes, ses moyennes d'UE et de modules. diff --git a/app/api/jury.py b/app/api/jury.py index 1131a284..1f42abff 100644 --- a/app/api/jury.py +++ b/app/api/jury.py @@ -4,7 +4,7 @@ # from app import models # from app.api import bp # from app.api.errors import error_response -# from app.api.auth import token_auth, token_permission_required +# from app.api.auth import permission_required_api # from app.scodoc.sco_prepajury import feuille_preparation_jury # from app.scodoc.sco_pvjury import formsemestre_pvjury diff --git a/app/api/logos.py b/app/api/logos.py index a2c1fbde..9fd9cade 100644 --- a/app/api/logos.py +++ b/app/api/logos.py @@ -38,13 +38,12 @@ from app.api.auth import token_auth from app.api.errors import error_response from app.models import Departement from app.scodoc.sco_logos import list_logos, find_logo -from app.api.auth import token_auth, token_permission_required +from app.api.auth import permission_required_api from app.scodoc.sco_permissions import Permission @bp.route("/logos", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def api_get_glob_logos(): if not g.current_user.has_permission(Permission.ScoSuperAdmin, None): return error_response(401, message="accès interdit") @@ -56,8 +55,7 @@ def api_get_glob_logos(): @bp.route("/logos/", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def api_get_glob_logo(logoname): if not g.current_user.has_permission(Permission.ScoSuperAdmin, None): return error_response(401, message="accès interdit") @@ -73,8 +71,7 @@ def api_get_glob_logo(logoname): @bp.route("/departements//logos", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def api_get_local_logos(departement): dept_id = Departement.from_acronym(departement).id if not g.current_user.has_permission(Permission.ScoChangePreferences, departement): @@ -84,8 +81,7 @@ def api_get_local_logos(departement): @bp.route("/departements//logos/", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def api_get_local_logo(departement, logoname): # format = requested_format("jpg", ['png', 'jpg']) XXX ? dept_id = Departement.from_acronym(departement).id diff --git a/app/api/partitions.py b/app/api/partitions.py index 5c3145ad..c8c2133b 100644 --- a/app/api/partitions.py +++ b/app/api/partitions.py @@ -12,7 +12,7 @@ from flask import abort, jsonify, request import app from app import db, log from app.api import bp -from app.api.auth import token_auth, token_permission_required +from app.api.auth import permission_required_api from app.models import FormSemestre, FormSemestreInscription, Identite from app.models import GroupDescr, Partition from app.models.groups import group_membership @@ -22,8 +22,7 @@ from app.scodoc import sco_utils as scu @bp.route("/partition/", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def partition_info(partition_id: int): """ Exemple de résultat : @@ -48,8 +47,7 @@ def partition_info(partition_id: int): @bp.route("/formsemestre//partitions", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def formsemestre_partitions(formsemestre_id: int): """ Retourne la liste de toutes les partitions d'un formsemestre @@ -64,8 +62,7 @@ def formsemestre_partitions(formsemestre_id: int): @bp.route("/group//etudiants", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def etud_in_group(group_id: int): """ Retourne la liste des étudiants dans un groupe @@ -91,8 +88,7 @@ def etud_in_group(group_id: int): @bp.route("/group//etudiants/query", methods=["GET"]) -@token_auth.login_required -@token_permission_required(Permission.APIView) +@permission_required_api(Permission.ScoView, Permission.APIView) def etud_in_group_query(group_id: int): """Etudiants du groupe, filtrés par état""" etat = request.args.get("etat") @@ -110,8 +106,7 @@ def etud_in_group_query(group_id: int): @bp.route("/group//set_etudiant/", methods=["POST"]) -@token_auth.login_required -@token_permission_required(Permission.APIEditGroups) +@permission_required_api(Permission.ScoEtudChangeGroups, Permission.APIEditGroups) def set_etud_group(etudid: int, group_id: int): """Affecte l'étudiant au groupe indiqué""" etud = Identite.query.get_or_404(etudid) @@ -136,8 +131,7 @@ def set_etud_group(etudid: int, group_id: int): @bp.route("/partition//group/create", methods=["POST"]) -@token_auth.login_required -@token_permission_required(Permission.APIEditGroups) +@permission_required_api(Permission.ScoEtudChangeGroups, Permission.APIEditGroups) def group_create(partition_id: int): """Création d'un groupe dans une partition @@ -167,8 +161,7 @@ def group_create(partition_id: int): @bp.route("/group//delete", methods=["POST"]) -@token_auth.login_required -@token_permission_required(Permission.APIEditGroups) +@permission_required_api(Permission.ScoEtudChangeGroups, Permission.APIEditGroups) def group_delete(group_id: int): """Suppression d'un groupe""" group = GroupDescr.query.get_or_404(group_id) @@ -184,8 +177,7 @@ def group_delete(group_id: int): @bp.route("/group//edit", methods=["POST"]) -@token_auth.login_required -@token_permission_required(Permission.APIEditGroups) +@permission_required_api(Permission.ScoEtudChangeGroups, Permission.APIEditGroups) def group_edit(group_id: int): """Edit a group""" group: GroupDescr = GroupDescr.query.get_or_404(group_id) @@ -206,8 +198,7 @@ def group_edit(group_id: int): @bp.route("/formsemestre//partition/create", methods=["POST"]) -@token_auth.login_required -@token_permission_required(Permission.APIEditGroups) +@permission_required_api(Permission.ScoEtudChangeGroups, Permission.APIEditGroups) def partition_create(formsemestre_id: int): """Création d'une partition dans un semestre @@ -253,8 +244,7 @@ def partition_create(formsemestre_id: int): @bp.route("/partition//edit", methods=["POST"]) -@token_auth.login_required -@token_permission_required(Permission.APIEditGroups) +@permission_required_api(Permission.ScoEtudChangeGroups, Permission.APIEditGroups) def partition_edit(partition_id: int): """Modification d'une partition dans un semestre @@ -306,8 +296,7 @@ def partition_edit(partition_id: int): @bp.route("/partition//delete", methods=["POST"]) -@token_auth.login_required -@token_permission_required(Permission.APIEditGroups) +@permission_required_api(Permission.ScoEtudChangeGroups, Permission.APIEditGroups) def partition_delete(partition_id: int): """Suppression d'une partition (et de tous ses groupes). diff --git a/tests/api/exemple-api-basic.py b/tests/api/exemple-api-basic.py index 126643bf..11254297 100644 --- a/tests/api/exemple-api-basic.py +++ b/tests/api/exemple-api-basic.py @@ -36,8 +36,13 @@ load_dotenv(os.path.join(BASEDIR, ".env")) CHK_CERT = bool(int(os.environ.get("CHECK_CERTIFICATE", False))) SCODOC_URL = os.environ.get("SCODOC_URL") or "http://localhost:5000" API_URL = SCODOC_URL + "/ScoDoc/api" +# Admin: SCODOC_USER = os.environ["SCODOC_USER"] SCODOC_PASSWORD = os.environ["SCODOC_PASSWORD"] +# Lecteur +SCODOC_USER_API_LECTEUR = os.environ["SCODOC_USER_API_LECTEUR"] +SCODOC_PASSWORD_API_LECTEUR = os.environ["SCODOC_PASSWORD_API_LECTEUR"] + print(f"SCODOC_URL={SCODOC_URL}") print(f"API URL={API_URL}") @@ -84,13 +89,16 @@ def POST_JSON(path: str, data: dict = {}, headers={}, errmsg=None): return r.json() # decode la reponse JSON -# --- Obtention du jeton (token) -r = requests.post(API_URL + "/tokens", auth=(SCODOC_USER, SCODOC_PASSWORD)) -assert r.status_code == 200 -token = r.json()["token"] -HEADERS = {"Authorization": f"Bearer {token}"} -# HEADERS_JSON = HEADERS.copy() -# HEADERS_JSON["Content-Type"] = "application/json" +def GET_TOKEN(user, password): + "Obtention du jeton (token)" + r = requests.post(API_URL + "/tokens", auth=(user, password)) + assert r.status_code == 200 + token = r.json()["token"] + return {"Authorization": f"Bearer {token}"} + + +HEADERS = GET_TOKEN(SCODOC_USER, SCODOC_PASSWORD) +HEADERS_USER = GET_TOKEN(SCODOC_USER_API_LECTEUR, SCODOC_PASSWORD_API_LECTEUR) r = requests.get(API_URL + "/departements", headers=HEADERS, verify=CHK_CERT) if r.status_code != 200: