Merge branch 'master' of https://scodoc.org/git/ScoDoc/ScoDoc into entreprises
This commit is contained in:
commit
8e730c2164
@ -46,23 +46,16 @@ from app.scodoc.sco_permissions import Permission
|
||||
|
||||
@bp.route("/logos")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
@permission_required(Permission.ScoSuperAdmin)
|
||||
def api_get_glob_logos():
|
||||
if not g.current_user.has_permission(Permission.ScoSuperAdmin, None):
|
||||
return json_error(403, message="accès interdit")
|
||||
required_format = requested_format() # json only
|
||||
if required_format is None:
|
||||
return json_error(400, "Illegal format")
|
||||
logos = list_logos()[None]
|
||||
return jsonify(list(logos.keys()))
|
||||
|
||||
|
||||
@bp.route("/logos/<string:logoname>")
|
||||
@bp.route("/logo/<string:logoname>")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
@permission_required(Permission.ScoSuperAdmin)
|
||||
def api_get_glob_logo(logoname):
|
||||
if not g.current_user.has_permission(Permission.ScoSuperAdmin, None):
|
||||
return json_error(403, message="accès interdit")
|
||||
logo = find_logo(logoname=logoname)
|
||||
if logo is None:
|
||||
return json_error(404, message="logo not found")
|
||||
@ -74,25 +67,27 @@ def api_get_glob_logo(logoname):
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/departements/<string:departement>/logos")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
def api_get_local_logos(departement):
|
||||
dept_id = Departement.from_acronym(departement).id
|
||||
if not g.current_user.has_permission(Permission.ScoChangePreferences, departement):
|
||||
return json_error(403, message="accès interdit")
|
||||
def core_get_logos(dept_id):
|
||||
logos = list_logos().get(dept_id, dict())
|
||||
return jsonify(list(logos.keys()))
|
||||
|
||||
|
||||
@bp.route("/departements/<string:departement>/logos/<string:logoname>")
|
||||
@bp.route("/departement/<string:departement>/logos")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
def api_get_local_logo(departement, logoname):
|
||||
# format = requested_format("jpg", ['png', 'jpg']) XXX ?
|
||||
@permission_required(Permission.ScoSuperAdmin)
|
||||
def api_get_local_logos_by_acronym(departement):
|
||||
dept_id = Departement.from_acronym(departement).id
|
||||
if not g.current_user.has_permission(Permission.ScoChangePreferences, departement):
|
||||
return json_error(403, message="accès interdit")
|
||||
return core_get_logos(dept_id)
|
||||
|
||||
|
||||
@bp.route("/departement/id/<int:dept_id>/logos")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoSuperAdmin)
|
||||
def api_get_local_logos_by_id(dept_id):
|
||||
return core_get_logos(dept_id)
|
||||
|
||||
|
||||
def core_get_logo(dept_id, logoname):
|
||||
logo = find_logo(logoname=logoname, dept_id=dept_id)
|
||||
if logo is None:
|
||||
return json_error(404, message="logo not found")
|
||||
@ -102,3 +97,18 @@ def api_get_local_logo(departement, logoname):
|
||||
mimetype=f"image/{logo.suffix}",
|
||||
last_modified=datetime.now(),
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/departement/<string:departement>/logo/<string:logoname>")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoSuperAdmin)
|
||||
def api_get_local_logo_dept_by_acronym(departement, logoname):
|
||||
dept_id = Departement.from_acronym(departement).id
|
||||
return core_get_logo(dept_id, logoname)
|
||||
|
||||
|
||||
@bp.route("/departement/id/<int:dept_id>/logo/<string:logoname>")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoSuperAdmin)
|
||||
def api_get_local_logo_dept_by_id(dept_id, logoname):
|
||||
return core_get_logo(dept_id, logoname)
|
||||
|
@ -14,9 +14,9 @@ from flask_login import current_user, login_required
|
||||
|
||||
from app import db, log
|
||||
from app.api import api_bp as bp, api_web_bp
|
||||
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 is_valid_password
|
||||
from app.decorators import scodoc, permission_required
|
||||
from app.models import Departement
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
@ -38,7 +38,7 @@ def user_info(uid: int):
|
||||
return json_error(404, "user not found")
|
||||
if g.scodoc_dept:
|
||||
allowed_depts = current_user.get_depts_with_permission(Permission.ScoUsersView)
|
||||
if user.dept not in allowed_depts:
|
||||
if (None not in allowed_depts) and (user.dept not in allowed_depts):
|
||||
return json_error(404, "user not found")
|
||||
|
||||
return jsonify(user.to_dict())
|
||||
@ -109,7 +109,7 @@ def user_create():
|
||||
if dept == "@all":
|
||||
dept = None
|
||||
allowed_depts = current_user.get_depts_with_permission(Permission.ScoUsersAdmin)
|
||||
if dept not in allowed_depts:
|
||||
if (None not in allowed_depts) and (dept not in allowed_depts):
|
||||
return json_error(403, "user_create: departement non autorise")
|
||||
if (dept is not None) and (
|
||||
Departement.query.filter_by(acronym=dept).first() is None
|
||||
@ -168,6 +168,35 @@ def user_edit(uid: int):
|
||||
return jsonify(user.to_dict())
|
||||
|
||||
|
||||
@bp.route("/user/<int:uid>/password", methods=["POST"])
|
||||
@api_web_bp.route("/user/<int:uid>/password", methods=["POST"])
|
||||
@login_required
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoUsersAdmin)
|
||||
def user_password(uid: int):
|
||||
"""Modification du mot de passe d'un utilisateur
|
||||
Champs modifiables:
|
||||
{
|
||||
"password": str
|
||||
}
|
||||
Si le mot de passe ne convient pas, erreur 400.
|
||||
"""
|
||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||
user: User = User.query.get_or_404(uid)
|
||||
password = data.get("password")
|
||||
if not password:
|
||||
return json_error(404, "user_password: missing password")
|
||||
if not is_valid_password(password):
|
||||
return json_error(400, "user_password: invalid password")
|
||||
allowed_depts = current_user.get_depts_with_permission(Permission.ScoUsersAdmin)
|
||||
if (None not in allowed_depts) and ((user.dept not in allowed_depts)):
|
||||
return json_error(403, "user_password: departement non autorise")
|
||||
user.set_password(password)
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
return jsonify(user.to_dict())
|
||||
|
||||
|
||||
@bp.route("/user/<int:uid>/role/<string:role_name>/add", methods=["POST"])
|
||||
@api_web_bp.route("/user/<int:uid>/role/<string:role_name>/add", methods=["POST"])
|
||||
@bp.route(
|
||||
|
@ -51,6 +51,7 @@ print(f"API URL={API_URL}")
|
||||
|
||||
|
||||
HEADERS = get_auth_headers(API_USER, API_PASSWORD)
|
||||
admin_h = get_auth_headers("admin_api", "admin_api")
|
||||
|
||||
departements = GET("/departements", headers=HEADERS)
|
||||
pp(departements)
|
||||
|
@ -6,8 +6,9 @@
|
||||
|
||||
Usage:
|
||||
cd /opt/scodoc/tests/api
|
||||
python make_samples.py
|
||||
python make_samples.py [entry_names]
|
||||
|
||||
si entry_names est spécifié, la génération est restreints aux exemples cités. expl: `python make_samples departements departement-formsemestres`
|
||||
doit être exécutée immédiatement apres une initialisation de la base pour test API! (car dépendant des identifiants générés lors de la création des objets)
|
||||
cd /opt/scodoc/tests/api
|
||||
tools/create_database.sh --drop SCODOC_TEST_API && flask db upgrade &&flask sco-db-init --erase && flask init-test-database
|
||||
@ -41,6 +42,8 @@ TODO: ajouter un argument au script permettant de ne générer qu'un seul fichie
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import re
|
||||
from collections import defaultdict
|
||||
from pprint import pprint as pp
|
||||
from pprint import pformat as pf
|
||||
@ -69,6 +72,7 @@ class Sample:
|
||||
self.url = url
|
||||
self.method = method
|
||||
self.result = None
|
||||
self.output = "json"
|
||||
if permission == "ScoView":
|
||||
HEADERS = get_auth_headers("test", "test")
|
||||
elif permission == "ScoSuperAdmin":
|
||||
@ -87,16 +91,16 @@ class Sample:
|
||||
self.result = POST_JSON(self.url, json.loads(self.content), HEADERS)
|
||||
elif self.method[0] != "#":
|
||||
raise Exception(f"Bad method : {self.method}")
|
||||
else: # method begin with # => comment
|
||||
print(" pass")
|
||||
self.shorten()
|
||||
file = open(f"sample_TEST.json.md", "tw")
|
||||
self.dump(file)
|
||||
file.close()
|
||||
|
||||
def _shorten(self, item):
|
||||
def _shorten(
|
||||
self, item
|
||||
): # abrege les longues listes (limite à 2 éléments et affiche "... etc. à la place"
|
||||
if isinstance(item, list):
|
||||
return [self._shorten(child) for child in item[:2]]
|
||||
return [self._shorten(child) for child in item[:2]] + ["... etc."]
|
||||
return item
|
||||
|
||||
def shorten(self):
|
||||
@ -117,19 +121,36 @@ class Sample:
|
||||
file.write(f"> `{self.content}`\n\n")
|
||||
|
||||
file.write("```json\n")
|
||||
file.write(json.dumps(self.result, indent=4))
|
||||
content = json.dumps(self.result, indent=4, sort_keys=True)
|
||||
content = content.replace("... etc.", "...")
|
||||
# regexp for date like: "2022-08-14T10:01:44.043869+02:00"
|
||||
regexp = re.compile(
|
||||
r'"(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?"'
|
||||
)
|
||||
content = regexp.sub('"2022-08-20T12:00:00.000000+02:00"', content)
|
||||
file.write(content)
|
||||
file.write("\n```\n\n")
|
||||
|
||||
|
||||
class Samples:
|
||||
def __init__(self):
|
||||
def __init__(self, entry_names):
|
||||
"""Entry_names: la liste des entrées à reconstruire.
|
||||
si None, la totalité des lignes de samples.csv est prise en compte
|
||||
"""
|
||||
self.entries = defaultdict(lambda: set())
|
||||
self.entry_names = entry_names
|
||||
|
||||
def add_sample(self, entry, url, method="GET", permission="ScoView", content=None):
|
||||
show_content = "" if content == "" else f": '{content}'"
|
||||
print(f"{entry:50} {method:5} {url:50} {show_content}")
|
||||
sample = Sample(url, method, permission, content)
|
||||
self.entries[entry].add(sample)
|
||||
if self.entry_names is None or entry in self.entry_names:
|
||||
if method[0] == "#":
|
||||
detail = "**ignored**"
|
||||
elif content == "":
|
||||
detail = ""
|
||||
else:
|
||||
detail = f": {content}"
|
||||
print(f"{entry:50} {method:5} {url:50} {detail}")
|
||||
sample = Sample(url, method, permission, content)
|
||||
self.entries[entry].add(sample)
|
||||
|
||||
def pp(self):
|
||||
for entry, samples in self.entries.items():
|
||||
@ -141,12 +162,18 @@ class Samples:
|
||||
for entry, samples in self.entries.items():
|
||||
file = open(f"{DATA_DIR}sample_{entry}.json.md", "tw")
|
||||
file.write(f"### {entry}\n\n")
|
||||
for sample in samples:
|
||||
for sample in sorted(
|
||||
samples, key=lambda s: s.url
|
||||
): # sorted de façon à rendre le fichier résultat déterministe (i.e. indépendant de l ordre d arrivée des résultats)
|
||||
sample.dump(file)
|
||||
file.close()
|
||||
|
||||
|
||||
def make_samples():
|
||||
if len(sys.argv) == 1:
|
||||
entry_names = None
|
||||
else:
|
||||
entry_names = sys.argv[1:]
|
||||
if os.path.exists(DATA_DIR):
|
||||
if not os.path.isdir(DATA_DIR):
|
||||
raise f"{DATA_DIR} existe déjà et n'est pas un répertoire"
|
||||
@ -157,9 +184,9 @@ def make_samples():
|
||||
else:
|
||||
os.mkdir("/tmp/samples")
|
||||
|
||||
samples = Samples()
|
||||
# samples.pp()
|
||||
with open("samples.csv") as f:
|
||||
samples = Samples(entry_names)
|
||||
samples_file = os.path.dirname(__file__) + "/samples.csv"
|
||||
with open(samples_file) as f:
|
||||
L = [x[:-1].split("\t") for x in f]
|
||||
for line in L[1:]:
|
||||
entry_name = line[0]
|
||||
|
@ -26,6 +26,7 @@ etudiant_formsemestres /etudiant/nip/11/formsemestres GET
|
||||
etudiant-formsemestre-bulletin /etudiant/etudid/11/formsemestre/1/bulletin GET
|
||||
etudiant-formsemestre-bulletin /etudiant/ine/INE11/formsemestre/1/bulletin GET
|
||||
etudiant-formsemestre-bulletin /etudiant/nip/11/formsemestre/1/bulletin GET
|
||||
etudiant-formsemestre-bulletin /etudiant/nip/11/formsemestre/1/bulletin/short/pdf GET
|
||||
etudiant-formsemestre-groups /etudiant/etudid/11/formsemestre/1/groups GET
|
||||
formations /formations GET
|
||||
formations_ids /formations_ids GET
|
||||
@ -67,11 +68,30 @@ partition-groups-order /partition/1/groups/order ScoSuperAdmin POST [ 1 ]
|
||||
partition-delete /partition/2/delete ScoSuperAdmin POST
|
||||
user-create /user/create ScoSuperAdmin POST {"user_name": "alain", "dept": null, "nom": "alain", "prenom": "bruno", "active": true }
|
||||
user-edit /user/10/edit ScoSuperAdmin POST { "dept": "TAPI", "nom": "alain2", "prenom": "bruno2", "active": false }
|
||||
user-role-add /user/10/role/Observateur/add ScoSuperAdmin POST
|
||||
user-password /user/3/password ScoSuperAdmin POST { "password": "rePlaCemeNT456averylongandcomplicated" }
|
||||
user-password /user/3/password ScoSuperAdmin POST { "password": "too_simple" }
|
||||
user-role-add /user/10/role/Observateur/add ScoSuperAdmin POST
|
||||
user-role-remove /user/10/role/Observateur/remove ScoSuperAdmin POST
|
||||
role-create /role/create/customRole ScoSuperAdmin POST {"permissions": ["ScoView", "ScoUsersView"]}
|
||||
role-remove_permission /role/customRole/remove_permission/ScoUsersView ScoSuperAdmin POST
|
||||
role-add_permission /role/customRole/add_permission/ScoUsersView ScoSuperAdmin POST
|
||||
role-edit /role/customRole/edit ScoSuperAdmin POST { "name" : "LaveurDeVitres", "permissions" : [ "ScoView", "APIView" ] }
|
||||
role-edit /role/customRole/edit ScoSuperAdmin POST { "name" : "LaveurDeVitres", "permissions" : [ "ScoView", "APIView" ] }
|
||||
role-delete /role/customRole/delete ScoSuperAdmin POST
|
||||
logos /logos ScoSuperAdmin GET
|
||||
logo /logo/demo ScoSuperAdmin GET
|
||||
departement-logos /departement/TAPI/logos ScoSuperAdmin GET
|
||||
departement-logos /departement/id/1/logos ScoSuperAdmin GET
|
||||
departement-logo /departement/TAPI/logo/demo ScoSuperAdmin GET
|
||||
departement-logo /departement/id/1/logo/demo ScoSuperAdmin GET
|
||||
test-pdf /etudiant/nip/11/formsemestre/1/bulletin/pdf GET
|
||||
test-pdf /etudiant/nip/11/formsemestre/1/bulletin/pdf GET
|
||||
test-pdf /etudiant/etudid/11/formsemestre/1/bulletin/short/pdf GET
|
||||
test-pdf /etudiant/ine/INE11/formsemestre/1/bulletin/short/pdf GET
|
||||
test-pdf /etudiant/nip/11/formsemestre/1/bulletin/short/pdf GET
|
||||
test-pdf /etudiant/etudid/11/formsemestre/1/bulletin/pdf GET
|
||||
test-pdf /etudiant/etudid/11/formsemestre/1/bulletin/short GET
|
||||
test-pdf /etudiant/ine/INE11/formsemestre/1/bulletin/short GET
|
||||
test-pdf /etudiant/nip/11/formsemestre/1/bulletin/short GET
|
||||
test-pdf /etudiant/etudid/11/formsemestre/1/bulletin GET
|
||||
test-pdf /etudiant/ine/INE11/formsemestre/1/bulletin GET
|
||||
test-pdf /etudiant/nip/11/formsemestre/1/bulletin GET
|
||||
|
Can't render this file because it contains an unexpected character in line 12 and column 60.
|
@ -65,7 +65,9 @@ def api_admin_headers() -> dict:
|
||||
|
||||
|
||||
def GET(path: str, headers: dict = None, errmsg=None, dept=None):
|
||||
"""Get and returns as JSON"""
|
||||
"""Get and returns as JSON
|
||||
Special case for non json result (image or pdf): return Content-Disposition string (inline or attachment)
|
||||
"""
|
||||
if dept:
|
||||
url = SCODOC_URL + f"/ScoDoc/{dept}/api" + path
|
||||
else:
|
||||
@ -73,13 +75,34 @@ def GET(path: str, headers: dict = None, errmsg=None, dept=None):
|
||||
r = requests.get(url, headers=headers or {}, verify=CHECK_CERTIFICATE)
|
||||
if r.status_code != 200:
|
||||
raise APIError(errmsg or f"""erreur status={r.status_code} !""", r.json())
|
||||
|
||||
if r.headers.get("Content-Type", None) == "application/json":
|
||||
return r.json() # decode la reponse JSON
|
||||
elif r.headers.get("Content-Type", None) in [
|
||||
"image/jpg",
|
||||
"image/png",
|
||||
"application/pdf",
|
||||
]:
|
||||
retval = {
|
||||
"Content-Type": r.headers.get("Content-Type", None),
|
||||
"Content-Disposition": r.headers.get("Content-Disposition", None),
|
||||
}
|
||||
return retval
|
||||
else:
|
||||
raise APIError(
|
||||
"Unknown returned content {r.headers.get('Content-Type', None} !\n"
|
||||
)
|
||||
return r.json() # decode la reponse JSON
|
||||
|
||||
|
||||
def POST_JSON(path: str, data: dict = {}, headers: dict = None, errmsg=None):
|
||||
def POST_JSON(path: str, data: dict = {}, headers: dict = None, errmsg=None, dept=None):
|
||||
"""Post"""
|
||||
if dept:
|
||||
url = SCODOC_URL + f"/ScoDoc/{dept}/api" + path
|
||||
else:
|
||||
url = API_URL + path
|
||||
r = requests.post(
|
||||
API_URL + path,
|
||||
url,
|
||||
json=data,
|
||||
headers=headers or {},
|
||||
verify=CHECK_CERTIFICATE,
|
||||
|
@ -14,7 +14,7 @@ utilisation:
|
||||
# Ce test a une logique très différente des autres : A UNIFIER
|
||||
|
||||
|
||||
from tests.api.setup_test_api import API_URL
|
||||
from tests.api.setup_test_api import API_URL, api_admin_headers, api_headers
|
||||
|
||||
from scodoc import app
|
||||
from tests.unit.config_test_logos import (
|
||||
@ -26,48 +26,152 @@ from tests.unit.config_test_logos import (
|
||||
)
|
||||
|
||||
|
||||
def test_super_access(create_super_token):
|
||||
def test_super_access(api_admin_headers):
|
||||
"""
|
||||
Route: /logos
|
||||
"""
|
||||
dept1, dept2, dept3, token = create_super_token
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
with app.test_client() as client:
|
||||
headers = api_admin_headers
|
||||
with app.test_client(api_admin_headers) as client:
|
||||
response = client.get(API_URL + "/logos", headers=headers)
|
||||
assert response.status_code == 200
|
||||
assert response.json is not None
|
||||
|
||||
|
||||
def test_admin_access(create_admin_token):
|
||||
def test_admin_access(api_headers):
|
||||
"""
|
||||
Route:
|
||||
Route: /logos
|
||||
"""
|
||||
dept1, dept2, dept3, token = create_admin_token
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
headers = api_headers
|
||||
with app.test_client() as client:
|
||||
response = client.get(API_URL + "/logos", headers=headers)
|
||||
assert response.status_code == 403
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_lambda_access(create_lambda_token):
|
||||
def test_lambda_access(api_headers):
|
||||
"""
|
||||
Route:
|
||||
Route: /logos
|
||||
"""
|
||||
dept1, dept2, dept3, token = create_lambda_token
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
headers = api_headers
|
||||
with app.test_client() as client:
|
||||
response = client.get(API_URL + "/logos", headers=headers)
|
||||
assert response.status_code == 403
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_initial_with_header_and_footer(create_super_token):
|
||||
def test_global_logos(api_admin_headers):
|
||||
"""
|
||||
Route:
|
||||
"""
|
||||
dept1, dept2, dept3, token = create_super_token
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
headers = api_admin_headers
|
||||
with app.test_client() as client:
|
||||
response = client.get(API_URL + "/logos", headers=headers)
|
||||
assert response.status_code == 200
|
||||
assert response.json is not None
|
||||
assert len(response.json) == 7
|
||||
assert (
|
||||
len(response.json) == 4
|
||||
) # 4 items in fakelogo context: ['header', 'footer', 'logo_B', 'logo_C']
|
||||
|
||||
|
||||
def test_local_by_id_logos(api_admin_headers):
|
||||
"""
|
||||
Route: /departement/id/1/logos
|
||||
"""
|
||||
headers = api_admin_headers
|
||||
with app.test_client() as client:
|
||||
response = client.get(API_URL + "/departement/id/1/logos", headers=headers)
|
||||
assert response.status_code == 200
|
||||
assert response.json is not None
|
||||
assert (
|
||||
len(response.json) == 2
|
||||
) # 2 items in dept(1, TAPI) fakelogo context: ['logo_A', 'logo_D']
|
||||
|
||||
|
||||
def test_local_by_name_logos(api_admin_headers):
|
||||
"""
|
||||
Route: /departement/TAPI/logos
|
||||
"""
|
||||
headers = api_admin_headers
|
||||
with app.test_client() as client:
|
||||
response = client.get(API_URL + "/departement/TAPI/logos", headers=headers)
|
||||
assert response.status_code == 200
|
||||
assert response.json is not None
|
||||
assert (
|
||||
len(response.json) == 2
|
||||
) # 2 items in dept(1, TAPI) fakelogo context: ['logo_A', 'logo_D']
|
||||
|
||||
|
||||
def test_local_png_by_id_logo(api_admin_headers):
|
||||
"""
|
||||
Route: /departement/id/1/logo/D
|
||||
"""
|
||||
headers = api_admin_headers
|
||||
with app.test_client() as client:
|
||||
response = client.get(API_URL + "/departement/id/1/logo/D", headers=headers)
|
||||
assert response.status_code == 200
|
||||
assert response.headers["Content-Type"] == "image/png"
|
||||
assert response.headers["Content-Disposition"].startswith("inline")
|
||||
assert "logo_D.png" in response.headers["Content-Disposition"]
|
||||
|
||||
|
||||
def test_global_png_logo(api_admin_headers):
|
||||
"""
|
||||
Route: /logo/C
|
||||
"""
|
||||
headers = api_admin_headers
|
||||
with app.test_client() as client:
|
||||
response = client.get(API_URL + "/logo/C", headers=headers)
|
||||
assert response.status_code == 200
|
||||
assert response.headers["Content-Type"] == "image/png"
|
||||
assert response.headers["Content-Disposition"].startswith("inline")
|
||||
assert "logo_C.png" in response.headers["Content-Disposition"]
|
||||
|
||||
|
||||
def test_global_jpg_logo(api_admin_headers):
|
||||
"""
|
||||
Route: /logo/B
|
||||
"""
|
||||
headers = api_admin_headers
|
||||
with app.test_client() as client:
|
||||
response = client.get(API_URL + "/logo/B", headers=headers)
|
||||
assert response.status_code == 200
|
||||
assert response.headers["Content-Type"] == "image/jpg"
|
||||
assert response.headers["Content-Disposition"].startswith("inline")
|
||||
assert "logo_B.jpg" in response.headers["Content-Disposition"]
|
||||
|
||||
|
||||
def test_local_png_by_name_logo(api_admin_headers):
|
||||
"""
|
||||
Route: /departement/TAPI/logo/A
|
||||
"""
|
||||
headers = api_admin_headers
|
||||
with app.test_client() as client:
|
||||
response = client.get(API_URL + "/departement/TAPI/logo/D", headers=headers)
|
||||
assert response.status_code == 200
|
||||
assert response.headers["Content-Type"] == "image/png"
|
||||
assert response.headers["Content-Disposition"].startswith("inline")
|
||||
assert "logo_D.png" in response.headers["Content-Disposition"]
|
||||
|
||||
|
||||
def test_local_jpg_by_id_logo(api_admin_headers):
|
||||
"""
|
||||
Route: /departement/id/1/logo/D
|
||||
"""
|
||||
headers = api_admin_headers
|
||||
with app.test_client() as client:
|
||||
response = client.get(API_URL + "/departement/id/1/logo/A", headers=headers)
|
||||
assert response.status_code == 200
|
||||
assert response.headers["Content-Type"] == "image/jpg"
|
||||
assert response.headers["Content-Disposition"].startswith("inline")
|
||||
assert "logo_A.jpg" in response.headers["Content-Disposition"]
|
||||
|
||||
|
||||
def test_local_jpg_by_name_logo(api_admin_headers):
|
||||
"""
|
||||
Route: /departement/TAPI/logo/A
|
||||
"""
|
||||
headers = api_admin_headers
|
||||
with app.test_client() as client:
|
||||
response = client.get(API_URL + "/departement/TAPI/logo/A", headers=headers)
|
||||
assert response.status_code == 200
|
||||
assert response.headers["Content-Type"] == "image/jpg"
|
||||
assert response.headers["Content-Disposition"].startswith("inline")
|
||||
assert "logo_A.jpg" in response.headers["Content-Disposition"]
|
||||
|
@ -8,6 +8,7 @@ Utilisation :
|
||||
|
||||
from tests.api.setup_test_api import (
|
||||
API_URL,
|
||||
APIError,
|
||||
CHECK_CERTIFICATE,
|
||||
GET,
|
||||
POST_JSON,
|
||||
@ -83,7 +84,7 @@ def test_edit_users(api_admin_headers):
|
||||
assert (nb_users + 1) == len(GET("/users/query", headers=admin_h))
|
||||
# Change le dept et rend inactif
|
||||
user = POST_JSON(
|
||||
f"/user/edit/{user['id']}",
|
||||
f"/user/{user['id']}/edit",
|
||||
{"active": False, "dept": "TAPI"},
|
||||
headers=admin_h,
|
||||
)
|
||||
@ -129,3 +130,102 @@ def test_roles(api_admin_headers):
|
||||
assert set(role["permissions"]) == {"ScoView", "ScoAbsAddBillet"}
|
||||
ans = POST_JSON("/role/Test_Y/delete", headers=admin_h)
|
||||
assert ans["OK"] is True
|
||||
|
||||
|
||||
def test_modif_users_depts(api_admin_headers):
|
||||
"""
|
||||
Ce test vise à vérifier qu'un admin déclaré sur deux départements peut
|
||||
bien modifier les utilisateurs de ses départements mais pas ceux des autres.
|
||||
"""
|
||||
admin_h = api_admin_headers
|
||||
depts = GET("/departements", headers=admin_h)
|
||||
assert len(depts) > 2
|
||||
dept1, dept2, dept3 = depts[:3]
|
||||
# On va utiliser les 3 1er dept (TAPI, AA, BB)
|
||||
# On crée un nouvel utilisateur "chef2", admin dans les 2 premiers dept
|
||||
# puis un utilisateur lambda, dans le dept 2 (AA)
|
||||
chef2 = POST_JSON(
|
||||
"/user/create",
|
||||
{
|
||||
"user_name": "chef2",
|
||||
"nom": "Chef",
|
||||
"prenom": "Test",
|
||||
"dept": dept1["acronym"], # rattaché à dept1
|
||||
},
|
||||
headers=admin_h,
|
||||
)
|
||||
role_chef = POST_JSON(
|
||||
"/role/create/chef",
|
||||
{"permissions": ["ScoView", "ScoUsersAdmin", "ScoUsersView"]},
|
||||
headers=admin_h,
|
||||
)
|
||||
_ = POST_JSON(
|
||||
f"/user/{chef2['id']}/role/chef/add/departement/{dept1['acronym']}",
|
||||
headers=admin_h,
|
||||
)
|
||||
_ = POST_JSON(
|
||||
f"/user/{chef2['id']}/role/chef/add/departement/{dept2['acronym']}",
|
||||
headers=admin_h,
|
||||
)
|
||||
# Un mot de passe trop simple:
|
||||
ok = False
|
||||
try:
|
||||
_ = POST_JSON(
|
||||
f"/user/{chef2['id']}/password",
|
||||
{"password": "123456"},
|
||||
headers=admin_h,
|
||||
)
|
||||
except APIError as exc:
|
||||
if exc.args[1]["status"] == 400:
|
||||
ok = True
|
||||
assert ok
|
||||
# Un "vrai" mot de passe:
|
||||
chef2_password = "17HIOPpYhabb8qw'E:/jd7FFddjd"
|
||||
_ = POST_JSON(
|
||||
f"/user/{chef2['id']}/password",
|
||||
{"password": chef2_password},
|
||||
headers=admin_h,
|
||||
)
|
||||
# Création user lambda:
|
||||
u_lambda = POST_JSON(
|
||||
"/user/create",
|
||||
{
|
||||
"user_name": "lambda",
|
||||
"nom": "Lambda",
|
||||
"prenom": "Test",
|
||||
"dept": dept2["acronym"],
|
||||
},
|
||||
headers=admin_h,
|
||||
)
|
||||
|
||||
# Le chef va modifier u_lambda:
|
||||
chef_h = get_auth_headers(chef2["user_name"], chef2_password)
|
||||
# on utilise une URL avec département car on n'a pas le droit sur tous:
|
||||
u = POST_JSON(
|
||||
f"/user/{u_lambda['id']}/edit",
|
||||
{"nom": "toto"},
|
||||
headers=chef_h,
|
||||
dept=dept1["acronym"],
|
||||
)
|
||||
assert u["nom"] == "toto"
|
||||
# Dans l'autre ?
|
||||
u = POST_JSON(
|
||||
f"/user/{u_lambda['id']}/edit",
|
||||
{"nom": "toto"},
|
||||
headers=chef_h,
|
||||
dept=dept2["acronym"],
|
||||
)
|
||||
# mais pas dans le troisième:
|
||||
ok = False
|
||||
try:
|
||||
u = POST_JSON(
|
||||
f"/user/{u_lambda['id']}/edit",
|
||||
{"nom": "toto"},
|
||||
headers=chef_h,
|
||||
dept=dept3["acronym"],
|
||||
)
|
||||
except APIError as exc:
|
||||
if exc.args[1]["status"] == 401:
|
||||
ok = True
|
||||
assert ok
|
||||
# Nettoyage:
|
||||
|
@ -8,7 +8,9 @@
|
||||
|
||||
"""
|
||||
import datetime
|
||||
import os
|
||||
import random
|
||||
import shutil
|
||||
import time
|
||||
import sys
|
||||
|
||||
@ -45,6 +47,10 @@ REFCOMP_FILENAME = (
|
||||
"ressources/referentiels/but2022/competences/but-RT-05012022-081735.xml"
|
||||
)
|
||||
|
||||
# la réserve de logos
|
||||
LOGOS_STOCK = "/opt/scodoc/tests/ressources/test_logos/"
|
||||
LOGOS_DIR = "/opt/scodoc-data/config/logos/"
|
||||
|
||||
|
||||
def create_departements(acronyms: list[str]) -> list[Departement]:
|
||||
"Create depts"
|
||||
@ -353,6 +359,27 @@ def create_etape_apo(formsemestre: FormSemestre):
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def create_logos():
|
||||
if not os.path.exists(LOGOS_DIR + "logos_1"):
|
||||
os.mkdir(LOGOS_DIR + "logos_1")
|
||||
shutil.copy(
|
||||
LOGOS_STOCK + "logo_A.jpg",
|
||||
LOGOS_DIR + "logos_1/logo_A.jpg",
|
||||
)
|
||||
shutil.copy(
|
||||
LOGOS_STOCK + "logo_D.png",
|
||||
LOGOS_DIR + "logos_1/logo_D.png",
|
||||
)
|
||||
shutil.copy(
|
||||
LOGOS_STOCK + "logo_A.jpg",
|
||||
LOGOS_DIR + "logo_B.jpg",
|
||||
)
|
||||
shutil.copy(
|
||||
LOGOS_STOCK + "logo_D.png",
|
||||
LOGOS_DIR + "logo_C.png",
|
||||
)
|
||||
|
||||
|
||||
def init_test_database():
|
||||
"""Appelé par la commande `flask init-test-database`
|
||||
|
||||
@ -373,6 +400,7 @@ def init_test_database():
|
||||
saisie_notes_evaluations(formsemestre, user_lecteur)
|
||||
add_absences(formsemestre)
|
||||
create_etape_apo(formsemestre)
|
||||
create_logos()
|
||||
# à compléter
|
||||
# - groupes
|
||||
# - absences
|
||||
|
Loading…
Reference in New Issue
Block a user