Add support for use singe pic on post
This commit is contained in:
@@ -10,20 +10,25 @@ from functools import wraps
|
||||
from pathlib import Path
|
||||
from secrets import token_urlsafe
|
||||
from hashlib import sha256
|
||||
from uuid import uuid4
|
||||
|
||||
from flask import Flask, abort, flash, g, redirect, render_template, request, session, url_for
|
||||
from flask import Flask, abort, flash, g, redirect, render_template, request, send_from_directory, session, url_for
|
||||
from flask_wtf.csrf import CSRFProtect
|
||||
from PIL import Image, ImageOps, UnidentifiedImageError
|
||||
import pyotp
|
||||
import qrcode
|
||||
from werkzeug.security import check_password_hash, generate_password_hash
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
DATABASE = Path(os.environ.get("DATABASE_PATH", BASE_DIR / "data" / "eternity.db"))
|
||||
UPLOAD_FOLDER = Path(os.environ.get("UPLOAD_FOLDER", BASE_DIR / "data" / "uploads"))
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.update(
|
||||
SECRET_KEY=os.environ.get("SECRET_KEY", "change-this-secret-before-production"),
|
||||
DATABASE=DATABASE,
|
||||
UPLOAD_FOLDER=UPLOAD_FOLDER,
|
||||
MAX_CONTENT_LENGTH=8 * 1024 * 1024,
|
||||
MAIL_HOST=os.environ.get("MAIL_HOST"),
|
||||
MAIL_PORT=int(os.environ.get("MAIL_PORT", "587")),
|
||||
MAIL_USERNAME=os.environ.get("MAIL_USERNAME"),
|
||||
@@ -71,6 +76,7 @@ def init_db():
|
||||
excerpt TEXT NOT NULL,
|
||||
body TEXT NOT NULL,
|
||||
category TEXT NOT NULL,
|
||||
image_filename TEXT,
|
||||
author_id INTEGER NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
@@ -95,9 +101,12 @@ def init_db():
|
||||
"mfa_enabled": "ALTER TABLE users ADD COLUMN mfa_enabled INTEGER NOT NULL DEFAULT 0",
|
||||
"email": "ALTER TABLE users ADD COLUMN email TEXT",
|
||||
}
|
||||
post_columns = {row["name"] for row in db.execute("PRAGMA table_info(posts)")}
|
||||
for column, statement in migrations.items():
|
||||
if column not in user_columns:
|
||||
db.execute(statement)
|
||||
if "image_filename" not in post_columns:
|
||||
db.execute("ALTER TABLE posts ADD COLUMN image_filename TEXT")
|
||||
db.execute("CREATE UNIQUE INDEX IF NOT EXISTS users_email_unique ON users(email)")
|
||||
|
||||
# Preserve access for accounts created before approvals were introduced.
|
||||
@@ -159,6 +168,27 @@ def post_from_request(post_id=None):
|
||||
return title, unique_slug(title, post_id), excerpt, body, category, now
|
||||
|
||||
|
||||
def save_post_image():
|
||||
image_file = request.files.get("image")
|
||||
if image_file is None or not image_file.filename:
|
||||
return None
|
||||
try:
|
||||
image = Image.open(image_file.stream)
|
||||
image.verify()
|
||||
source_format = image.format
|
||||
image_file.stream.seek(0)
|
||||
image = ImageOps.exif_transpose(Image.open(image_file.stream)).convert("RGB")
|
||||
except (UnidentifiedImageError, OSError, SyntaxError) as error:
|
||||
raise ValueError("Upload a valid JPEG, PNG, or WebP image.") from error
|
||||
if source_format not in {"JPEG", "PNG", "WEBP"}:
|
||||
raise ValueError("Upload a JPEG, PNG, or WebP image.")
|
||||
image.thumbnail((2400, 2400))
|
||||
filename = f"{uuid4().hex}.webp"
|
||||
app.config["UPLOAD_FOLDER"].mkdir(parents=True, exist_ok=True)
|
||||
image.save(app.config["UPLOAD_FOLDER"] / filename, "WEBP", quality=88, method=6)
|
||||
return filename
|
||||
|
||||
|
||||
def valid_email(email):
|
||||
return re.fullmatch(r"[^\s@]+@[^\s@]+\.[^\s@]+", email) is not None
|
||||
|
||||
@@ -222,6 +252,11 @@ def post(slug):
|
||||
return render_template("post.html", post=article)
|
||||
|
||||
|
||||
@app.get("/uploads/<path:filename>")
|
||||
def uploaded_image(filename):
|
||||
return send_from_directory(app.config["UPLOAD_FOLDER"], filename)
|
||||
|
||||
|
||||
@app.route("/register", methods=("GET", "POST"))
|
||||
def register():
|
||||
if request.method == "POST":
|
||||
@@ -423,10 +458,11 @@ def write():
|
||||
if request.method == "POST":
|
||||
try:
|
||||
title, slug, excerpt, body, category, now = post_from_request()
|
||||
image_filename = save_post_image()
|
||||
get_db().execute(
|
||||
"""INSERT INTO posts (title, slug, excerpt, body, category, author_id, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
(title, slug, excerpt, body, category, session["user_id"], now, now),
|
||||
"""INSERT INTO posts (title, slug, excerpt, body, category, image_filename, author_id, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
(title, slug, excerpt, body, category, image_filename, session["user_id"], now, now),
|
||||
)
|
||||
get_db().commit()
|
||||
return redirect(url_for("post", slug=slug))
|
||||
@@ -446,11 +482,14 @@ def edit_post(slug):
|
||||
if request.method == "POST":
|
||||
try:
|
||||
title, new_slug, excerpt, body, category, now = post_from_request(article["id"])
|
||||
image_filename = save_post_image() or article["image_filename"]
|
||||
get_db().execute(
|
||||
"""UPDATE posts SET title=?, slug=?, excerpt=?, body=?, category=?, updated_at=? WHERE id=?""",
|
||||
(title, new_slug, excerpt, body, category, now, article["id"]),
|
||||
"""UPDATE posts SET title=?, slug=?, excerpt=?, body=?, category=?, image_filename=?, updated_at=? WHERE id=?""",
|
||||
(title, new_slug, excerpt, body, category, image_filename, now, article["id"]),
|
||||
)
|
||||
get_db().commit()
|
||||
if image_filename != article["image_filename"] and article["image_filename"]:
|
||||
(app.config["UPLOAD_FOLDER"] / article["image_filename"]).unlink(missing_ok=True)
|
||||
return redirect(url_for("post", slug=new_slug))
|
||||
except ValueError as error:
|
||||
flash(str(error), "error")
|
||||
|
||||
Reference in New Issue
Block a user