From 06ca1363841dbb288ec929d333cd8487f8b05b3b Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 21 Dec 2021 00:10:51 +0100 Subject: [PATCH] =?UTF-8?q?Exemple=20API=20avec=20contr=C3=B4le=20acc?= =?UTF-8?q?=C3=A8s=20manuel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/auth.py | 32 +++++++++++++++++++++----------- app/api/sco_api.py | 33 +++++++++++++++++++++++++++++---- app/auth/models.py | 2 +- tests/api/exemple-api-basic.py | 11 ++++++++++- 4 files changed, 61 insertions(+), 17 deletions(-) diff --git a/app/api/auth.py b/app/api/auth.py index 958001eea..331cd388d 100644 --- a/app/api/auth.py +++ b/app/api/auth.py @@ -1,6 +1,7 @@ # -*- coding: UTF-8 -* # Authentication code borrowed from Miguel Grinberg's Mega Tutorial # (see https://github.com/miguelgrinberg/microblog) +# and modified for ScoDoc # Under The MIT License (MIT) @@ -23,6 +24,7 @@ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from flask import g from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth from app.auth.models import User from app.api.errors import error_response @@ -35,6 +37,7 @@ token_auth = HTTPTokenAuth() def verify_password(username, password): user = User.query.filter_by(user_name=username).first() if user and user.check_password(password): + g.current_user = user return user @@ -45,7 +48,9 @@ def basic_auth_error(status): @token_auth.verify_token def verify_token(token): - return User.check_token(token) if token else None + user = User.check_token(token) if token else None + g.current_user = user + return user @token_auth.error_handler @@ -53,15 +58,20 @@ def token_auth_error(status): return error_response(status) -def token_permission_required(permission): - def decorator(f): - @wraps(f) - def decorated_function(*args, **kwargs): - scodoc_dept = getattr(g, "scodoc_dept", None) - if not current_user.has_permission(permission, scodoc_dept): - abort(403) - return f(*args, **kwargs) +@token_auth.get_user_roles +def get_user_roles(user): + return user.roles - return login_required(decorated_function) - return decorator +# def token_permission_required(permission): +# def decorator(f): +# @wraps(f) +# def decorated_function(*args, **kwargs): +# scodoc_dept = getattr(g, "scodoc_dept", None) +# if not current_user.has_permission(permission, scodoc_dept): +# abort(403) +# return f(*args, **kwargs) + +# return login_required(decorated_function) + +# return decorator diff --git a/app/api/sco_api.py b/app/api/sco_api.py index c3ee74240..65bc8c12f 100644 --- a/app/api/sco_api.py +++ b/app/api/sco_api.py @@ -39,13 +39,18 @@ # Scolarite/Notes/moduleimpl_status # Scolarite/setGroups -from flask import jsonify, request, url_for, abort -from app import db +from flask import jsonify, request, url_for, abort, g +from flask_login import current_user +from sqlalchemy.sql import func + +from app import db, log from app.api import bp from app.api.auth import token_auth -from app.api.errors import bad_request - +from app.api.errors import bad_request, error_response +from app.decorators import permission_required from app import models +from app.models import FormSemestre, FormSemestreInscription, Identite +from app.scodoc.sco_permissions import Permission @bp.route("list_depts", methods=["GET"]) @@ -54,3 +59,23 @@ def list_depts(): depts = models.Departement.query.filter_by(visible=True).all() data = [d.to_dict() for d in depts] return jsonify(data) + + +@bp.route("/etudiants/courant", methods=["GET"]) +@token_auth.login_required +def etudiants(): + """Liste de tous les étudiants actuellement inscrits à un semestre + en cours. + """ + # Vérification de l'accès: permission Observateir sur tous les départements + # (c'est un exemple à compléter) + if not g.current_user.has_permission(Permission.ScoObservateur, None): + return error_response(401, message="accès interdit") + + query = db.session.query(Identite).filter( + FormSemestreInscription.formsemestre_id == FormSemestre.id, + FormSemestreInscription.etudid == Identite.id, + FormSemestre.date_debut <= func.now(), + FormSemestre.date_fin >= func.now(), + ) + return jsonify([e.to_dict_bul(include_photo=False) for e in query]) diff --git a/app/auth/models.py b/app/auth/models.py index d29cde908..d9c5455b7 100644 --- a/app/auth/models.py +++ b/app/auth/models.py @@ -272,7 +272,7 @@ class User(UserMixin, db.Model): """string repr. of user's roles (with depts) e.g. "Ens_RT, Ens_Info, Secr_CJ" """ - return ",".join(f"{r.role.name}_{r.dept or ''}" for r in self.user_roles) + return ",".join(f"{r.role.name or ''}_{r.dept or ''}" for r in self.user_roles) def is_administrator(self): "True if i'm an active SuperAdmin" diff --git a/tests/api/exemple-api-basic.py b/tests/api/exemple-api-basic.py index 529c379e5..0975e1003 100644 --- a/tests/api/exemple-api-basic.py +++ b/tests/api/exemple-api-basic.py @@ -2,7 +2,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -"""Exemple utilisation API ScoDoc 9 avec jeton obtenu par basic athentication +"""Exemple utilisation API ScoDoc 9 avec jeton obtenu par basic authentication Utilisation: créer les variables d'environnement: (indiquer les valeurs @@ -80,6 +80,15 @@ if r.status_code != 200: pp(r.json()) +# Liste des tous les étudiants en cours (de tous les depts) +r = requests.get( + SCODOC_URL + "/ScoDoc/api/etudiants/courant", + headers=HEADERS, + verify=CHECK_CERTIFICATE, +) +if r.status_code != 200: + raise ScoError("erreur de connexion: vérifier adresse et identifiants") + # # --- Recupere la liste de tous les semestres: # sems = GET(s, "Notes/formsemestre_list?format=json", "Aucun semestre !")