forked from ScoDoc/ScoDoc
API FormSemestreDescription: images: upload, tests.
This commit is contained in:
parent
5a751cb6e7
commit
4bfd0858a8
@ -13,12 +13,14 @@
|
||||
FormSemestre
|
||||
|
||||
"""
|
||||
import mimetypes
|
||||
import base64
|
||||
import io
|
||||
from operator import attrgetter, itemgetter
|
||||
|
||||
from flask import g, make_response, request
|
||||
from flask_json import as_json
|
||||
from flask_login import current_user, login_required
|
||||
import PIL
|
||||
import sqlalchemy as sa
|
||||
import app
|
||||
from app import db, log
|
||||
@ -820,8 +822,8 @@ def formsemestre_get_description(formsemestre_id: int):
|
||||
@permission_required(Permission.ScoView)
|
||||
@as_json
|
||||
def formsemestre_edit_description(formsemestre_id: int):
|
||||
"""Modifie description externe du formsemestre
|
||||
|
||||
"""Modifie description externe du formsemestre.
|
||||
Les images peuvent êtres passées dans el json, encodées en base64.
|
||||
formsemestre_id : l'id du formsemestre
|
||||
|
||||
SAMPLES
|
||||
@ -832,6 +834,10 @@ def formsemestre_edit_description(formsemestre_id: int):
|
||||
args = request.get_json(force=True) # may raise 400 Bad Request
|
||||
if not formsemestre.description:
|
||||
formsemestre.description = FormSemestreDescription()
|
||||
# Decode images (base64)
|
||||
for key in ["image", "photo_ens"]:
|
||||
if key in args:
|
||||
args[key] = base64.b64decode(args[key])
|
||||
formsemestre.description.from_dict(args)
|
||||
db.session.commit()
|
||||
return formsemestre.description.to_dict()
|
||||
@ -868,11 +874,12 @@ def formsemestre_get_photo_ens(formsemestre_id: int):
|
||||
return _image_response(formsemestre.description.photo_ens)
|
||||
|
||||
|
||||
def _image_response(image_data):
|
||||
def _image_response(image_data: bytes):
|
||||
# Guess the mimetype based on the image data
|
||||
mimetype = mimetypes.guess_type("image")[0]
|
||||
|
||||
if not mimetype:
|
||||
try:
|
||||
image = PIL.Image.open(io.BytesIO(image_data))
|
||||
mimetype = image.get_format_mimetype()
|
||||
except PIL.UnidentifiedImageError:
|
||||
# Default to binary stream if mimetype cannot be determined
|
||||
mimetype = "application/octet-stream"
|
||||
|
||||
|
@ -30,9 +30,11 @@ Emmanuel Viennet, 2023
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import io
|
||||
|
||||
from flask import flash, redirect, render_template, url_for
|
||||
from flask import current_app, g, request
|
||||
import PIL
|
||||
|
||||
from app import db, log
|
||||
from app.decorators import (
|
||||
@ -319,6 +321,20 @@ def edit_formsemestre_description(formsemestre_id: int):
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)
|
||||
)
|
||||
try:
|
||||
_ = PIL.Image.open(io.BytesIO(image_data))
|
||||
except PIL.UnidentifiedImageError:
|
||||
flash(
|
||||
f"Image invalide ({field}), doit être une image",
|
||||
"danger",
|
||||
)
|
||||
return redirect(
|
||||
url_for(
|
||||
"notes.edit_formsemestre_description",
|
||||
formsemestre_id=formsemestre.id,
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)
|
||||
)
|
||||
setattr(formsemestre_description, field, image_data)
|
||||
|
||||
db.session.commit()
|
||||
|
@ -122,9 +122,14 @@ def GET(path: str, headers: dict = None, errmsg=None, dept=None, raw=False):
|
||||
if reply.headers.get("Content-Type", None) == "application/json":
|
||||
return reply.json() # decode la reponse JSON
|
||||
if reply.headers.get("Content-Type", None) in [
|
||||
"image/jpg",
|
||||
"image/png",
|
||||
"application/pdf",
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"image/gif",
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/webp",
|
||||
]:
|
||||
retval = {
|
||||
"Content-Type": reply.headers.get("Content-Type", None),
|
||||
@ -132,7 +137,7 @@ def GET(path: str, headers: dict = None, errmsg=None, dept=None, raw=False):
|
||||
}
|
||||
return retval
|
||||
raise APIError(
|
||||
"Unknown returned content {r.headers.get('Content-Type', None} !\n",
|
||||
f"Unknown returned content {reply.headers.get('Content-Type', None)} !\n",
|
||||
status_code=reply.status_code,
|
||||
)
|
||||
|
||||
|
@ -16,6 +16,7 @@ Utilisation :
|
||||
Lancer :
|
||||
pytest tests/api/test_api_formsemestre.py
|
||||
"""
|
||||
import base64
|
||||
import json
|
||||
import requests
|
||||
from types import NoneType
|
||||
@ -813,6 +814,9 @@ def test_formsemestre_description(api_admin_headers):
|
||||
assert r["salle"] == "une salle"
|
||||
assert r["dispositif"] == 1
|
||||
assert r["wip"] is True
|
||||
# La réponse ne contient pas les images, servies à part:
|
||||
assert "image" not in r
|
||||
assert "photo_ens" not in r
|
||||
r = POST(
|
||||
f"/formsemestre/{formsemestre_id}/description/edit",
|
||||
data={
|
||||
@ -828,3 +832,15 @@ def test_formsemestre_description(api_admin_headers):
|
||||
assert r["salle"] == ""
|
||||
assert r["dispositif"] == 0
|
||||
assert r["wip"] is False
|
||||
# Upload image
|
||||
with open("tests/ressources/images/papillon.jpg", "rb") as f:
|
||||
img = f.read()
|
||||
img_base64 = base64.b64encode(img).decode("utf-8")
|
||||
r = POST(
|
||||
f"/formsemestre/{formsemestre_id}/description/edit", data={"image": img_base64}
|
||||
)
|
||||
assert r["wip"] is False
|
||||
r = GET(f"/formsemestre/{formsemestre_id}/description/image", raw=True)
|
||||
assert r.status_code == 200
|
||||
assert r.headers.get("Content-Type") == "image/jpeg"
|
||||
assert r.content == img
|
||||
|
Loading…
Reference in New Issue
Block a user