[pricelist] Use new image controller

This commit is contained in:
Ferdinand Thiessen 2021-11-15 16:34:35 +01:00
parent a6fe921920
commit a43441e0c5
5 changed files with 25 additions and 103 deletions

View File

@ -2,10 +2,11 @@
from flask import Blueprint, jsonify, request, current_app from flask import Blueprint, jsonify, request, current_app
from werkzeug.local import LocalProxy from werkzeug.local import LocalProxy
from werkzeug.exceptions import BadRequest, Forbidden, Unauthorized from werkzeug.exceptions import BadRequest, Forbidden, NotFound, Unauthorized
from flaschengeist import logger from flaschengeist import logger
from flaschengeist.controller import userController from flaschengeist.controller import userController
from flaschengeist.controller.imageController import send_image, send_thumbnail
from flaschengeist.plugins import Plugin from flaschengeist.plugins import Plugin
from flaschengeist.utils.decorators import login_required, extract_session from flaschengeist.utils.decorators import login_required, extract_session
from flaschengeist.utils.HTTP import no_content from flaschengeist.utils.HTTP import no_content
@ -709,7 +710,7 @@ def get_priclist_setting(userid, current_session):
return no_content() return no_content()
@PriceListPlugin.blueprint.route("/drinks/<int:identifier>/picture", methods=["POST", "GET", "DELETE"]) @PriceListPlugin.blueprint.route("/drinks/<int:identifier>/picture", methods=["POST" "DELETE"])
@login_required(permission=permissions.EDIT) @login_required(permission=permissions.EDIT)
def set_picture(identifier, current_session): def set_picture(identifier, current_session):
"""Get, Create, Delete Drink Picture """Get, Create, Delete Drink Picture
@ -731,25 +732,24 @@ def set_picture(identifier, current_session):
file = request.files.get("file") file = request.files.get("file")
if file: if file:
picture = models._Picture() return jsonify(pricelist_controller.save_drink_picture(identifier, file))
picture.mimetype = file.content_type
picture.binary = bytearray(file.stream.read())
return jsonify(pricelist_controller.save_drink_picture(identifier, picture))
else: else:
raise BadRequest raise BadRequest
@PriceListPlugin.blueprint.route("/picture/<identifier>", methods=["GET"]) @PriceListPlugin.blueprint.route("/drinks/<int:identifier>/picture", methods=["GET"])
def _get_picture(identifier): def _get_picture(identifier):
"""Get Picture """Get Picture
Args: Args:
identifier: Identifier of Picture identifier: Identifier of Drink
Returns: Returns:
Picture or HTTP-error Picture or HTTP-error
""" """
if request.method == "GET": drink = pricelist_controller.get_drink(identifier)
size = request.args.get("size") if drink.has_image:
response = pricelist_controller.get_drink_picture(identifier, size) if request.args.get("thumbnail"):
return response.make_conditional(request) return send_thumbnail(image=drink.image_)
return send_image(image=drink.image_)
raise NotFound

View File

@ -1,7 +1,7 @@
from __future__ import annotations # TODO: Remove if python requirement is >= 3.10 from __future__ import annotations # TODO: Remove if python requirement is >= 3.10
from flaschengeist.database import db from flaschengeist.database import db
from flaschengeist.models import ModelSerializeMixin from flaschengeist.models.image import Image
from typing import Optional from typing import Optional
@ -150,11 +150,14 @@ class Drink(db.Model, ModelSerializeMixin):
volume: Optional[float] = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False)) volume: Optional[float] = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False))
cost_per_volume: Optional[float] = db.Column(db.Numeric(precision=5, scale=3, asdecimal=False)) cost_per_volume: Optional[float] = db.Column(db.Numeric(precision=5, scale=3, asdecimal=False))
cost_per_package: Optional[float] = db.Column(db.Numeric(precision=5, scale=3, asdecimal=False)) cost_per_package: Optional[float] = db.Column(db.Numeric(precision=5, scale=3, asdecimal=False))
has_image: bool = False
uuid: str = db.Column(db.String(36)) uuid: str = db.Column(db.String(36))
receipt: Optional[list[str]] = db.Column(db.PickleType(protocol=4)) receipt: Optional[list[str]] = db.Column(db.PickleType(protocol=4))
_type_id = db.Column("type_id", db.Integer, db.ForeignKey("drink_type.id")) _image_id = db.Column("image_id", Serial, db.ForeignKey("image.id"))
image_: Image = db.relationship("Image", cascade="all, delete", foreign_keys=[_image_id])
tags: Optional[list[Tag]] = db.relationship("Tag", secondary=drink_tag_association, cascade="save-update, merge") tags: Optional[list[Tag]] = db.relationship("Tag", secondary=drink_tag_association, cascade="save-update, merge")
type: Optional[DrinkType] = db.relationship("DrinkType", foreign_keys=[_type_id]) type: Optional[DrinkType] = db.relationship("DrinkType", foreign_keys=[_type_id])
@ -166,9 +169,6 @@ class Drink(db.Model, ModelSerializeMixin):
def __repr__(self): def __repr__(self):
return f"Drink({self.id},{self.name},{self.volumes})" return f"Drink({self.id},{self.name},{self.volumes})"
@property
class _Picture: def has_image(self):
"""Wrapper class for pictures binaries""" return self.image_ is not None
mimetype = ""
binary = bytearray()

View File

@ -5,12 +5,12 @@ from uuid import uuid4
from flaschengeist import logger from flaschengeist import logger
from flaschengeist.config import config from flaschengeist.config import config
from flaschengeist.database import db from flaschengeist.database import db
from flaschengeist.utils.picture import save_picture, get_picture, delete_picture
from flaschengeist.utils.decorators import extract_session from flaschengeist.utils.decorators import extract_session
from .models import Drink, DrinkPrice, Ingredient, Tag, DrinkType, DrinkPriceVolume, DrinkIngredient, ExtraIngredient from .models import Drink, DrinkPrice, Ingredient, Tag, DrinkType, DrinkPriceVolume, DrinkIngredient, ExtraIngredient
from .permissions import EDIT_VOLUME, EDIT_PRICE, EDIT_INGREDIENTS_DRINK from .permissions import EDIT_VOLUME, EDIT_PRICE, EDIT_INGREDIENTS_DRINK
import flaschengeist.controller.imageController as image_controller
def update(): def update():
db.session.commit() db.session.commit()
@ -333,9 +333,6 @@ def set_volumes(volumes):
def delete_drink(identifier): def delete_drink(identifier):
drink = get_drink(identifier) drink = get_drink(identifier)
if drink.uuid:
path = config["pricelist"]["path"]
delete_picture(f"{path}/{drink.uuid}")
db.session.delete(drink) db.session.delete(drink)
db.session.commit() db.session.commit()
@ -534,33 +531,13 @@ def delete_extra_ingredient(identifier):
def save_drink_picture(identifier, file): def save_drink_picture(identifier, file):
drink = get_drink(identifier) drink = get_drink(identifier)
old_uuid = None drink.image = image_controller.upload_image(file)
if drink.uuid:
old_uuid = drink.uuid
drink.uuid = str(uuid4())
db.session.commit() db.session.commit()
path = config["pricelist"]["path"]
save_picture(file, f"{path}/{drink.uuid}")
if old_uuid:
delete_picture(f"{path}/{old_uuid}")
return drink return drink
def get_drink_picture(identifier, size=None):
path = config["pricelist"]["path"]
drink = None
if isinstance(identifier, int):
drink = get_drink(identifier)
if isinstance(identifier, str):
drink = Drink.query.filter(Drink.uuid == identifier).one_or_none()
if drink:
return get_picture(f"{path}/{drink.uuid}", size)
raise FileNotFoundError
def delete_drink_picture(identifier): def delete_drink_picture(identifier):
drink = get_drink(identifier) drink = get_drink(identifier)
if drink.uuid: drink.image = None
delete_picture(f"{config['pricelist']['path']}/{drink.uuid}") db.session.commit()
drink.uuid = None return drink
db.session.commit()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

View File

@ -1,55 +0,0 @@
import os, sys, shutil, io
from PIL import Image
from flask import Response
from werkzeug.exceptions import BadRequest
from ..utils.HTTP import no_content
thumbnail_sizes = ((32, 32), (64, 64), (128, 128), (256, 256), (512, 512))
def save_picture(picture, path):
if not picture.mimetype.startswith("image/"):
raise BadRequest
os.makedirs(path, exist_ok=True)
file_type = picture.mimetype.replace("image/", "")
filename = f"{path}/drink"
with open(f"{filename}.{file_type}", "wb") as file:
file.write(picture.binary)
image = Image.open(f"{filename}.{file_type}")
if file_type != "png":
image.save(f"{filename}.png", "PNG")
os.remove(f"{filename}.{file_type}")
for thumbnail_size in thumbnail_sizes:
work_image = image.copy()
work_image.thumbnail(thumbnail_size)
work_image.save(f"{filename}-{thumbnail_size[0]}.png", "PNG")
def get_picture(path, size=None):
try:
if size:
if os.path.isfile(f"{path}/drink-{size}.png"):
with open(f"{path}/drink-{size}.png", "rb") as file:
image = file.read()
else:
_image = Image.open(f"{path}/drink.png")
_image.thumbnail((int(size), int(size)))
with io.BytesIO() as file:
_image.save(file, format="PNG")
image = file.getvalue()
else:
with open(f"{path}/drink.png", "rb") as file:
image = file.read()
response = Response(image, mimetype="image/png")
response.add_etag()
return response
except:
raise FileNotFoundError
def delete_picture(path):
try:
shutil.rmtree(path)
except FileNotFoundError:
pass