From ee9fd059da4ed9bc6ab9452bd6b194d1e2c0c7d7 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 15 May 2023 23:39:08 +0200 Subject: [PATCH] API: groups_auto_assignment --- app/api/formsemestres.py | 45 +++++++++++- app/models/formsemestre.py | 6 ++ ...c79_add_data_for_groups_auto_assignment.py | 34 +++++++++ tests/api/test_api_formsemestre_data.py | 71 +++++++++++++++++++ 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 migrations/versions/b8df1b913c79_add_data_for_groups_auto_assignment.py create mode 100644 tests/api/test_api_formsemestre_data.py diff --git a/app/api/formsemestres.py b/app/api/formsemestres.py index e7ca242f8..18b987387 100644 --- a/app/api/formsemestres.py +++ b/app/api/formsemestres.py @@ -9,11 +9,12 @@ """ from operator import attrgetter, itemgetter -from flask import g, request +from flask import g, make_response, request from flask_json import as_json from flask_login import login_required import app +from app import db from app.api import api_bp as bp, api_web_bp, API_CLIENT_ERROR from app.decorators import scodoc, permission_required from app.scodoc.sco_utils import json_error @@ -30,6 +31,7 @@ from app.models import ( ModuleImpl, NotesNotes, ) +from app.models.formsemestre import GROUPS_AUTO_ASSIGNMENT_DATA_MAX from app.scodoc.sco_bulletins import get_formsemestre_bulletin_etud_json from app.scodoc import sco_groups from app.scodoc.sco_permissions import Permission @@ -496,3 +498,44 @@ def formsemestre_resultat(formsemestre_id: int): row["partitions"] = etud_groups.get(row["etudid"], {}) return rows + + +@bp.route("/formsemestre//get_groups_auto_assignment") +@api_web_bp.route("/formsemestre//get_groups_auto_assignment") +@login_required +@scodoc +@permission_required(Permission.ScoView) +@as_json +def get_groups_auto_assignment(formsemestre_id: int): + """rend les données""" + query = FormSemestre.query.filter_by(id=formsemestre_id) + if g.scodoc_dept: + query = query.filter_by(dept_id=g.scodoc_dept_id) + formsemestre: FormSemestre = query.first_or_404(formsemestre_id) + response = make_response(formsemestre.groups_auto_assignment_data or b"") + response.headers["Content-Type"] = scu.JSON_MIMETYPE + return response + + +@bp.route( + "/formsemestre//save_groups_auto_assignment", methods=["POST"] +) +@api_web_bp.route( + "/formsemestre//save_groups_auto_assignment", methods=["POST"] +) +@login_required +@scodoc +@permission_required(Permission.ScoView) +@as_json +def save_groups_auto_assignment(formsemestre_id: int): + """enregistre les données""" + query = FormSemestre.query.filter_by(id=formsemestre_id) + if g.scodoc_dept: + query = query.filter_by(dept_id=g.scodoc_dept_id) + formsemestre: FormSemestre = query.first_or_404(formsemestre_id) + + if len(request.data) > GROUPS_AUTO_ASSIGNMENT_DATA_MAX: + return json_error(413, "data too large") + formsemestre.groups_auto_assignment_data = request.data + db.session.add(formsemestre) + db.session.commit() diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index 26bb5ac40..68399262b 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -42,6 +42,8 @@ from app.scodoc.sco_permissions import Permission from app.scodoc.sco_utils import MONTH_NAMES_ABBREV from app.scodoc.sco_vdi import ApoEtapeVDI +GROUPS_AUTO_ASSIGNMENT_DATA_MAX = 1024 * 1024 # bytes + class FormSemestre(db.Model): """Mise en oeuvre d'un semestre de formation""" @@ -108,6 +110,10 @@ class FormSemestre(db.Model): elt_annee_apo = db.Column(db.Text()) "code element annee Apogee, eg 'VRT1A' ou 'V2INLA,V2INCA,...'" + # Data pour groups_auto_assignment + # (ce champ est utilisé uniquement via l'API par le front js) + groups_auto_assignment_data = db.Column(db.LargeBinary(), nullable=True) + # Relations: etapes = db.relationship( "FormSemestreEtape", cascade="all,delete", backref="formsemestre" diff --git a/migrations/versions/b8df1b913c79_add_data_for_groups_auto_assignment.py b/migrations/versions/b8df1b913c79_add_data_for_groups_auto_assignment.py new file mode 100644 index 000000000..54e9db27e --- /dev/null +++ b/migrations/versions/b8df1b913c79_add_data_for_groups_auto_assignment.py @@ -0,0 +1,34 @@ +"""Add data for groups_auto_assignment + +Revision ID: b8df1b913c79 +Revises: 054dd6133b9c +Create Date: 2023-05-15 23:12:58.257709 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "b8df1b913c79" +down_revision = "054dd6133b9c" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("notes_formsemestre", schema=None) as batch_op: + batch_op.add_column( + sa.Column("groups_auto_assignment_data", sa.LargeBinary(), nullable=True) + ) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("notes_formsemestre", schema=None) as batch_op: + batch_op.drop_column("groups_auto_assignment_data") + + # ### end Alembic commands ### diff --git a/tests/api/test_api_formsemestre_data.py b/tests/api/test_api_formsemestre_data.py new file mode 100644 index 000000000..fd9b94707 --- /dev/null +++ b/tests/api/test_api_formsemestre_data.py @@ -0,0 +1,71 @@ +"""Test formsemestre + +Utilisation : + créer les variables d'environnement: (indiquer les valeurs + pour le serveur ScoDoc que vous voulez interroger) + + export SCODOC_URL="https://scodoc.xxx.net/" + export SCODOC_USER="xxx" + export SCODOC_PASSWD="xxx" + export CHECK_CERTIFICATE=0 # ou 1 si serveur de production avec certif SSL valide + + (on peut aussi placer ces valeurs dans un fichier .env du répertoire tests/api). + + Lancer : + pytest tests/api/test_api_formsemestre.py +""" +import requests + +from app.scodoc import sco_utils as scu + +from tests.api.setup_test_api import ( + API_URL, + CHECK_CERTIFICATE, + api_headers, +) + + +def test_save_groups_auto_assignment(api_headers): + """ + Routes: + /formsemestre//save_groups_auto_assignment + /formsemestre//get_groups_auto_assignment + """ + formsemestre_id = 1 + r = requests.get( + f"{API_URL}/formsemestre/{formsemestre_id}", + headers=api_headers, + verify=CHECK_CERTIFICATE, + timeout=scu.SCO_TEST_API_TIMEOUT, + ) + assert r.status_code == 200 + # On stocke une chaine quelconque + data_orig = ( + """{ "attribute" : "Un paquet de json", "valide": pas nécessairement +}--""" + ) + r = requests.post( + f"{API_URL}/formsemestre/{formsemestre_id}/save_groups_auto_assignment", + data=data_orig.encode("utf-8"), + headers=api_headers, + verify=CHECK_CERTIFICATE, + timeout=scu.SCO_TEST_API_TIMEOUT, + ) + assert r.status_code == 200 + # GET + r = requests.get( + f"{API_URL}/formsemestre/{formsemestre_id}/get_groups_auto_assignment", + headers=api_headers, + verify=CHECK_CERTIFICATE, + timeout=scu.SCO_TEST_API_TIMEOUT, + ) + assert r.status_code == 200 + assert r.text == data_orig + # Tente d'envoyer trop de données + r = requests.post( + f"{API_URL}/formsemestre/{formsemestre_id}/save_groups_auto_assignment", + data="F*CK" * 1000000, # environ 4MB + headers=api_headers, + verify=CHECK_CERTIFICATE, + timeout=scu.SCO_TEST_API_TIMEOUT, + ) + assert r.status_code == 413