Initial commit: Key Ajans portfolio site

This commit is contained in:
kayasamat
2026-08-07 17:46:14 +03:00
commit 91bb52bce4
18 changed files with 1656 additions and 0 deletions
+153
View File
@@ -0,0 +1,153 @@
"""Proje yönetimi: yükleme, listeleme, indirme, silme (yalnızca admin)."""
import mimetypes
import os
import re
import uuid
from flask import (
Blueprint,
abort,
current_app,
flash,
redirect,
render_template,
request,
session,
send_from_directory,
url_for,
)
from werkzeug.utils import secure_filename
import security
from db import UPLOAD_DIR, get_db
project_bp = Blueprint("projects", __name__)
ALLOWED_EXT = {
"png", "jpg", "jpeg", "gif", "webp",
"pdf", "zip", "rar", "7z", "tar", "gz",
"txt", "md", "html", "htm",
"doc", "docx", "ppt", "pptx", "xls", "xlsx",
}
MAX_UPLOAD = 25 * 1024 * 1024
def _is_admin():
return session.get("role") == "admin"
@project_bp.before_request
def _guard():
if request.path.startswith("/admin") and not _is_admin():
abort(403)
@project_bp.get("/admin/projeler")
def admin_panel():
db = get_db()
projects = db.execute(
"SELECT * FROM projects ORDER BY created_at DESC"
).fetchall()
return render_template("admin/projects.html", projects=projects)
@project_bp.post("/admin/projeler")
@security.rate_limited("upload", 12, 900)
def do_upload():
title = security.clean_text(request.form.get("title"), 150)
description = security.clean_multiline(request.form.get("description"), 5000)
tags = security.clean_text(request.form.get("tags"), 300)
link = security.validate_link(request.form.get("link"))
if not title:
flash("Proje başlığı zorunlu.", "error")
return redirect(url_for("projects.admin_panel"))
if link is None:
flash("Bağlantı geçersiz (http/https olmalı).", "error")
return redirect(url_for("projects.admin_panel"))
stored_name = None
orig_name = ""
mime = None
size = None
file = request.files.get("file")
if file and file.filename:
orig = secure_filename(file.filename) or "dosya"
ext = orig.rsplit(".", 1)[-1].lower() if "." in orig else ""
if ext not in ALLOWED_EXT:
flash("Bu dosya türüne izin verilmiyor.", "error")
return redirect(url_for("projects.admin_panel"))
payload = file.read(MAX_UPLOAD + 1)
if len(payload) > MAX_UPLOAD:
flash("Dosya 25 MB sınırını aşıyor.", "error")
return redirect(url_for("projects.admin_panel"))
stored_name = uuid.uuid4().hex + "." + ext
with open(os.path.join(UPLOAD_DIR, stored_name), "wb") as fh:
fh.write(payload)
orig_name = orig
mime = mimetypes.guess_type(orig)[0] or "application/octet-stream"
size = len(payload)
db = get_db()
db.execute(
"""INSERT INTO projects (title, description, tags, link, stored_name,
orig_name, mime, size)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
(title, description, tags, link, stored_name, orig_name, mime, size),
)
db.commit()
flash("Proje yüklendi.", "success")
return redirect(url_for("projects.admin_panel"))
@project_bp.post("/admin/projeler/<int:pid>/sil")
def do_delete(pid):
db = get_db()
row = db.execute("SELECT * FROM projects WHERE id = ?", (pid,)).fetchone()
if row is None:
abort(404)
if row["stored_name"]:
path = os.path.join(UPLOAD_DIR, row["stored_name"])
if os.path.isfile(path):
os.remove(path)
db.execute("DELETE FROM projects WHERE id = ?", (pid,))
db.commit()
flash("Proje kaldırıldı.", "info")
return redirect(url_for("projects.admin_panel"))
# ---------------- herkese açık uçlar ----------------
def _get_public_project(pid):
db = get_db()
return db.execute("SELECT * FROM projects WHERE id = ?", (pid,)).fetchone()
@project_bp.get("/projeler/<int:pid>/indir")
def download(pid):
row = _get_public_project(pid)
if row is None or not row["stored_name"]:
abort(404)
return send_from_directory(
UPLOAD_DIR,
row["stored_name"],
as_attachment=True,
download_name=row["orig_name"] or "proje",
)
@project_bp.get("/projeler/<int:pid>/goster")
def show_file(pid):
row = _get_public_project(pid)
if row is None or not row["stored_name"]:
abort(404)
if not (row["mime"] or "").startswith("image/"):
abort(404)
return send_from_directory(UPLOAD_DIR, row["stored_name"])
def public_projects():
db = get_db()
return db.execute(
"SELECT * FROM projects ORDER BY created_at DESC"
).fetchall()