"""api.__init__ """ from functools import wraps from flask_json import as_json from flask import Blueprint from flask import current_app, g, request from flask_login import current_user from app import db, log from app.decorators import permission_required from app.scodoc import sco_utils as scu from app.scodoc.sco_exceptions import AccessDenied, ScoException from app.scodoc.sco_permissions import Permission api_bp = Blueprint("api", __name__) api_web_bp = Blueprint("apiweb", __name__) # HTTP ERROR STATUS API_CLIENT_ERROR = 400 # erreur dans les paramètres fournis par le client def api_permission_required(permission): """Ce décorateur fait la même chose que @permission_required mais enregistre dans l'attribut .scodoc_permission de la fonction la valeur de la permission. Cette valeur n'est utilisée que pour la génération automatique de la documentation. """ def decorator(f): f.scodoc_permission = permission @wraps(f) def decorated_function(*args, **kwargs): scodoc_dept = getattr(g, "scodoc_dept", None) if not current_user.has_permission(permission, scodoc_dept): return current_app.login_manager.unauthorized() return f(*args, **kwargs) return decorated_function return decorator @api_bp.errorhandler(ScoException) @api_web_bp.errorhandler(ScoException) @api_bp.errorhandler(404) def api_error_handler(e): "erreurs API => json" log(f"api_error_handler: {e}") return scu.json_error(404, message=str(e)) @api_bp.errorhandler(AccessDenied) @api_web_bp.errorhandler(AccessDenied) def permission_denied_error_handler(exc): """ Renvoie message d'erreur pour l'erreur 403 """ return scu.json_error( 403, f"operation non autorisee ({exc.args[0] if exc.args else ''})" ) def requested_format(default_format="json", allowed_formats=None): """Extract required format from query string. * default value is json. A list of allowed formats may be provided (['json'] considered if not provided). * if the required format is not in allowed list, returns None. NB: if json in not in allowed_formats, format specification is mandatory. """ format_type = request.args.get("format", default_format) if format_type in (allowed_formats or ["json"]): return format_type return None @as_json def get_model_api_object( model_cls: db.Model, model_id: int, join_cls: db.Model = None, restrict: bool | None = None, ): """ Retourne une réponse contenant la représentation api de l'objet "Model[model_id]" Filtrage du département en fonction d'une classe de jointure (eg: Identite, Formsemestre) -> join_cls exemple d'utilisation : fonction "justificatif()" -> app/api/justificatifs.py L'agument restrict est passé to_dict, est signale que l'on veut une version restreinte (sans données personnelles, ou sans informations sur le justificatif d'absence) """ query = model_cls.query.filter_by(id=model_id) if g.scodoc_dept and join_cls is not None: query = query.join(join_cls).filter_by(dept_id=g.scodoc_dept_id) unique: model_cls = query.first() if unique is None: return scu.json_error( 404, message=f"{model_cls.__name__} inexistant(e)", ) if restrict is None: return unique.to_dict(format_api=True) return unique.to_dict(format_api=True, restrict=restrict) from app.api import tokens from app.api import ( assiduites, billets_absences, departements, etud_suivi, etudiants, evaluations, formations, formsemestres, jury, justificatifs, logos, moduleimpl, operations, partitions, semset, users, )