forked from ScoDoc/ScoDoc
API: unifie traitement errors, messages JSON.
This commit is contained in:
parent
a053afeba6
commit
f7a2c1e8e7
@ -3,11 +3,18 @@
|
|||||||
|
|
||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
from flask import request
|
from flask import request
|
||||||
|
from app.scodoc import sco_utils as scu
|
||||||
|
|
||||||
api_bp = Blueprint("api", __name__)
|
api_bp = Blueprint("api", __name__)
|
||||||
api_web_bp = Blueprint("apiweb", __name__)
|
api_web_bp = Blueprint("apiweb", __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@api_bp.errorhandler(404)
|
||||||
|
def api_error_handler(e):
|
||||||
|
"erreurs API => json"
|
||||||
|
return scu.json_error(404, message=str(e))
|
||||||
|
|
||||||
|
|
||||||
def requested_format(default_format="json", allowed_formats=None):
|
def requested_format(default_format="json", allowed_formats=None):
|
||||||
"""Extract required format from query string.
|
"""Extract required format from query string.
|
||||||
* default value is json. A list of allowed formats may be provided
|
* default value is json. A list of allowed formats may be provided
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
|
|
||||||
from app.api import api_bp as bp
|
from app.api import api_bp as bp
|
||||||
from app.api.errors import error_response
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
from app.models import Identite
|
from app.models import Identite
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ def absences(etudid: int = None):
|
|||||||
"""
|
"""
|
||||||
etud = Identite.query.get(etudid)
|
etud = Identite.query.get(etudid)
|
||||||
if etud is None:
|
if etud is None:
|
||||||
return error_response(404, message="etudiant inexistant")
|
return json_error(404, message="etudiant inexistant")
|
||||||
# Absences de l'étudiant
|
# Absences de l'étudiant
|
||||||
ndb.open_db_connection()
|
ndb.open_db_connection()
|
||||||
abs_list = sco_abs.list_abs_date(etud.id)
|
abs_list = sco_abs.list_abs_date(etud.id)
|
||||||
@ -97,7 +97,7 @@ def absences_just(etudid: int = None):
|
|||||||
"""
|
"""
|
||||||
etud = Identite.query.get(etudid)
|
etud = Identite.query.get(etudid)
|
||||||
if etud is None:
|
if etud is None:
|
||||||
return error_response(404, message="etudiant inexistant")
|
return json_error(404, message="etudiant inexistant")
|
||||||
|
|
||||||
# Absences justifiées de l'étudiant
|
# Absences justifiées de l'étudiant
|
||||||
abs_just = [
|
abs_just = [
|
||||||
|
@ -15,7 +15,7 @@ import app
|
|||||||
from app import db
|
from app import db
|
||||||
from app.api import api_bp as bp, api_web_bp
|
from app.api import api_bp as bp, api_web_bp
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
from app.api.errors import error_response
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.models import BilletAbsence
|
from app.models import BilletAbsence
|
||||||
from app.models.etudiants import Identite
|
from app.models.etudiants import Identite
|
||||||
from app.scodoc import sco_abs_billets
|
from app.scodoc import sco_abs_billets
|
||||||
@ -47,7 +47,7 @@ def billets_absence_create():
|
|||||||
description = data.get("description", "")
|
description = data.get("description", "")
|
||||||
justified = data.get("justified", False)
|
justified = data.get("justified", False)
|
||||||
if None in (etudid, abs_begin, abs_end):
|
if None in (etudid, abs_begin, abs_end):
|
||||||
return error_response(
|
return json_error(
|
||||||
404, message="Paramètre manquant: etudid, abs_bein, abs_end requis"
|
404, message="Paramètre manquant: etudid, abs_bein, abs_end requis"
|
||||||
)
|
)
|
||||||
query = Identite.query.filter_by(etudid=etudid)
|
query = Identite.query.filter_by(etudid=etudid)
|
||||||
|
@ -17,7 +17,7 @@ from flask_login import login_required
|
|||||||
import app
|
import app
|
||||||
from app import db, log
|
from app import db, log
|
||||||
from app.api import api_bp as bp
|
from app.api import api_bp as bp
|
||||||
from app.api.errors import error_response
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
from app.models import Departement, FormSemestre
|
from app.models import Departement, FormSemestre
|
||||||
from app.models import departements
|
from app.models import departements
|
||||||
@ -103,12 +103,12 @@ def departement_create():
|
|||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
acronym = str(data.get("acronym", ""))
|
acronym = str(data.get("acronym", ""))
|
||||||
if not acronym:
|
if not acronym:
|
||||||
return error_response(404, "missing acronym")
|
return json_error(404, "missing acronym")
|
||||||
visible = bool(data.get("visible", True))
|
visible = bool(data.get("visible", True))
|
||||||
try:
|
try:
|
||||||
dept = departements.create_dept(acronym, visible=visible)
|
dept = departements.create_dept(acronym, visible=visible)
|
||||||
except ScoValueError as exc:
|
except ScoValueError as exc:
|
||||||
return error_response(404, exc.args[0] if exc.args else "")
|
return json_error(404, exc.args[0] if exc.args else "")
|
||||||
return jsonify(dept.to_dict())
|
return jsonify(dept.to_dict())
|
||||||
|
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ def departement_edit(acronym):
|
|||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
visible = bool(data.get("visible", None))
|
visible = bool(data.get("visible", None))
|
||||||
if visible is None:
|
if visible is None:
|
||||||
return error_response(404, "missing argument: visible")
|
return json_error(404, "missing argument: visible")
|
||||||
visible = bool(visible)
|
visible = bool(visible)
|
||||||
dept.visible = visible
|
dept.visible = visible
|
||||||
db.session.add(dept)
|
db.session.add(dept)
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
# Authentication code borrowed from Miguel Grinberg's Mega Tutorial
|
|
||||||
# (see https://github.com/miguelgrinberg/microblog)
|
|
||||||
|
|
||||||
# Under The MIT License (MIT)
|
|
||||||
|
|
||||||
# Copyright (c) 2017 Miguel Grinberg
|
|
||||||
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
# this software and associated documentation files (the "Software"), to deal in
|
|
||||||
# the Software without restriction, including without limitation the rights to
|
|
||||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
# subject to the following conditions:
|
|
||||||
|
|
||||||
# The above copyright notice and this permission notice shall be included in all
|
|
||||||
# copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
# 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 jsonify
|
|
||||||
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
|
|
||||||
response = jsonify(payload)
|
|
||||||
response.status_code = status_code
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
def bad_request(message):
|
|
||||||
"400 Bad Request response"
|
|
||||||
return error_response(400, message)
|
|
@ -15,7 +15,7 @@ from sqlalchemy import desc, or_
|
|||||||
|
|
||||||
import app
|
import app
|
||||||
from app.api import api_bp as bp, api_web_bp
|
from app.api import api_bp as bp, api_web_bp
|
||||||
from app.api.errors import error_response
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.api import tools
|
from app.api import tools
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
from app.models import (
|
from app.models import (
|
||||||
@ -116,7 +116,7 @@ def etudiant(etudid: int = None, nip: str = None, ine: str = None):
|
|||||||
etud = tools.get_etud(etudid, nip, ine)
|
etud = tools.get_etud(etudid, nip, ine)
|
||||||
|
|
||||||
if etud is None:
|
if etud is None:
|
||||||
return error_response(
|
return json_error(
|
||||||
404,
|
404,
|
||||||
message="étudiant inconnu",
|
message="étudiant inconnu",
|
||||||
)
|
)
|
||||||
@ -148,7 +148,7 @@ def etudiants(etudid: int = None, nip: str = None, ine: str = None):
|
|||||||
elif ine is not None:
|
elif ine is not None:
|
||||||
query = Identite.query.filter_by(code_ine=ine)
|
query = Identite.query.filter_by(code_ine=ine)
|
||||||
else:
|
else:
|
||||||
return error_response(
|
return json_error(
|
||||||
404,
|
404,
|
||||||
message="parametre manquant",
|
message="parametre manquant",
|
||||||
)
|
)
|
||||||
@ -185,12 +185,12 @@ def etudiant_formsemestres(etudid: int = None, nip: int = None, ine: int = None)
|
|||||||
elif ine is not None:
|
elif ine is not None:
|
||||||
q_etud = Identite.query.filter_by(code_ine=ine)
|
q_etud = Identite.query.filter_by(code_ine=ine)
|
||||||
else:
|
else:
|
||||||
return error_response(404, message="parametre manquant")
|
return json_error(404, message="parametre manquant")
|
||||||
if g.scodoc_dept is not None:
|
if g.scodoc_dept is not None:
|
||||||
q_etud = q_etud.filter_by(dept_id=g.scodoc_dept_id)
|
q_etud = q_etud.filter_by(dept_id=g.scodoc_dept_id)
|
||||||
etud = q_etud.join(Admission).order_by(desc(Admission.annee)).first()
|
etud = q_etud.join(Admission).order_by(desc(Admission.annee)).first()
|
||||||
if etud is None:
|
if etud is None:
|
||||||
return error_response(404, message="etudiant inexistant")
|
return json_error(404, message="etudiant inexistant")
|
||||||
query = FormSemestre.query.filter(
|
query = FormSemestre.query.filter(
|
||||||
FormSemestreInscription.etudid == etud.id,
|
FormSemestreInscription.etudid == etud.id,
|
||||||
FormSemestreInscription.formsemestre_id == FormSemestre.id,
|
FormSemestreInscription.formsemestre_id == FormSemestre.id,
|
||||||
@ -328,7 +328,7 @@ def etudiant_bulletin_semestre(
|
|||||||
formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first_or_404()
|
formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first_or_404()
|
||||||
dept = Departement.query.filter_by(id=formsemestre.dept_id).first_or_404()
|
dept = Departement.query.filter_by(id=formsemestre.dept_id).first_or_404()
|
||||||
if g.scodoc_dept and dept != g.scodoc_dept:
|
if g.scodoc_dept and dept != g.scodoc_dept:
|
||||||
return error_response(404, "formsemestre non trouve")
|
return json_error(404, "formsemestre non trouve")
|
||||||
if etudid is not None:
|
if etudid is not None:
|
||||||
query = Identite.query.filter_by(id=etudid)
|
query = Identite.query.filter_by(id=etudid)
|
||||||
elif nip is not None:
|
elif nip is not None:
|
||||||
@ -336,11 +336,11 @@ def etudiant_bulletin_semestre(
|
|||||||
elif ine is not None:
|
elif ine is not None:
|
||||||
query = Identite.query.filter_by(code_ine=ine, dept_id=dept.id)
|
query = Identite.query.filter_by(code_ine=ine, dept_id=dept.id)
|
||||||
else:
|
else:
|
||||||
return error_response(404, message="parametre manquant")
|
return json_error(404, message="parametre manquant")
|
||||||
|
|
||||||
etud = query.first()
|
etud = query.first()
|
||||||
if etud is None:
|
if etud is None:
|
||||||
return error_response(404, message="etudiant inexistant")
|
return json_error(404, message="etudiant inexistant")
|
||||||
|
|
||||||
app.set_sco_dept(dept.acronym)
|
app.set_sco_dept(dept.acronym)
|
||||||
|
|
||||||
@ -400,7 +400,7 @@ def etudiant_groups(formsemestre_id: int, etudid: int = None):
|
|||||||
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
||||||
formsemestre = query.first()
|
formsemestre = query.first()
|
||||||
if formsemestre is None:
|
if formsemestre is None:
|
||||||
return error_response(
|
return json_error(
|
||||||
404,
|
404,
|
||||||
message="formsemestre inconnu",
|
message="formsemestre inconnu",
|
||||||
)
|
)
|
||||||
|
@ -15,7 +15,7 @@ import app
|
|||||||
|
|
||||||
from app.api import api_bp as bp, api_web_bp
|
from app.api import api_bp as bp, api_web_bp
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
from app.api.errors import error_response
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.models import Evaluation, ModuleImpl, FormSemestre
|
from app.models import Evaluation, ModuleImpl, FormSemestre
|
||||||
from app.scodoc import sco_evaluation_db
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
@ -13,7 +13,7 @@ from flask_login import login_required
|
|||||||
|
|
||||||
import app
|
import app
|
||||||
from app.api import api_bp as bp, api_web_bp
|
from app.api import api_bp as bp, api_web_bp
|
||||||
from app.api.errors import error_response
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
from app.models.formations import Formation
|
from app.models.formations import Formation
|
||||||
from app.models.formsemestre import FormSemestre
|
from app.models.formsemestre import FormSemestre
|
||||||
@ -210,7 +210,7 @@ def formation_export_by_formation_id(formation_id: int, export_ids=False):
|
|||||||
try:
|
try:
|
||||||
data = sco_formations.formation_export(formation_id, export_ids)
|
data = sco_formations.formation_export(formation_id, export_ids)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return error_response(500, message="Erreur inconnue")
|
return json_error(500, message="Erreur inconnue")
|
||||||
|
|
||||||
return jsonify(data)
|
return jsonify(data)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ from flask_login import login_required
|
|||||||
import app
|
import app
|
||||||
from app.api import api_bp as bp, api_web_bp
|
from app.api import api_bp as bp, api_web_bp
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
from app.api.errors import error_response
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
from app.comp.moy_mod import ModuleImplResults
|
from app.comp.moy_mod import ModuleImplResults
|
||||||
from app.comp.res_compat import NotesTableCompat
|
from app.comp.res_compat import NotesTableCompat
|
||||||
@ -107,7 +107,7 @@ def formsemestres_query():
|
|||||||
try:
|
try:
|
||||||
annee_scolaire_int = int(annee_scolaire)
|
annee_scolaire_int = int(annee_scolaire)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return error_response(404, "invalid annee_scolaire: not int")
|
return json_error(404, "invalid annee_scolaire: not int")
|
||||||
debut_annee = scu.date_debut_anne_scolaire(annee_scolaire_int)
|
debut_annee = scu.date_debut_anne_scolaire(annee_scolaire_int)
|
||||||
fin_annee = scu.date_fin_anne_scolaire(annee_scolaire_int)
|
fin_annee = scu.date_fin_anne_scolaire(annee_scolaire_int)
|
||||||
formsemestres = formsemestres.filter(
|
formsemestres = formsemestres.filter(
|
||||||
@ -119,7 +119,7 @@ def formsemestres_query():
|
|||||||
try:
|
try:
|
||||||
dept_id = int(dept_id)
|
dept_id = int(dept_id)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return error_response(404, "invalid dept_id: not int")
|
return json_error(404, "invalid dept_id: not int")
|
||||||
formsemestres = formsemestres.filter_by(dept_id=dept_id)
|
formsemestres = formsemestres.filter_by(dept_id=dept_id)
|
||||||
if etape_apo is not None:
|
if etape_apo is not None:
|
||||||
formsemestres = formsemestres.join(FormSemestreEtape).filter(
|
formsemestres = formsemestres.join(FormSemestreEtape).filter(
|
||||||
@ -417,7 +417,7 @@ def formsemestre_resultat(formsemestre_id: int):
|
|||||||
"""
|
"""
|
||||||
format_spec = request.args.get("format", None)
|
format_spec = request.args.get("format", None)
|
||||||
if format_spec is not None and format_spec != "raw":
|
if format_spec is not None and format_spec != "raw":
|
||||||
return error_response(404, "invalid format specification")
|
return json_error(404, "invalid format specification")
|
||||||
convert_values = format_spec != "raw"
|
convert_values = format_spec != "raw"
|
||||||
|
|
||||||
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
||||||
|
@ -15,7 +15,7 @@ import app
|
|||||||
from app import db, log
|
from app import db, log
|
||||||
from app.api import api_bp as bp, api_web_bp
|
from app.api import api_bp as bp, api_web_bp
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
from app.api.errors import error_response
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.but import jury_but_recap
|
from app.but import jury_but_recap
|
||||||
from app.models import FormSemestre, FormSemestreInscription, Identite
|
from app.models import FormSemestre, FormSemestreInscription, Identite
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
@ -35,7 +35,7 @@ from flask_login import login_required
|
|||||||
|
|
||||||
from app.api import api_bp as bp, api_web_bp
|
from app.api import api_bp as bp, api_web_bp
|
||||||
from app.api import requested_format
|
from app.api import requested_format
|
||||||
from app.api.errors import error_response
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.models import Departement
|
from app.models import Departement
|
||||||
from app.scodoc.sco_logos import list_logos, find_logo
|
from app.scodoc.sco_logos import list_logos, find_logo
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
@ -49,10 +49,10 @@ from app.scodoc.sco_permissions import Permission
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
def api_get_glob_logos():
|
def api_get_glob_logos():
|
||||||
if not g.current_user.has_permission(Permission.ScoSuperAdmin, None):
|
if not g.current_user.has_permission(Permission.ScoSuperAdmin, None):
|
||||||
return error_response(401, message="accès interdit")
|
return json_error(403, message="accès interdit")
|
||||||
required_format = requested_format() # json only
|
required_format = requested_format() # json only
|
||||||
if required_format is None:
|
if required_format is None:
|
||||||
return error_response(400, "Illegal format")
|
return json_error(400, "Illegal format")
|
||||||
logos = list_logos()[None]
|
logos = list_logos()[None]
|
||||||
return jsonify(list(logos.keys()))
|
return jsonify(list(logos.keys()))
|
||||||
|
|
||||||
@ -62,10 +62,10 @@ def api_get_glob_logos():
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
def api_get_glob_logo(logoname):
|
def api_get_glob_logo(logoname):
|
||||||
if not g.current_user.has_permission(Permission.ScoSuperAdmin, None):
|
if not g.current_user.has_permission(Permission.ScoSuperAdmin, None):
|
||||||
return error_response(401, message="accès interdit")
|
return json_error(403, message="accès interdit")
|
||||||
logo = find_logo(logoname=logoname)
|
logo = find_logo(logoname=logoname)
|
||||||
if logo is None:
|
if logo is None:
|
||||||
return error_response(404, message="logo not found")
|
return json_error(404, message="logo not found")
|
||||||
logo.select()
|
logo.select()
|
||||||
return send_file(
|
return send_file(
|
||||||
logo.filepath,
|
logo.filepath,
|
||||||
@ -80,7 +80,7 @@ def api_get_glob_logo(logoname):
|
|||||||
def api_get_local_logos(departement):
|
def api_get_local_logos(departement):
|
||||||
dept_id = Departement.from_acronym(departement).id
|
dept_id = Departement.from_acronym(departement).id
|
||||||
if not g.current_user.has_permission(Permission.ScoChangePreferences, departement):
|
if not g.current_user.has_permission(Permission.ScoChangePreferences, departement):
|
||||||
return error_response(401, message="accès interdit")
|
return json_error(403, message="accès interdit")
|
||||||
logos = list_logos().get(dept_id, dict())
|
logos = list_logos().get(dept_id, dict())
|
||||||
return jsonify(list(logos.keys()))
|
return jsonify(list(logos.keys()))
|
||||||
|
|
||||||
@ -92,10 +92,10 @@ def api_get_local_logo(departement, logoname):
|
|||||||
# format = requested_format("jpg", ['png', 'jpg']) XXX ?
|
# format = requested_format("jpg", ['png', 'jpg']) XXX ?
|
||||||
dept_id = Departement.from_acronym(departement).id
|
dept_id = Departement.from_acronym(departement).id
|
||||||
if not g.current_user.has_permission(Permission.ScoChangePreferences, departement):
|
if not g.current_user.has_permission(Permission.ScoChangePreferences, departement):
|
||||||
return error_response(401, message="accès interdit")
|
return json_error(403, message="accès interdit")
|
||||||
logo = find_logo(logoname=logoname, dept_id=dept_id)
|
logo = find_logo(logoname=logoname, dept_id=dept_id)
|
||||||
if logo is None:
|
if logo is None:
|
||||||
return error_response(404, message="logo not found")
|
return json_error(404, message="logo not found")
|
||||||
logo.select()
|
logo.select()
|
||||||
return send_file(
|
return send_file(
|
||||||
logo.filepath,
|
logo.filepath,
|
||||||
|
@ -14,7 +14,7 @@ import app
|
|||||||
from app import db, log
|
from app import db, log
|
||||||
from app.api import api_bp as bp, api_web_bp
|
from app.api import api_bp as bp, api_web_bp
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
from app.api.errors import error_response
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.models import FormSemestre, FormSemestreInscription, Identite
|
from app.models import FormSemestre, FormSemestreInscription, Identite
|
||||||
from app.models import GroupDescr, Partition
|
from app.models import GroupDescr, Partition
|
||||||
from app.models.groups import group_membership
|
from app.models.groups import group_membership
|
||||||
@ -137,7 +137,7 @@ def etud_in_group_query(group_id: int):
|
|||||||
"""Etudiants du groupe, filtrés par état"""
|
"""Etudiants du groupe, filtrés par état"""
|
||||||
etat = request.args.get("etat")
|
etat = request.args.get("etat")
|
||||||
if etat not in {scu.INSCRIT, scu.DEMISSION, scu.DEF}:
|
if etat not in {scu.INSCRIT, scu.DEMISSION, scu.DEF}:
|
||||||
return error_response(404, "etat: valeur invalide")
|
return json_error(404, "etat: valeur invalide")
|
||||||
query = GroupDescr.query.filter_by(id=group_id)
|
query = GroupDescr.query.filter_by(id=group_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = (
|
query = (
|
||||||
@ -169,7 +169,7 @@ def set_etud_group(etudid: int, group_id: int):
|
|||||||
)
|
)
|
||||||
group = query.first_or_404()
|
group = query.first_or_404()
|
||||||
if etud.id not in {e.id for e in group.partition.formsemestre.etuds}:
|
if etud.id not in {e.id for e in group.partition.formsemestre.etuds}:
|
||||||
return error_response(404, "etud non inscrit au formsemestre du groupe")
|
return json_error(404, "etud non inscrit au formsemestre du groupe")
|
||||||
groups = (
|
groups = (
|
||||||
GroupDescr.query.filter_by(partition_id=group.partition.id)
|
GroupDescr.query.filter_by(partition_id=group.partition.id)
|
||||||
.join(group_membership)
|
.join(group_membership)
|
||||||
@ -261,13 +261,13 @@ def group_create(partition_id: int):
|
|||||||
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
partition: Partition = query.first_or_404()
|
partition: Partition = query.first_or_404()
|
||||||
if not partition.groups_editable:
|
if not partition.groups_editable:
|
||||||
return error_response(404, "partition non editable")
|
return json_error(404, "partition non editable")
|
||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
group_name = data.get("group_name")
|
group_name = data.get("group_name")
|
||||||
if group_name is None:
|
if group_name is None:
|
||||||
return error_response(404, "missing group name or invalid data format")
|
return json_error(404, "missing group name or invalid data format")
|
||||||
if not GroupDescr.check_name(partition, group_name):
|
if not GroupDescr.check_name(partition, group_name):
|
||||||
return error_response(404, "invalid group_name")
|
return json_error(404, "invalid group_name")
|
||||||
group_name = group_name.strip()
|
group_name = group_name.strip()
|
||||||
|
|
||||||
group = GroupDescr(group_name=group_name, partition_id=partition_id)
|
group = GroupDescr(group_name=group_name, partition_id=partition_id)
|
||||||
@ -293,7 +293,7 @@ def group_delete(group_id: int):
|
|||||||
)
|
)
|
||||||
group: GroupDescr = query.first_or_404()
|
group: GroupDescr = query.first_or_404()
|
||||||
if not group.partition.groups_editable:
|
if not group.partition.groups_editable:
|
||||||
return error_response(404, "partition non editable")
|
return json_error(404, "partition non editable")
|
||||||
formsemestre_id = group.partition.formsemestre_id
|
formsemestre_id = group.partition.formsemestre_id
|
||||||
log(f"deleting {group}")
|
log(f"deleting {group}")
|
||||||
db.session.delete(group)
|
db.session.delete(group)
|
||||||
@ -317,12 +317,12 @@ def group_edit(group_id: int):
|
|||||||
)
|
)
|
||||||
group: GroupDescr = query.first_or_404()
|
group: GroupDescr = query.first_or_404()
|
||||||
if not group.partition.groups_editable:
|
if not group.partition.groups_editable:
|
||||||
return error_response(404, "partition non editable")
|
return json_error(404, "partition non editable")
|
||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
group_name = data.get("group_name")
|
group_name = data.get("group_name")
|
||||||
if group_name is not None:
|
if group_name is not None:
|
||||||
if not GroupDescr.check_name(group.partition, group_name, existing=True):
|
if not GroupDescr.check_name(group.partition, group_name, existing=True):
|
||||||
return error_response(404, "invalid group_name")
|
return json_error(404, "invalid group_name")
|
||||||
group.group_name = group_name.strip()
|
group.group_name = group_name.strip()
|
||||||
db.session.add(group)
|
db.session.add(group)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@ -358,14 +358,14 @@ def partition_create(formsemestre_id: int):
|
|||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
partition_name = data.get("partition_name")
|
partition_name = data.get("partition_name")
|
||||||
if partition_name is None:
|
if partition_name is None:
|
||||||
return error_response(404, "missing partition_name or invalid data format")
|
return json_error(404, "missing partition_name or invalid data format")
|
||||||
if partition_name == scu.PARTITION_PARCOURS:
|
if partition_name == scu.PARTITION_PARCOURS:
|
||||||
return error_response(404, f"invalid partition_name {scu.PARTITION_PARCOURS}")
|
return json_error(404, f"invalid partition_name {scu.PARTITION_PARCOURS}")
|
||||||
if not Partition.check_name(formsemestre, partition_name):
|
if not Partition.check_name(formsemestre, partition_name):
|
||||||
return error_response(404, "invalid partition_name")
|
return json_error(404, "invalid partition_name")
|
||||||
numero = data.get("numero", 0)
|
numero = data.get("numero", 0)
|
||||||
if not isinstance(numero, int):
|
if not isinstance(numero, int):
|
||||||
return error_response(404, "invalid type for numero")
|
return json_error(404, "invalid type for numero")
|
||||||
args = {
|
args = {
|
||||||
"formsemestre_id": formsemestre_id,
|
"formsemestre_id": formsemestre_id,
|
||||||
"partition_name": partition_name.strip(),
|
"partition_name": partition_name.strip(),
|
||||||
@ -376,7 +376,7 @@ def partition_create(formsemestre_id: int):
|
|||||||
boolean_field, False if boolean_field != "groups_editable" else True
|
boolean_field, False if boolean_field != "groups_editable" else True
|
||||||
)
|
)
|
||||||
if not isinstance(value, bool):
|
if not isinstance(value, bool):
|
||||||
return error_response(404, f"invalid type for {boolean_field}")
|
return json_error(404, f"invalid type for {boolean_field}")
|
||||||
args[boolean_field] = value
|
args[boolean_field] = value
|
||||||
|
|
||||||
partition = Partition(**args)
|
partition = Partition(**args)
|
||||||
@ -407,7 +407,7 @@ def formsemestre_order_partitions(formsemestre_id: int):
|
|||||||
if not isinstance(partition_ids, int) and not all(
|
if not isinstance(partition_ids, int) and not all(
|
||||||
isinstance(x, int) for x in partition_ids
|
isinstance(x, int) for x in partition_ids
|
||||||
):
|
):
|
||||||
return error_response(
|
return json_error(
|
||||||
404,
|
404,
|
||||||
message="paramètre liste des partitions invalide",
|
message="paramètre liste des partitions invalide",
|
||||||
)
|
)
|
||||||
@ -444,7 +444,7 @@ def partition_order_groups(partition_id: int):
|
|||||||
if not isinstance(group_ids, int) and not all(
|
if not isinstance(group_ids, int) and not all(
|
||||||
isinstance(x, int) for x in group_ids
|
isinstance(x, int) for x in group_ids
|
||||||
):
|
):
|
||||||
return error_response(
|
return json_error(
|
||||||
404,
|
404,
|
||||||
message="paramètre liste de groupe invalide",
|
message="paramètre liste de groupe invalide",
|
||||||
)
|
)
|
||||||
@ -487,18 +487,18 @@ def partition_edit(partition_id: int):
|
|||||||
#
|
#
|
||||||
if partition_name is not None and partition_name != partition.partition_name:
|
if partition_name is not None and partition_name != partition.partition_name:
|
||||||
if partition.is_parcours():
|
if partition.is_parcours():
|
||||||
return error_response(404, f"can't rename {scu.PARTITION_PARCOURS}")
|
return json_error(404, f"can't rename {scu.PARTITION_PARCOURS}")
|
||||||
if not Partition.check_name(
|
if not Partition.check_name(
|
||||||
partition.formsemestre, partition_name, existing=True
|
partition.formsemestre, partition_name, existing=True
|
||||||
):
|
):
|
||||||
return error_response(404, "invalid partition_name")
|
return json_error(404, "invalid partition_name")
|
||||||
partition.partition_name = partition_name.strip()
|
partition.partition_name = partition_name.strip()
|
||||||
modified = True
|
modified = True
|
||||||
|
|
||||||
numero = data.get("numero")
|
numero = data.get("numero")
|
||||||
if numero is not None and numero != partition.numero:
|
if numero is not None and numero != partition.numero:
|
||||||
if not isinstance(numero, int):
|
if not isinstance(numero, int):
|
||||||
return error_response(404, "invalid type for numero")
|
return json_error(404, "invalid type for numero")
|
||||||
partition.numero = numero
|
partition.numero = numero
|
||||||
modified = True
|
modified = True
|
||||||
|
|
||||||
@ -506,9 +506,9 @@ def partition_edit(partition_id: int):
|
|||||||
value = data.get(boolean_field)
|
value = data.get(boolean_field)
|
||||||
if value is not None and value != getattr(partition, boolean_field):
|
if value is not None and value != getattr(partition, boolean_field):
|
||||||
if not isinstance(value, bool):
|
if not isinstance(value, bool):
|
||||||
return error_response(404, f"invalid type for {boolean_field}")
|
return json_error(404, f"invalid type for {boolean_field}")
|
||||||
if boolean_field == "groups_editable" and partition.is_parcours():
|
if boolean_field == "groups_editable" and partition.is_parcours():
|
||||||
return error_response(404, f"can't change {scu.PARTITION_PARCOURS}")
|
return json_error(404, f"can't change {scu.PARTITION_PARCOURS}")
|
||||||
setattr(partition, boolean_field, value)
|
setattr(partition, boolean_field, value)
|
||||||
modified = True
|
modified = True
|
||||||
|
|
||||||
@ -540,7 +540,7 @@ def partition_delete(partition_id: int):
|
|||||||
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
partition: Partition = query.first_or_404()
|
partition: Partition = query.first_or_404()
|
||||||
if not partition.partition_name:
|
if not partition.partition_name:
|
||||||
return error_response(404, "ne peut pas supprimer la partition par défaut")
|
return json_error(404, "ne peut pas supprimer la partition par défaut")
|
||||||
is_parcours = partition.is_parcours()
|
is_parcours = partition.is_parcours()
|
||||||
formsemestre: FormSemestre = partition.formsemestre
|
formsemestre: FormSemestre = partition.formsemestre
|
||||||
log(f"deleting partition {partition}")
|
log(f"deleting partition {partition}")
|
||||||
|
@ -10,7 +10,7 @@ from flask_login import current_user
|
|||||||
from sqlalchemy import desc, or_
|
from sqlalchemy import desc, or_
|
||||||
|
|
||||||
from app import models
|
from app import models
|
||||||
from app.api.errors import error_response
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.models import Departement, Identite, Admission
|
from app.models import Departement, Identite, Admission
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ def get_etud(etudid=None, nip=None, ine=None) -> models.Identite:
|
|||||||
elif ine is not None:
|
elif ine is not None:
|
||||||
query = Identite.query.filter_by(code_ine=ine)
|
query = Identite.query.filter_by(code_ine=ine)
|
||||||
else:
|
else:
|
||||||
return error_response(
|
return json_error(
|
||||||
404,
|
404,
|
||||||
message="parametre manquant",
|
message="parametre manquant",
|
||||||
)
|
)
|
||||||
|
@ -12,10 +12,10 @@
|
|||||||
from flask import g, jsonify, request
|
from flask import g, jsonify, request
|
||||||
from flask_login import current_user, login_required
|
from flask_login import current_user, login_required
|
||||||
|
|
||||||
import app
|
|
||||||
from app import db, log
|
from app import db, log
|
||||||
from app.api import api_bp as bp, api_web_bp
|
from app.api import api_bp as bp, api_web_bp
|
||||||
from app.api.errors import error_response
|
from app.models.etudiants import Identite
|
||||||
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.auth.models import User, Role, UserRole
|
from app.auth.models import User, Role, UserRole
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
from app.models import Departement
|
from app.models import Departement
|
||||||
@ -35,11 +35,11 @@ def user_info(uid: int):
|
|||||||
"""
|
"""
|
||||||
user: User = User.query.get(uid)
|
user: User = User.query.get(uid)
|
||||||
if user is None:
|
if user is None:
|
||||||
return error_response(404, "user not found")
|
return json_error(404, "user not found")
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
allowed_depts = current_user.get_depts_with_permission(Permission.ScoUsersView)
|
allowed_depts = current_user.get_depts_with_permission(Permission.ScoUsersView)
|
||||||
if user.dept not in allowed_depts:
|
if user.dept not in allowed_depts:
|
||||||
return error_response(404, "user not found")
|
return json_error(404, "user not found")
|
||||||
|
|
||||||
return jsonify(user.to_dict())
|
return jsonify(user.to_dict())
|
||||||
|
|
||||||
@ -101,20 +101,20 @@ def user_create():
|
|||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
user_name = data.get("user_name")
|
user_name = data.get("user_name")
|
||||||
if not user_name:
|
if not user_name:
|
||||||
return error_response(404, "empty user_name")
|
return json_error(404, "empty user_name")
|
||||||
user = User.query.filter_by(user_name=user_name).first()
|
user = User.query.filter_by(user_name=user_name).first()
|
||||||
if user:
|
if user:
|
||||||
return error_response(404, f"user_create: user {user} already exists\n")
|
return json_error(404, f"user_create: user {user} already exists\n")
|
||||||
dept = data.get("dept")
|
dept = data.get("dept")
|
||||||
if dept == "@all":
|
if dept == "@all":
|
||||||
dept = None
|
dept = None
|
||||||
allowed_depts = current_user.get_depts_with_permission(Permission.ScoUsersAdmin)
|
allowed_depts = current_user.get_depts_with_permission(Permission.ScoUsersAdmin)
|
||||||
if dept not in allowed_depts:
|
if dept not in allowed_depts:
|
||||||
return error_response(403, "user_create: departement non autorise")
|
return json_error(403, "user_create: departement non autorise")
|
||||||
if (dept is not None) and (
|
if (dept is not None) and (
|
||||||
Departement.query.filter_by(acronym=dept).first() is None
|
Departement.query.filter_by(acronym=dept).first() is None
|
||||||
):
|
):
|
||||||
return error_response(404, "user_create: departement inexistant")
|
return json_error(404, "user_create: departement inexistant")
|
||||||
nom = data.get("nom")
|
nom = data.get("nom")
|
||||||
prenom = data.get("prenom")
|
prenom = data.get("prenom")
|
||||||
active = scu.to_bool(data.get("active", True))
|
active = scu.to_bool(data.get("active", True))
|
||||||
@ -151,12 +151,12 @@ def user_edit(uid: int):
|
|||||||
if (None not in allowed_depts) and (
|
if (None not in allowed_depts) and (
|
||||||
(orig_dept not in allowed_depts) or (dest_dept not in allowed_depts)
|
(orig_dept not in allowed_depts) or (dest_dept not in allowed_depts)
|
||||||
):
|
):
|
||||||
return error_response(403, "user_edit: departement non autorise")
|
return json_error(403, "user_edit: departement non autorise")
|
||||||
if dest_dept != orig_dept:
|
if dest_dept != orig_dept:
|
||||||
if (dest_dept is not None) and (
|
if (dest_dept is not None) and (
|
||||||
Departement.query.filter_by(acronym=dest_dept).first() is None
|
Departement.query.filter_by(acronym=dest_dept).first() is None
|
||||||
):
|
):
|
||||||
return error_response(404, "user_edit: departement inexistant")
|
return json_error(404, "user_edit: departement inexistant")
|
||||||
user.dept = dest_dept
|
user.dept = dest_dept
|
||||||
|
|
||||||
user.nom = data.get("nom", user.nom)
|
user.nom = data.get("nom", user.nom)
|
||||||
@ -189,7 +189,7 @@ def user_role_add(uid: int, role_name: str, dept: str = None):
|
|||||||
_ = Departement.query.filter_by(acronym=dept).first_or_404()
|
_ = Departement.query.filter_by(acronym=dept).first_or_404()
|
||||||
allowed_depts = current_user.get_depts_with_permission(Permission.ScoSuperAdmin)
|
allowed_depts = current_user.get_depts_with_permission(Permission.ScoSuperAdmin)
|
||||||
if (None not in allowed_depts) and (dept not in allowed_depts):
|
if (None not in allowed_depts) and (dept not in allowed_depts):
|
||||||
return error_response(403, "user_role_add: departement non autorise")
|
return json_error(403, "user_role_add: departement non autorise")
|
||||||
user.add_role(role, dept)
|
user.add_role(role, dept)
|
||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@ -217,7 +217,7 @@ def user_role_remove(uid: int, role_name: str, dept: str = None):
|
|||||||
_ = Departement.query.filter_by(acronym=dept).first_or_404()
|
_ = Departement.query.filter_by(acronym=dept).first_or_404()
|
||||||
allowed_depts = current_user.get_depts_with_permission(Permission.ScoSuperAdmin)
|
allowed_depts = current_user.get_depts_with_permission(Permission.ScoSuperAdmin)
|
||||||
if (None not in allowed_depts) and (dept not in allowed_depts):
|
if (None not in allowed_depts) and (dept not in allowed_depts):
|
||||||
return error_response(403, "user_role_remove: departement non autorise")
|
return json_error(403, "user_role_remove: departement non autorise")
|
||||||
|
|
||||||
query = UserRole.query.filter(UserRole.role == role, UserRole.user == user)
|
query = UserRole.query.filter(UserRole.role == role, UserRole.user == user)
|
||||||
if dept is not None:
|
if dept is not None:
|
||||||
@ -276,7 +276,7 @@ def role_permission_add(role_name: str, perm_name: str):
|
|||||||
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
||||||
permission = Permission.get_by_name(perm_name)
|
permission = Permission.get_by_name(perm_name)
|
||||||
if permission is None:
|
if permission is None:
|
||||||
return error_response(404, "role_permission_add: permission inconnue")
|
return json_error(404, "role_permission_add: permission inconnue")
|
||||||
role.add_permission(permission)
|
role.add_permission(permission)
|
||||||
db.session.add(role)
|
db.session.add(role)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@ -299,7 +299,7 @@ def role_permission_remove(role_name: str, perm_name: str):
|
|||||||
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
||||||
permission = Permission.get_by_name(perm_name)
|
permission = Permission.get_by_name(perm_name)
|
||||||
if permission is None:
|
if permission is None:
|
||||||
return error_response(404, "role_permission_remove: permission inconnue")
|
return json_error(404, "role_permission_remove: permission inconnue")
|
||||||
role.remove_permission(permission)
|
role.remove_permission(permission)
|
||||||
db.session.add(role)
|
db.session.add(role)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@ -319,7 +319,7 @@ def role_create(role_name: str):
|
|||||||
"""
|
"""
|
||||||
role: Role = Role.query.filter_by(name=role_name).first()
|
role: Role = Role.query.filter_by(name=role_name).first()
|
||||||
if role:
|
if role:
|
||||||
return error_response(404, "role_create: role already exists")
|
return json_error(404, "role_create: role already exists")
|
||||||
role = Role(name=role_name)
|
role = Role(name=role_name)
|
||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
permissions = data.get("permissions")
|
permissions = data.get("permissions")
|
||||||
@ -327,7 +327,7 @@ def role_create(role_name: str):
|
|||||||
try:
|
try:
|
||||||
role.set_named_permissions(permissions)
|
role.set_named_permissions(permissions)
|
||||||
except ScoValueError:
|
except ScoValueError:
|
||||||
return error_response(404, "role_create: invalid permissions")
|
return json_error(404, "role_create: invalid permissions")
|
||||||
db.session.add(role)
|
db.session.add(role)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return jsonify(role.to_dict())
|
return jsonify(role.to_dict())
|
||||||
@ -352,12 +352,12 @@ def role_edit(role_name: str):
|
|||||||
try:
|
try:
|
||||||
role.set_named_permissions(permissions)
|
role.set_named_permissions(permissions)
|
||||||
except ScoValueError:
|
except ScoValueError:
|
||||||
return error_response(404, "role_create: invalid permissions")
|
return json_error(404, "role_create: invalid permissions")
|
||||||
role_name = data.get("role_name")
|
role_name = data.get("role_name")
|
||||||
if role_name and role_name != role.name:
|
if role_name and role_name != role.name:
|
||||||
existing_role: Role = Role.query.filter_by(name=role_name).first()
|
existing_role: Role = Role.query.filter_by(name=role_name).first()
|
||||||
if existing_role:
|
if existing_role:
|
||||||
return error_response(404, "role_edit: role name already exists")
|
return json_error(404, "role_edit: role name already exists")
|
||||||
role.name = role_name
|
role.name = role_name
|
||||||
db.session.add(role)
|
db.session.add(role)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -9,7 +9,7 @@ from flask import g, redirect, request, url_for
|
|||||||
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth
|
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth
|
||||||
import flask_login
|
import flask_login
|
||||||
from app import login
|
from app import login
|
||||||
from app.api.errors import error_response
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.auth.models import User
|
from app.auth.models import User
|
||||||
|
|
||||||
basic_auth = HTTPBasicAuth()
|
basic_auth = HTTPBasicAuth()
|
||||||
@ -80,8 +80,6 @@ def load_user_from_request(req: flask.Request) -> User:
|
|||||||
@login.unauthorized_handler
|
@login.unauthorized_handler
|
||||||
def unauthorized():
|
def unauthorized():
|
||||||
"flask-login: si pas autorisé, redirige vers page login, sauf si API"
|
"flask-login: si pas autorisé, redirige vers page login, sauf si API"
|
||||||
from app.api.errors import error_response as api_error_response
|
|
||||||
|
|
||||||
if request.blueprint == "api" or request.blueprint == "apiweb":
|
if request.blueprint == "api" or request.blueprint == "apiweb":
|
||||||
return api_error_response(http.HTTPStatus.UNAUTHORIZED, "Non autorise (logic)")
|
return json_error(http.HTTPStatus.UNAUTHORIZED, "Non autorise (logic)")
|
||||||
return redirect(url_for("auth.login"))
|
return redirect(url_for("auth.login"))
|
||||||
|
@ -10,11 +10,10 @@
|
|||||||
import collections
|
import collections
|
||||||
import datetime
|
import datetime
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from flask import url_for, g
|
from flask import g, has_request_context, url_for
|
||||||
|
|
||||||
from app.comp.res_but import ResultatsSemestreBUT
|
from app.comp.res_but import ResultatsSemestreBUT
|
||||||
from app.models import FormSemestre, Identite
|
from app.models import FormSemestre, Identite
|
||||||
from app.models import but_validations
|
|
||||||
from app.models.groups import GroupDescr
|
from app.models.groups import GroupDescr
|
||||||
from app.models.ues import UniteEns
|
from app.models.ues import UniteEns
|
||||||
from app.scodoc import sco_bulletins, sco_utils as scu
|
from app.scodoc import sco_bulletins, sco_utils as scu
|
||||||
@ -170,7 +169,9 @@ class BulletinBUT:
|
|||||||
"notes.moduleimpl_status",
|
"notes.moduleimpl_status",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
moduleimpl_id=modimpl.id,
|
moduleimpl_id=modimpl.id,
|
||||||
),
|
)
|
||||||
|
if has_request_context()
|
||||||
|
else "na",
|
||||||
"moyenne": {
|
"moyenne": {
|
||||||
# # moyenne indicative de module: moyenne des UE,
|
# # moyenne indicative de module: moyenne des UE,
|
||||||
# # ignorant celles sans notes (nan)
|
# # ignorant celles sans notes (nan)
|
||||||
@ -228,7 +229,9 @@ class BulletinBUT:
|
|||||||
"notes.evaluation_listenotes",
|
"notes.evaluation_listenotes",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
evaluation_id=e.id,
|
evaluation_id=e.id,
|
||||||
),
|
)
|
||||||
|
if has_request_context()
|
||||||
|
else "na",
|
||||||
}
|
}
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from flask import abort, url_for
|
from flask import abort, has_request_context, url_for
|
||||||
from flask import g, request
|
from flask import g, request
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
from sqlalchemy import desc, text
|
from sqlalchemy import desc, text
|
||||||
@ -196,7 +196,8 @@ class Identite(db.Model):
|
|||||||
"nationalite": self.nationalite or "",
|
"nationalite": self.nationalite or "",
|
||||||
"boursier": self.boursier or "",
|
"boursier": self.boursier or "",
|
||||||
}
|
}
|
||||||
if include_urls:
|
if include_urls and has_request_context():
|
||||||
|
# test request context so we can use this func in tests under the flask shell
|
||||||
d["fiche_url"] = url_for(
|
d["fiche_url"] = url_for(
|
||||||
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=self.id
|
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=self.id
|
||||||
)
|
)
|
||||||
|
@ -37,6 +37,7 @@ from flask_login import current_user
|
|||||||
|
|
||||||
from app import email
|
from app import email
|
||||||
from app import log
|
from app import log
|
||||||
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.but import bulletin_but
|
from app.but import bulletin_but
|
||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
from app.comp.res_compat import NotesTableCompat
|
from app.comp.res_compat import NotesTableCompat
|
||||||
@ -74,9 +75,13 @@ def get_formsemestre_bulletin_etud_json(
|
|||||||
) -> str:
|
) -> str:
|
||||||
"""Le JSON du bulletin d'un étudiant, quel que soit le type de formation."""
|
"""Le JSON du bulletin d'un étudiant, quel que soit le type de formation."""
|
||||||
if formsemestre.formation.is_apc():
|
if formsemestre.formation.is_apc():
|
||||||
r = bulletin_but.BulletinBUT(formsemestre)
|
bul = bulletin_but.BulletinBUT(formsemestre)
|
||||||
|
if not etud.id in bul.res.identdict:
|
||||||
|
return error_response(
|
||||||
|
404, "get_formsemestre_bulletin_etud_json: invalid etud"
|
||||||
|
)
|
||||||
return jsonify(
|
return jsonify(
|
||||||
r.bulletin_etud(
|
bul.bulletin_etud(
|
||||||
etud,
|
etud,
|
||||||
formsemestre,
|
formsemestre,
|
||||||
force_publishing=force_publishing,
|
force_publishing=force_publishing,
|
||||||
|
@ -53,6 +53,7 @@ import requests
|
|||||||
import flask
|
import flask
|
||||||
from flask import g, request
|
from flask import g, request
|
||||||
from flask import flash, url_for, make_response, jsonify
|
from flask import flash, url_for, make_response, jsonify
|
||||||
|
from werkzeug.http import HTTP_STATUS_CODES
|
||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
from app import log
|
from app import log
|
||||||
@ -819,15 +820,26 @@ def get_request_args():
|
|||||||
return vals
|
return vals
|
||||||
|
|
||||||
|
|
||||||
def json_error(message, success=False, status=404):
|
def json_error(status_code, message=None):
|
||||||
"""Simple JSON response, for errors"""
|
"""Simple JSON response, for errors"""
|
||||||
response = {
|
payload = {
|
||||||
"success": success,
|
"error": HTTP_STATUS_CODES.get(status_code, "Unknown error"),
|
||||||
"status": status,
|
"status": status_code,
|
||||||
"message": message,
|
|
||||||
}
|
}
|
||||||
|
if message:
|
||||||
|
payload["message"] = message
|
||||||
|
response = jsonify(payload)
|
||||||
|
response.status_code = status_code
|
||||||
log(f"Error: {response}")
|
log(f"Error: {response}")
|
||||||
return jsonify(response), status
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
def json_ok_response(status_code=200, payload=None):
|
||||||
|
"""Simple JSON respons for "success" """
|
||||||
|
payload = payload or {"OK": True}
|
||||||
|
response = jsonify(payload)
|
||||||
|
response.status_code = status_code
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
def get_scodoc_version():
|
def get_scodoc_version():
|
||||||
|
@ -36,17 +36,22 @@ import time
|
|||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import abort, flash, jsonify, redirect, render_template, url_for
|
from flask import abort, flash, redirect, render_template, url_for
|
||||||
from flask import current_app, g, request
|
from flask import current_app, g, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
|
from app import db
|
||||||
|
from app import models
|
||||||
|
from app.auth.models import User
|
||||||
|
from app.but import apc_edit_ue, jury_but_recap
|
||||||
from app.but import jury_but, jury_but_validation_auto
|
from app.but import jury_but, jury_but_validation_auto
|
||||||
from app.but.forms import jury_but_forms
|
from app.but.forms import jury_but_forms
|
||||||
from app.but import jury_but_pv
|
from app.but import jury_but_pv
|
||||||
from app.but import jury_but_view
|
from app.but import jury_but_view
|
||||||
|
|
||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
from app.comp.res_but import ResultatsSemestreBUT
|
|
||||||
from app.comp.res_compat import NotesTableCompat
|
from app.comp.res_compat import NotesTableCompat
|
||||||
|
from app.models import ScolarNews
|
||||||
from app.models.config import ScoDocSiteConfig
|
from app.models.config import ScoDocSiteConfig
|
||||||
from app.models.etudiants import Identite
|
from app.models.etudiants import Identite
|
||||||
from app.models.formsemestre import FormSemestre
|
from app.models.formsemestre import FormSemestre
|
||||||
@ -54,13 +59,8 @@ from app.models.formsemestre import FormSemestreUEComputationExpr
|
|||||||
from app.models.moduleimpls import ModuleImpl
|
from app.models.moduleimpls import ModuleImpl
|
||||||
from app.models.modules import Module
|
from app.models.modules import Module
|
||||||
from app.models.ues import UniteEns
|
from app.models.ues import UniteEns
|
||||||
|
from app.views import notes_bp as bp
|
||||||
|
|
||||||
from app import api
|
|
||||||
from app import db
|
|
||||||
from app import models
|
|
||||||
from app.models import ScolarNews, but_validations
|
|
||||||
from app.auth.models import User
|
|
||||||
from app.but import apc_edit_ue, jury_but_recap
|
|
||||||
from app.decorators import (
|
from app.decorators import (
|
||||||
scodoc,
|
scodoc,
|
||||||
scodoc7func,
|
scodoc7func,
|
||||||
@ -68,7 +68,6 @@ from app.decorators import (
|
|||||||
permission_required_compat_scodoc7,
|
permission_required_compat_scodoc7,
|
||||||
)
|
)
|
||||||
|
|
||||||
from app.views import notes_bp as bp
|
|
||||||
|
|
||||||
# ---------------
|
# ---------------
|
||||||
|
|
||||||
@ -775,7 +774,7 @@ def formsemestre_list(
|
|||||||
formsemestre_id = int(formsemestre_id) if formsemestre_id is not None else None
|
formsemestre_id = int(formsemestre_id) if formsemestre_id is not None else None
|
||||||
formation_id = int(formation_id) if formation_id is not None else None
|
formation_id = int(formation_id) if formation_id is not None else None
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return api.errors.error_response(404, "invalid id")
|
return scu.json_error(404, "invalid id")
|
||||||
# XAPI: new json api
|
# XAPI: new json api
|
||||||
args = {}
|
args = {}
|
||||||
L = locals()
|
L = locals()
|
||||||
|
@ -128,26 +128,26 @@ def set_module_ue_coef():
|
|||||||
try:
|
try:
|
||||||
module_id = int(request.form["module_id"])
|
module_id = int(request.form["module_id"])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return scu.json_error("invalid module_id", 400)
|
return scu.json_error(404, "invalid module_id")
|
||||||
try:
|
try:
|
||||||
ue_id = int(request.form["ue_id"])
|
ue_id = int(request.form["ue_id"])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return scu.json_error("invalid ue_id", 400)
|
return scu.json_error(404, "invalid ue_id")
|
||||||
try:
|
try:
|
||||||
coef = float(request.form["coef"].replace(",", "."))
|
coef = float(request.form["coef"].replace(",", "."))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return scu.json_error("invalid coef", 400)
|
return scu.json_error(404, "invalid coef")
|
||||||
module = models.Module.query.get(module_id)
|
module = models.Module.query.get(module_id)
|
||||||
if module is None:
|
if module is None:
|
||||||
return scu.json_error(f"module not found ({module_id})", 404)
|
return scu.json_error(404, f"module not found ({module_id})")
|
||||||
ue = models.UniteEns.query.get(ue_id)
|
ue = models.UniteEns.query.get(ue_id)
|
||||||
if not ue:
|
if not ue:
|
||||||
return scu.json_error(f"UE not found ({ue_id})", 404)
|
return scu.json_error(404, f"UE not found ({ue_id})")
|
||||||
module.set_ue_coef(ue, coef)
|
module.set_ue_coef(ue, coef)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
module.formation.invalidate_cached_sems()
|
module.formation.invalidate_cached_sems()
|
||||||
|
|
||||||
return scu.json_error("ok", success=True, status=201)
|
return scu.json_ok_response(201)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/edit_modules_ue_coefs")
|
@bp.route("/edit_modules_ue_coefs")
|
||||||
|
@ -55,24 +55,24 @@ class APIError(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def GET(path: str, headers={}, errmsg=None, dept=None):
|
def GET(path: str, headers: dict = None, errmsg=None, dept=None):
|
||||||
"""Get and returns as JSON"""
|
"""Get and returns as JSON"""
|
||||||
if dept:
|
if dept:
|
||||||
url = SCODOC_URL + f"/ScoDoc/{dept}/api" + path
|
url = SCODOC_URL + f"/ScoDoc/{dept}/api" + path
|
||||||
else:
|
else:
|
||||||
url = API_URL + path
|
url = API_URL + path
|
||||||
r = requests.get(url, headers=headers or CUR_HEADERS, verify=CHECK_CERTIFICATE)
|
r = requests.get(url, headers=headers or {}, verify=CHECK_CERTIFICATE)
|
||||||
if r.status_code != 200:
|
if r.status_code != 200:
|
||||||
raise APIError(errmsg or f"""erreur status={r.status_code} !\n{r.text}""")
|
raise APIError(errmsg or f"""erreur status={r.status_code} !\n{r.text}""")
|
||||||
return r.json() # decode la reponse JSON
|
return r.json() # decode la reponse JSON
|
||||||
|
|
||||||
|
|
||||||
def POST_JSON(path: str, data: dict = {}, headers={}, errmsg=None):
|
def POST_JSON(path: str, data: dict = {}, headers: dict = None, errmsg=None):
|
||||||
"""Post"""
|
"""Post"""
|
||||||
r = requests.post(
|
r = requests.post(
|
||||||
API_URL + path,
|
API_URL + path,
|
||||||
json=data,
|
json=data,
|
||||||
headers=headers,
|
headers=headers or {},
|
||||||
verify=CHECK_CERTIFICATE,
|
verify=CHECK_CERTIFICATE,
|
||||||
)
|
)
|
||||||
if r.status_code != 200:
|
if r.status_code != 200:
|
||||||
|
@ -46,7 +46,7 @@ def test_admin_access(create_admin_token):
|
|||||||
headers = {"Authorization": f"Bearer {token}"}
|
headers = {"Authorization": f"Bearer {token}"}
|
||||||
with app.test_client() as client:
|
with app.test_client() as client:
|
||||||
response = client.get(API_URL + "/logos", headers=headers)
|
response = client.get(API_URL + "/logos", headers=headers)
|
||||||
assert response.status_code == 401
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
|
||||||
def test_lambda_access(create_lambda_token):
|
def test_lambda_access(create_lambda_token):
|
||||||
@ -57,7 +57,7 @@ def test_lambda_access(create_lambda_token):
|
|||||||
headers = {"Authorization": f"Bearer {token}"}
|
headers = {"Authorization": f"Bearer {token}"}
|
||||||
with app.test_client() as client:
|
with app.test_client() as client:
|
||||||
response = client.get(API_URL + "/logos", headers=headers)
|
response = client.get(API_URL + "/logos", headers=headers)
|
||||||
assert response.status_code == 401
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
|
||||||
def test_initial_with_header_and_footer(create_super_token):
|
def test_initial_with_header_and_footer(create_super_token):
|
||||||
|
@ -201,31 +201,21 @@ def create_formsemestre(
|
|||||||
|
|
||||||
|
|
||||||
def inscrit_etudiants(etuds: list, formsemestre: FormSemestre):
|
def inscrit_etudiants(etuds: list, formsemestre: FormSemestre):
|
||||||
"""Inscrit les etudiants aux semestres et à tous ses modules"""
|
"""Inscrit les étudiants au semestre et à tous ses modules.
|
||||||
for etud in etuds:
|
1/5 DEF, 1/5 DEF
|
||||||
aleatoire = random.randint(0, 10)
|
"""
|
||||||
if aleatoire <= 3:
|
for i, etud in enumerate(etuds):
|
||||||
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
|
if (i + 1) % 5 == 0:
|
||||||
formsemestre.id,
|
etat = "D"
|
||||||
etud.id,
|
elif (i + 2) % 5 == 0:
|
||||||
group_ids=[],
|
etat = "DEF"
|
||||||
etat="I",
|
|
||||||
method="init db test",
|
|
||||||
)
|
|
||||||
elif 3 < aleatoire <= 6:
|
|
||||||
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
|
|
||||||
formsemestre.id,
|
|
||||||
etud.id,
|
|
||||||
group_ids=[],
|
|
||||||
etat="D",
|
|
||||||
method="init db test",
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
|
etat = "I"
|
||||||
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
|
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
|
||||||
formsemestre.id,
|
formsemestre.id,
|
||||||
etud.id,
|
etud.id,
|
||||||
group_ids=[],
|
group_ids=[],
|
||||||
etat="DEF",
|
etat=etat,
|
||||||
method="init db test",
|
method="init db test",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -368,11 +358,11 @@ def init_test_database():
|
|||||||
mapp.set_sco_dept(dept.acronym)
|
mapp.set_sco_dept(dept.acronym)
|
||||||
user_lecteur, user_autre = create_users(depts)
|
user_lecteur, user_autre = create_users(depts)
|
||||||
with sco_cache.DeferredSemCacheManager():
|
with sco_cache.DeferredSemCacheManager():
|
||||||
etuds = create_etuds(dept)
|
etuds = create_etuds(dept, nb=20)
|
||||||
formation = import_formation(dept.id)
|
formation = import_formation(dept.id)
|
||||||
formsemestre = create_formsemestre(formation, user_lecteur)
|
formsemestre = create_formsemestre(formation, user_lecteur)
|
||||||
create_evaluations(formsemestre)
|
create_evaluations(formsemestre)
|
||||||
inscrit_etudiants(etuds, formsemestre)
|
inscrit_etudiants(etuds[:16], formsemestre)
|
||||||
saisie_notes_evaluations(formsemestre, user_lecteur)
|
saisie_notes_evaluations(formsemestre, user_lecteur)
|
||||||
add_absences(formsemestre)
|
add_absences(formsemestre)
|
||||||
create_etape_apo(formsemestre)
|
create_etape_apo(formsemestre)
|
||||||
|
Loading…
Reference in New Issue
Block a user