79b37d1891
Co-authored-by: Cursor <cursoragent@cursor.com>
114 lines
3.1 KiB
Python
114 lines
3.1 KiB
Python
import os
|
|
import uuid
|
|
from datetime import datetime, timezone
|
|
|
|
from flask import (
|
|
Blueprint,
|
|
current_app,
|
|
flash,
|
|
jsonify,
|
|
redirect,
|
|
render_template,
|
|
request,
|
|
send_from_directory,
|
|
url_for,
|
|
)
|
|
from werkzeug.utils import secure_filename
|
|
|
|
from app import Photo, db
|
|
|
|
bp = Blueprint("main", __name__)
|
|
|
|
|
|
def allowed_file(filename):
|
|
return (
|
|
"." in filename
|
|
and filename.rsplit(".", 1)[1].lower() in current_app.config["ALLOWED_EXTENSIONS"]
|
|
)
|
|
|
|
|
|
@bp.route("/")
|
|
def index():
|
|
photos = Photo.query.order_by(Photo.created_at.desc()).all()
|
|
total_size = sum(p.file_size for p in photos)
|
|
return render_template(
|
|
"index.html",
|
|
photos=photos,
|
|
total_photos=len(photos),
|
|
total_size=total_size,
|
|
max_upload_mb=current_app.config["MAX_CONTENT_LENGTH"] // (1024 * 1024),
|
|
)
|
|
|
|
|
|
@bp.route("/upload", methods=["POST"])
|
|
def upload():
|
|
if "photo" not in request.files:
|
|
flash("Файл не выбран", "error")
|
|
return redirect(url_for("main.index"))
|
|
|
|
file = request.files["photo"]
|
|
if file.filename == "":
|
|
flash("Файл не выбран", "error")
|
|
return redirect(url_for("main.index"))
|
|
|
|
if not allowed_file(file.filename):
|
|
flash("Недопустимый формат. Разрешены: PNG, JPG, GIF, WEBP, BMP", "error")
|
|
return redirect(url_for("main.index"))
|
|
|
|
ext = file.filename.rsplit(".", 1)[1].lower()
|
|
stored_name = f"{uuid.uuid4().hex}.{ext}"
|
|
safe_original = secure_filename(file.filename) or f"photo.{ext}"
|
|
|
|
upload_dir = current_app.config["UPLOAD_FOLDER"]
|
|
filepath = os.path.join(upload_dir, stored_name)
|
|
file.save(filepath)
|
|
file_size = os.path.getsize(filepath)
|
|
|
|
photo = Photo(
|
|
filename=stored_name,
|
|
original_name=safe_original,
|
|
file_size=file_size,
|
|
mime_type=file.content_type or f"image/{ext}",
|
|
created_at=datetime.now(timezone.utc),
|
|
)
|
|
db.session.add(photo)
|
|
db.session.commit()
|
|
|
|
flash("Фото успешно загружено", "success")
|
|
return redirect(url_for("main.index"))
|
|
|
|
|
|
@bp.route("/api/photos")
|
|
def api_photos():
|
|
photos = Photo.query.order_by(Photo.created_at.desc()).all()
|
|
return jsonify(
|
|
[
|
|
{
|
|
"id": p.id,
|
|
"url": p.url,
|
|
"original_name": p.original_name,
|
|
"file_size": p.file_size,
|
|
"size_human": p.size_human,
|
|
"created_at": p.created_at.isoformat(),
|
|
}
|
|
for p in photos
|
|
]
|
|
)
|
|
|
|
|
|
@bp.route("/uploads/<path:filename>")
|
|
def uploaded_file(filename):
|
|
return send_from_directory(current_app.config["UPLOAD_FOLDER"], filename)
|
|
|
|
|
|
@bp.route("/delete/<int:photo_id>", methods=["POST"])
|
|
def delete_photo(photo_id):
|
|
photo = Photo.query.get_or_404(photo_id)
|
|
filepath = os.path.join(current_app.config["UPLOAD_FOLDER"], photo.filename)
|
|
if os.path.exists(filepath):
|
|
os.remove(filepath)
|
|
db.session.delete(photo)
|
|
db.session.commit()
|
|
flash("Фото удалено", "success")
|
|
return redirect(url_for("main.index"))
|