From 92e9f4bc5f59268421855026ff7ac4100f2f74ca Mon Sep 17 00:00:00 2001 From: leonard_montalbano Date: Thu, 14 Apr 2022 14:56:36 +0200 Subject: [PATCH] todo a focus --- app/api/absences.py | 16 +++++++++------ app/api/departements.py | 12 ++++++----- app/api/etudiants.py | 20 ++++++++++++------- app/api/evaluations.py | 11 +++++----- app/api/formations.py | 19 ++++++++++++------ app/api/formsemestres.py | 13 ++++++++---- app/api/jury.py | 1 + app/api/logos.py | 9 +++++---- app/api/partitions.py | 9 ++++++--- tests/api/setup_test_api.py | 6 +++--- tests/api/test_api_departements.py | 18 ++++++++--------- tests/api/test_api_etudiants.py | 6 +++--- tests/api/test_api_formsemestre_.py | 2 +- .../fakedatabase/create_test_api_database.py | 7 ++++++- 14 files changed, 92 insertions(+), 57 deletions(-) diff --git a/app/api/absences.py b/app/api/absences.py index 38ec33fb..08ba7ef1 100644 --- a/app/api/absences.py +++ b/app/api/absences.py @@ -8,6 +8,7 @@ from app.api import bp from app.api.auth import token_auth from app.api.errors import error_response from app.decorators import permission_required +from app.api.auth import token_auth, token_permission_required from app.scodoc.sco_abs import add_absence, add_justif, annule_absence, annule_justif, list_abs_date from app.scodoc.sco_groups import get_group_members from app.scodoc.sco_permissions import Permission @@ -16,7 +17,8 @@ from app.scodoc.sco_permissions import Permission @bp.route("/absences/etudid/", methods=["GET"]) @bp.route("/absences/nip/", methods=["GET"]) @bp.route("/absences/ine/", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def absences(etudid: int = None, nip: int = None, ine: int = None): """ Retourne la liste des absences d'un étudiant donné @@ -53,7 +55,8 @@ def absences(etudid: int = None, nip: int = None, ine: int = None): @bp.route("/absences/etudid//abs_just_only", methods=["GET"]) @bp.route("/absences/nip//abs_just_only", methods=["GET"]) @bp.route("/absences/ine//abs_just_only", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def absences_justify(etudid: int = None, nip: int = None, ine: int = None): """ Retourne la liste des absences justifiées d'un étudiant donné @@ -96,7 +99,7 @@ def absences_justify(etudid: int = None, nip: int = None, ine: int = None): @bp.route("/absences/abs_signale?ine=&date=&matin=&justif=" "&description=&moduleimpl_id=", methods=["POST"]) @token_auth.login_required -@permission_required(Permission.APIAbsChange) +@token_permission_required(Permission.APIAbsChange) def abs_signale(date: datetime, matin: bool, justif: bool, etudid: int = None, nip: int = None, ine: int = None, description: str = None, moduleimpl_id: int = None): """ @@ -219,7 +222,7 @@ def abs_signale(date: datetime, matin: bool, justif: bool, etudid: int = None, n @bp.route("/absences/abs_annule?nip=&jour=&matin=", methods=["POST"]) @bp.route("/absences/abs_annule?ine=&jour=&matin=", methods=["POST"]) @token_auth.login_required -@permission_required(Permission.APIAbsChange) +@token_permission_required(Permission.APIAbsChange) def abs_annule(jour: datetime, matin: str, etudid: int = None, nip: int = None, ine: int = None): """ Retourne un html @@ -257,7 +260,7 @@ def abs_annule(jour: datetime, matin: str, etudid: int = None, nip: int = None, @bp.route("/absences/abs_annule_justif?nip=&jour=&matin=", methods=["POST"]) @bp.route("/absences/abs_annule_justif?ine=&jour=&matin=", methods=["POST"]) @token_auth.login_required -@permission_required(Permission.APIAbsChange) +@token_permission_required(Permission.APIAbsChange) def abs_annule_justif(jour: datetime, matin: str, etudid: int = None, nip: int = None, ine: int = None): """ Retourne un html @@ -292,7 +295,8 @@ def abs_annule_justif(jour: datetime, matin: str, etudid: int = None, nip: int = @bp.route("/absences/abs_group_etat/?group_id=&date_debut=date_debut&date_fin=date_fin", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def abs_groupe_etat(group_id: int, date_debut, date_fin, with_boursier=True, format="html"): """ Retoune la liste des absences d'un ou plusieurs groupes entre deux dates diff --git a/app/api/departements.py b/app/api/departements.py index ee7a8899..c4b689a1 100644 --- a/app/api/departements.py +++ b/app/api/departements.py @@ -32,7 +32,7 @@ def departements(): "/departements//etudiants/liste/", methods=["GET"] ) @token_auth.login_required -# @permission_required(Permission.APIView) +@token_permission_required(Permission.APIView) def liste_etudiants(dept: str, formsemestre_id=None): """ Retourne la liste des étudiants d'un département @@ -91,8 +91,8 @@ def liste_etudiants(dept: str, formsemestre_id=None): @bp.route("/departements//semestres_courants", methods=["GET"]) -# @token_auth.login_required # Commenté le temps des tests -# @permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def liste_semestres_courant(dept: str): """ Liste des semestres actifs d'un départements donné @@ -154,7 +154,8 @@ def liste_semestres_courant(dept: str): "/departements//formations//referentiel_competences", methods=["GET"], ) -# @permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def referenciel_competences(dept: str, formation_id: int): """ Retourne le référentiel de compétences @@ -188,7 +189,8 @@ def referenciel_competences(dept: str, formation_id: int): "/departements//formsemestre//programme", methods=["GET"], ) -# @permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def semestre_index(dept: str, formsemestre_id: int): """ Retourne la liste des Ues, ressources et SAE d'un semestre diff --git a/app/api/etudiants.py b/app/api/etudiants.py index a39f00bf..f1d03003 100644 --- a/app/api/etudiants.py +++ b/app/api/etudiants.py @@ -4,14 +4,15 @@ from flask import jsonify from app import models from app.api import bp from app.api.errors import error_response -from app.decorators import permission_required +from app.api.auth import token_auth, token_permission_required from app.scodoc.sco_bulletins_json import make_json_formsemestre_bulletinetud from app.scodoc.sco_groups import get_etud_groups from app.scodoc.sco_permissions import Permission @bp.route("/etudiants", methods=["GET"]) -#@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def etudiants(): """ Retourne la liste de tous les étudiants @@ -52,7 +53,8 @@ def etudiants(): @bp.route("/etudiants/courant", methods=["GET"]) -#@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def etudiants_courant(): """ Retourne la liste des étudiants courant @@ -98,7 +100,8 @@ def etudiants_courant(): @bp.route("/etudiant/etudid/", methods=["GET"]) @bp.route("/etudiant/nip/", methods=["GET"]) @bp.route("/etudiant/ine/", methods=["GET"]) -#@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def etudiant(etudid: int = None, nip: int = None, ine: int = None): """ Retourne les informations de l'étudiant correspondant à l'id passé en paramètres. @@ -143,7 +146,8 @@ def etudiant(etudid: int = None, nip: int = None, ine: int = None): @bp.route("/etudiant/etudid//formsemestres") @bp.route("/etudiant/nip//formsemestres") @bp.route("/etudiant/ine//formsemestres") -#@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def etudiant_formsemestres(etudid: int = None, nip: int = None, ine: int = None): """ Retourne la liste des semestres qu'un étudiant a suivis @@ -231,7 +235,8 @@ def etudiant_formsemestres(etudid: int = None, nip: int = None, ine: int = None) @bp.route("/etudiant/etudid//formsemestre//bulletin", methods=["GET"]) @bp.route("/etudiant/nip//formsemestre//bulletin", methods=["GET"]) @bp.route("/etudiant/ine//formsemestre//bulletin", methods=["GET"]) -#@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def etudiant_bulletin_semestre(formsemestre_id, etudid: int = None, nip: int = None, ine: int = None): """ Retourne le bulletin d'un étudiant en fonction de son id et d'un semestre donné @@ -262,7 +267,8 @@ def etudiant_bulletin_semestre(formsemestre_id, etudid: int = None, nip: int = N @bp.route("/etudiant/etudid//semestre//groups", methods=["GET"]) @bp.route("/etudiant/nip//semestre//groups", methods=["GET"]) @bp.route("/etudiant/ine//semestre//groups", methods=["GET"]) -#@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def etudiant_groups(formsemestre_id: int, etudid: int = None, nip: int = None, ine: int = None): """ Retourne la liste des groupes auxquels appartient l'étudiant dans le semestre indiqué diff --git a/app/api/evaluations.py b/app/api/evaluations.py index db1b7e84..e3ed707b 100644 --- a/app/api/evaluations.py +++ b/app/api/evaluations.py @@ -3,15 +3,15 @@ from flask import jsonify from app import models from app.api import bp -from app.api.auth import token_auth +from app.api.auth import token_auth, token_permission_required from app.api.errors import error_response -from app.decorators import permission_required from app.scodoc.sco_evaluation_db import do_evaluation_get_all_notes from app.scodoc.sco_permissions import Permission @bp.route("/evaluations/", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def evaluations(moduleimpl_id: int): """ Retourne la liste des évaluations à partir de l'id d'un moduleimpl @@ -29,7 +29,8 @@ def evaluations(moduleimpl_id: int): @bp.route("/evaluations/eval_notes/", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def evaluation_notes(evaluation_id: int): """ Retourne la liste des notes à partir de l'id d'une évaluation donnée @@ -51,7 +52,7 @@ def evaluation_notes(evaluation_id: int): @bp.route("/evaluations/eval_set_notes?eval_id=&nip=¬e=", methods=["POST"]) @bp.route("/evaluations/eval_set_notes?eval_id=&ine=¬e=", methods=["POST"]) @token_auth.login_required -@permission_required(Permission.APIEditAllNotes) +@token_permission_required(Permission.APIEditAllNotes) def evaluation_set_notes(eval_id: int, note: float, etudid: int = None, nip: int = None, ine: int = None): """ Set les notes d'une évaluation pour un étudiant donnée diff --git a/app/api/formations.py b/app/api/formations.py index 84c84b9c..bc7258bb 100644 --- a/app/api/formations.py +++ b/app/api/formations.py @@ -4,6 +4,7 @@ from flask import jsonify 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.decorators import permission_required from app.scodoc.sco_formations import formation_export from app.scodoc.sco_moduleimpl import moduleimpl_list @@ -11,7 +12,8 @@ from app.scodoc.sco_permissions import Permission @bp.route("/formations", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def formations(): """ Retourne la liste des formations @@ -26,7 +28,8 @@ def formations(): @bp.route("/formations/", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def formations_by_id(formation_id: int): """ Retourne une formation en fonction d'un id donné @@ -43,7 +46,8 @@ def formations_by_id(formation_id: int): @bp.route("/formations/formation_export/", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def formation_export_by_formation_id(formation_id: int, export_ids=False): """ Retourne la formation, avec UE, matières, modules @@ -60,7 +64,8 @@ def formation_export_by_formation_id(formation_id: int, export_ids=False): @bp.route("/formations/apo/", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def formsemestre_apo(etape_apo: int): """ Retourne les informations sur les formsemestres @@ -81,7 +86,8 @@ def formsemestre_apo(etape_apo: int): @bp.route("/formations/moduleimpl/", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def moduleimpls(moduleimpl_id: int): """ Retourne la liste des moduleimpl @@ -98,7 +104,8 @@ def moduleimpls(moduleimpl_id: int): @bp.route("/formations/moduleimpl//formsemestre/", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def moduleimpls_sem(moduleimpl_id: int, formsemestre_id: int): """ Retourne la liste des moduleimpl d'un semestre diff --git a/app/api/formsemestres.py b/app/api/formsemestres.py index 2466562e..2b98c6d1 100644 --- a/app/api/formsemestres.py +++ b/app/api/formsemestres.py @@ -5,6 +5,7 @@ from app import models from app.api import bp from app.api.errors import error_response from app.decorators import permission_required +from app.api.auth import token_auth, token_permission_required from app.scodoc.sco_bulletins import formsemestre_bulletinetud_dict from app.scodoc.sco_permissions import Permission from app.scodoc.sco_pvjury import formsemestre_pvjury @@ -12,7 +13,8 @@ from app.scodoc.sco_recapcomplet import formsemestre_recapcomplet @bp.route("/formations/formsemestre/", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def formsemestre(formsemestre_id: int): """ Retourne l'information sur le formsemestre correspondant au formsemestre_id @@ -41,7 +43,8 @@ def formsemestre(formsemestre_id: int): "/formsemestre//departements//etudiant/ine//bulletin", methods=["GET"], ) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def etudiant_bulletin(formsemestre_id, dept, etudid, format="json", *args, size): """ Retourne le bulletin de note d'un étudiant @@ -67,7 +70,8 @@ def etudiant_bulletin(formsemestre_id, dept, etudid, format="json", *args, size) @bp.route("/formsemestre//bulletins", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def bulletins(formsemestre_id: int): """ Retourne les bulletins d'un formsemestre donné @@ -86,7 +90,8 @@ def bulletins(formsemestre_id: int): @bp.route("/formsemestre//jury", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def jury(formsemestre_id: int): """ Retourne le récapitulatif des décisions jury diff --git a/app/api/jury.py b/app/api/jury.py index 11e87c49..0e72fc1e 100644 --- a/app/api/jury.py +++ b/app/api/jury.py @@ -4,6 +4,7 @@ from flask import jsonify 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.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 be689d72..e1faf0bc 100644 --- a/app/api/logos.py +++ b/app/api/logos.py @@ -39,12 +39,13 @@ from app.api.errors import error_response from app.decorators import permission_required 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.scodoc.sco_permissions import Permission @bp.route("/logos", methods=["GET"]) @token_auth.login_required -@permission_required(Permission.APIView) +@token_permission_required(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") @@ -57,7 +58,7 @@ def api_get_glob_logos(): @bp.route("/logos/", methods=["GET"]) @token_auth.login_required -@permission_required(Permission.APIView) +@token_permission_required(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") @@ -74,7 +75,7 @@ def api_get_glob_logo(logoname): @bp.route("/departements//logos", methods=["GET"]) @token_auth.login_required -@permission_required(Permission.APIView) +@token_permission_required(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): @@ -85,7 +86,7 @@ def api_get_local_logos(departement): @bp.route("/departements//logos/", methods=["GET"]) @token_auth.login_required -@permission_required(Permission.APIView) +@token_permission_required(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 3847bac4..6369c3af 100644 --- a/app/api/partitions.py +++ b/app/api/partitions.py @@ -6,12 +6,14 @@ from app.api import bp from app.api.auth import token_auth from app.api.errors import error_response from app.decorators import permission_required +from app.api.auth import token_auth, token_permission_required from app.scodoc.sco_groups import get_group_members, setGroups from app.scodoc.sco_permissions import Permission @bp.route("/partitions/", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def partition(formsemestre_id: int): """ Retourne la liste de toutes les partitions d'un formsemestre @@ -34,7 +36,8 @@ def partition(formsemestre_id: int): # ) @bp.route("/partitions/groups/", methods=["GET"]) @bp.route("/partitions/groups//etat/", methods=["GET"]) -@permission_required(Permission.APIView) +@token_auth.login_required +@token_permission_required(Permission.APIView) def etud_in_group(group_id: int, etat=None): """ Retourne la liste des étudiants dans un groupe @@ -65,7 +68,7 @@ def etud_in_group(group_id: int, etat=None): "groups_to_create=&groups_to_delete=", methods=["POST"], ) @token_auth.login_required -@permission_required(Permission.APIEtudChangeGroups) +@token_permission_required(Permission.APIEtudChangeGroups) def set_groups(partition_id: int, groups_lists: int, groups_to_delete: int, groups_to_create: int): """ Set les groups diff --git a/tests/api/setup_test_api.py b/tests/api/setup_test_api.py index 8ca16358..a413f6fd 100644 --- a/tests/api/setup_test_api.py +++ b/tests/api/setup_test_api.py @@ -17,9 +17,9 @@ import os import requests -SCODOC_USER = "api_tester" -SCODOC_PASSWORD = "api_tester" -SCODOC_URL = "http://deb11.viennet.net:5000" +SCODOC_USER = "test" +SCODOC_PASSWORD = "test" +SCODOC_URL = "http://192.168.1.12:5000" CHECK_CERTIFICATE = bool(int(os.environ.get("CHECK_CERTIFICATE", False))) diff --git a/tests/api/test_api_departements.py b/tests/api/test_api_departements.py index 1e5e901e..7e68d3cc 100644 --- a/tests/api/test_api_departements.py +++ b/tests/api/test_api_departements.py @@ -23,7 +23,7 @@ from tests.api.setup_test_api import SCODOC_URL, CHECK_CERTIFICATE, HEADERS # departements -def test_departements(): +def test_departements(): #XXX TODO pour Seb r = requests.get( SCODOC_URL + "/ScoDoc/api/departements", headers=HEADERS, @@ -34,7 +34,7 @@ def test_departements(): # liste_etudiants -def test_liste_etudiants(): +def test_liste_etudiants(): #XXX TODO pour Seb r = requests.get( SCODOC_URL + "/ScoDoc/api/departements/TAPI/etudiants/liste", headers=HEADERS, @@ -53,7 +53,7 @@ def test_liste_etudiants(): # liste_semestres_courant -def test_semestres_courant(): +def test_semestres_courant(): #XXX TODO pour Seb r = requests.get( SCODOC_URL + "/ScoDoc/api/departements/TAPI/semestres_courants", headers=HEADERS, @@ -75,9 +75,9 @@ def test_referenciel_competences(): # # semestre_index -# def test_semestre_index(): -# r = requests.get( -# SCODOC_URL + "/ScoDoc/api/departements/TAPI/formsemestre/1/programme", -# headers=HEADERS, verify=CHECK_CERTIFICATE -# ) -# assert r.status_code == 200 +def test_semestre_index(): #XXX TODO pour Seb + r = requests.get( + SCODOC_URL + "/ScoDoc/api/departements/TAPI/formsemestre/1/programme", + headers=HEADERS, verify=CHECK_CERTIFICATE + ) + assert r.status_code == 200 diff --git a/tests/api/test_api_etudiants.py b/tests/api/test_api_etudiants.py index 9c93804f..3a71bc48 100644 --- a/tests/api/test_api_etudiants.py +++ b/tests/api/test_api_etudiants.py @@ -59,7 +59,7 @@ def test_etudiants(): # etudiants_courant -def test_etudiants_courant(): +def test_etudiants_courant(): #XXX TODO pour Seb r = requests.get( SCODOC_URL + "/ScoDoc/api/etudiants/courant", headers=HEADERS, @@ -70,7 +70,7 @@ def test_etudiants_courant(): # etudiant -def test_etudiant(): +def test_etudiant(): #XXX TODO pour Seb r = requests.get( SCODOC_URL + "/ScoDoc/api/etudiant/etudid/1", headers=HEADERS, @@ -92,7 +92,7 @@ def test_etudiant(): # etudiant_formsemestres -def test_etudiant_formsemestres(): +def test_etudiant_formsemestres(): #XXX TODO pour Seb r = requests.get( SCODOC_URL + "/ScoDoc/api/etudiant/etudid/1/formsemestres", headers=HEADERS, diff --git a/tests/api/test_api_formsemestre_.py b/tests/api/test_api_formsemestre_.py index d703ac7e..4a702f37 100644 --- a/tests/api/test_api_formsemestre_.py +++ b/tests/api/test_api_formsemestre_.py @@ -32,7 +32,7 @@ def test_formsemestre(): # etudiant_bulletin -def test_etudiant_bulletin(): +def test_etudiant_bulletin(): #XXX TODO pour Seb r = requests.get( SCODOC_URL + "/ScoDoc/api/formsemestre//departements//etudiant/etudid//bulletin", diff --git a/tools/fakedatabase/create_test_api_database.py b/tools/fakedatabase/create_test_api_database.py index 8e19065a..19e70074 100644 --- a/tools/fakedatabase/create_test_api_database.py +++ b/tools/fakedatabase/create_test_api_database.py @@ -14,6 +14,10 @@ flask sco-db-init --erase flask init-test-database flask user-role -a Admin -d TAPI test + flask user-password test + flask create-role APIUserViewer + flask edit-role APIUserViewer -a APIView + flask user-role test -a APIUserViewer 3) relancer ScoDoc: flask run --host 0.0.0.0 @@ -104,7 +108,7 @@ def create_formsemestre(formation, user, semestre_idx=1): semestre_id=semestre_idx, titre="Semestre test", date_debut=datetime.datetime(2021, 9, 1), - date_fin=datetime.datetime(2022, 1, 31), + date_fin=datetime.datetime(2022, 8, 31), modalite="FI", formation=formation, ) @@ -137,6 +141,7 @@ def inscrit_etudiants(etuds, formsemestre): def init_test_database(): + dept = init_departement("TAPI") user = create_user(dept) etuds = create_etuds(dept)