diff --git a/app.py b/app.py index 355bcde..41fdf63 100644 --- a/app.py +++ b/app.py @@ -6,10 +6,8 @@ import mimetypes import sys import platform import psutil -import secrets import hashlib import re -import numpy as np from pillow_heif import register_heif_opener @@ -166,7 +164,6 @@ class Receipt(db.Model): with app.app_context(): db.create_all() - from werkzeug.security import generate_password_hash admin = User.query.filter_by(is_admin=True).first() username = app.config.get("DEFAULT_ADMIN_USERNAME", "admin") @@ -337,14 +334,22 @@ def _receipt_error(message): def rotate_receipt_by_id(receipt_id): receipt = Receipt.query.get_or_404(receipt_id) - filepath = os.path.join(app.config["UPLOAD_FOLDER"], receipt.filename) + old_path = os.path.join(app.config["UPLOAD_FOLDER"], receipt.filename) - if not os.path.exists(filepath): + if not os.path.exists(old_path): raise FileNotFoundError("Plik nie istnieje") - image = Image.open(filepath) + image = Image.open(old_path) rotated = image.rotate(-90, expand=True) - rotated.save(filepath, format="WEBP", quality=100) + + new_filename = generate_new_receipt_filename(receipt.list_id) + new_path = os.path.join(app.config["UPLOAD_FOLDER"], new_filename) + rotated.save(new_path, format="WEBP", quality=100) + + os.remove(old_path) + receipt.filename = new_filename + db.session.commit() + return receipt @@ -360,6 +365,12 @@ def delete_receipt_by_id(receipt_id): return receipt +def generate_new_receipt_filename(list_id): + timestamp = datetime.now().strftime("%Y%m%d_%H%M") + random_part = secrets.token_hex(3) + return f"list_{list_id}_{timestamp}_{random_part}.webp" + + ############# OCR ########################### @@ -623,7 +634,11 @@ def forbidden(e): "errors.html", code=403, title="Brak dostępu", - message="Nie masz uprawnień do wyświetlenia tej strony.", + message=( + e.description + if e.description + else "Nie masz uprawnień do wyświetlenia tej strony." + ), ), 403, ) @@ -775,7 +790,7 @@ def edit_my_list(list_id): abort(404) if l.owner_id != current_user.id: - return redirect_with_flash("Nie masz uprawnień do tej listy", "danger") + abort(403, description="Nie jesteś właścicielem tej listy.") if request.method == "POST": new_title = request.form.get("title", "").strip() @@ -818,6 +833,11 @@ def edit_my_list(list_id): @app.route("/delete_user_list/", methods=["POST"]) @login_required def delete_user_list(list_id): + + l = db.session.get(ShoppingList, list_id) + if l is None or l.owner_id != current_user.id: + abort(403, description="Nie jesteś właścicielem tej listy.") + l = db.session.get(ShoppingList, list_id) if l is None or l.owner_id != current_user.id: abort(403) @@ -1104,6 +1124,10 @@ def all_products(): @login_required def upload_receipt(list_id): + l = db.session.get(ShoppingList, list_id) + if l is None or l.owner_id != current_user.id: + return _receipt_error("Nie masz uprawnień do tej listy.") + if "receipt" not in request.files: return _receipt_error("Brak pliku") @@ -1528,10 +1552,7 @@ def rename_receipt(receipt_id): flash("Plik nie istnieje", "danger") return redirect(request.referrer) - now = datetime.now() - timestamp = now.strftime("%Y%m%d_%H%M") - random_part = secrets.token_hex(3) - new_filename = f"list_{receipt.list_id}_{timestamp}_{random_part}.webp" + new_filename = generate_new_receipt_filename(receipt.list_id) new_path = os.path.join(app.config["UPLOAD_FOLDER"], new_filename) try: @@ -1975,6 +1996,7 @@ def demote_user(user_id): flash(f"Użytkownik {user.username} został zdegradowany.", "success") return redirect(url_for("list_users")) + @app.route("/admin/crop_receipt", methods=["POST"]) @login_required @admin_required @@ -1986,11 +2008,20 @@ def crop_receipt(): return jsonify(success=False, error="Brak danych") receipt = Receipt.query.get_or_404(receipt_id) - filepath = os.path.join(app.config["UPLOAD_FOLDER"], receipt.filename) + old_path = os.path.join(app.config["UPLOAD_FOLDER"], receipt.filename) try: image = Image.open(file).convert("RGB") - image.save(filepath, format="WEBP", quality=100) + new_filename = generate_new_receipt_filename(receipt.list_id) + new_path = os.path.join(app.config["UPLOAD_FOLDER"], new_filename) + image.save(new_path, format="WEBP", quality=100) + + if os.path.exists(old_path): + os.remove(old_path) + + receipt.filename = new_filename + db.session.commit() + return jsonify(success=True) except Exception as e: return jsonify(success=False, error=str(e)) diff --git a/static/js/receipt_crop.js b/static/js/receipt_crop.js index 35a291a..94bf38d 100644 --- a/static/js/receipt_crop.js +++ b/static/js/receipt_crop.js @@ -33,7 +33,6 @@ document.addEventListener("DOMContentLoaded", function () { }; }); - // zapisz przycięty document.getElementById("saveCrop").addEventListener("click", function () { if (!cropper) return; @@ -49,13 +48,14 @@ document.addEventListener("DOMContentLoaded", function () { .then((res) => res.json()) .then((data) => { if (data.success) { - location.reload(); + showToast("Zapisano przycięty paragon", "success"); + setTimeout(() => location.reload(), 1500); } else { - alert("❌ Błąd: " + data.error || "Nieznany"); + showToast("Błąd: " + (data.error || "Nieznany"), "danger"); } }) .catch((err) => { - alert("❌ Błąd sieci"); + showToast("Błąd sieci", "danger"); console.error(err); }); }, "image/webp"); diff --git a/templates/admin/receipts.html b/templates/admin/receipts.html index 0591f3c..9ad5357 100644 --- a/templates/admin/receipts.html +++ b/templates/admin/receipts.html @@ -66,9 +66,10 @@ -