style: Remove team management functionality and associated templates for a cleaner codebase
This commit is contained in:
-185
@@ -41,7 +41,6 @@ def set_security_headers(response):
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
INVOICE_UPLOAD_DIR = os.path.join(BASE_DIR, "static", "uploads", "invoices")
|
||||
TEAM_UPLOAD_DIR = os.path.join(BASE_DIR, "static", "uploads", "team")
|
||||
MONGO_URI = os.environ.get("MONGO_URI", "mongodb://localhost:27017")
|
||||
MONGO_DB_NAME = os.environ.get("MONGO_DB_NAME", "Invario_Website")
|
||||
INSTANCE_REPO_URL = os.environ.get("INSTANCE_REPO_URL", "https://github.com/AIIrondev/legendary-octo-garbanzo")
|
||||
@@ -118,30 +117,6 @@ def _save_invoice_pdf(file_obj, invoice_number: str) -> str | None:
|
||||
file_obj.save(target)
|
||||
return f"uploads/invoices/{unique_name}"
|
||||
|
||||
|
||||
def _save_team_photo(file_obj, identifier: str) -> str | None:
|
||||
if not file_obj or not file_obj.filename:
|
||||
return None
|
||||
original_name = secure_filename(file_obj.filename)
|
||||
if not _is_allowed_image_filename(original_name):
|
||||
return None
|
||||
os.makedirs(TEAM_UPLOAD_DIR, exist_ok=True)
|
||||
# If a photo for this identifier already exists, keep the first one and return it.
|
||||
safe_identifier = secure_filename(identifier or "member")
|
||||
try:
|
||||
for existing in sorted(os.listdir(TEAM_UPLOAD_DIR)):
|
||||
if existing.startswith(f"team_{safe_identifier}_"):
|
||||
return f"uploads/team/{existing}"
|
||||
except Exception:
|
||||
# If listing fails for any reason, proceed to save new file.
|
||||
pass
|
||||
extension = os.path.splitext(original_name)[1].lower() or ".jpg"
|
||||
unique_name = f"team_{safe_identifier}_{datetime.utcnow().strftime('%Y%m%d%H%M%S')}{extension}"
|
||||
target = os.path.join(TEAM_UPLOAD_DIR, unique_name)
|
||||
file_obj.save(target)
|
||||
return f"uploads/team/{unique_name}"
|
||||
|
||||
|
||||
def _get_mongo_client() -> MongoClient:
|
||||
global _MONGO_CLIENT
|
||||
if _MONGO_CLIENT is not None:
|
||||
@@ -1504,42 +1479,6 @@ def _sanitize_html(html_content: str, max_length: int = 50000) -> str:
|
||||
return bleach.clean(html_content, tags=allowed_tags, attributes=allowed_attrs, strip=True)
|
||||
|
||||
|
||||
def _get_team_members() -> list:
|
||||
members = []
|
||||
client = None
|
||||
try:
|
||||
client, col = _get_collection("team_members")
|
||||
members = list(col.find().sort([("sort_order", 1), ("created_at", 1)]))
|
||||
except PyMongoError:
|
||||
return []
|
||||
finally:
|
||||
if client:
|
||||
client.close()
|
||||
|
||||
normalized = []
|
||||
for member in members:
|
||||
public_id = str(member.get("_id") or "")
|
||||
sort_raw = member.get("sort_order", 999)
|
||||
try:
|
||||
sort_order = int(sort_raw)
|
||||
except (TypeError, ValueError):
|
||||
sort_order = 999
|
||||
normalized.append(
|
||||
{
|
||||
"id": public_id,
|
||||
"sort_order": sort_order,
|
||||
"name": _sanitize_text(member.get("name") or "", 120),
|
||||
"role": _sanitize_text(member.get("role") or "", 120),
|
||||
"work": _sanitize_text(member.get("work") or "", 220),
|
||||
"bio": _sanitize_text(member.get("bio") or "", 500),
|
||||
"photo": _sanitize_text(member.get("photo") or "", 255),
|
||||
}
|
||||
)
|
||||
|
||||
normalized.sort(key=lambda value: (value.get("sort_order", 999), value.get("name", "")))
|
||||
return normalized
|
||||
|
||||
|
||||
def _validate_username(username: str) -> bool:
|
||||
"""Validate username format: alphanumeric, underscore, dash, 3-30 chars."""
|
||||
if not username or not isinstance(username, str):
|
||||
@@ -1689,12 +1628,6 @@ def inventarsystem():
|
||||
return render_template("inventarsystem.html")
|
||||
|
||||
|
||||
@app.route('/team')
|
||||
def team():
|
||||
team_members = _get_team_members()
|
||||
return render_template("team.html", team_members=team_members)
|
||||
|
||||
|
||||
@app.route('/kontakt')
|
||||
def kontakt():
|
||||
return render_template("kontakt.html")
|
||||
@@ -2581,124 +2514,6 @@ def admin_users():
|
||||
instances_by_owner = _list_instances_grouped_by_owner()
|
||||
return render_template("admin_users.html", users=users, instances_by_owner=instances_by_owner)
|
||||
|
||||
|
||||
@app.route('/admin/team', methods=['GET', 'POST'])
|
||||
@admin_required
|
||||
def admin_team():
|
||||
if request.method == 'POST':
|
||||
action = _sanitize_text(request.form.get("action") or "upsert", 20)
|
||||
member_id = _sanitize_text(request.form.get("member_id") or "", 64)
|
||||
|
||||
client = None
|
||||
try:
|
||||
client, col = _get_collection("team_members")
|
||||
|
||||
if action == "delete":
|
||||
try:
|
||||
result = col.delete_one({"_id": ObjectId(member_id)})
|
||||
except Exception:
|
||||
flash("Ungültige Team-ID.", "error")
|
||||
return redirect(url_for("admin_team"))
|
||||
if result.deleted_count:
|
||||
flash("Teammitglied entfernt.", "success")
|
||||
else:
|
||||
flash("Teammitglied nicht gefunden.", "error")
|
||||
return redirect(url_for("admin_team"))
|
||||
|
||||
name = _sanitize_text(request.form.get("name") or "", 120)
|
||||
role = _sanitize_text(request.form.get("role") or "", 120)
|
||||
work = _sanitize_text(request.form.get("work") or "", 220)
|
||||
bio = _sanitize_text(request.form.get("bio") or "", 500)
|
||||
sort_raw = _sanitize_text(request.form.get("sort_order") or "999", 10)
|
||||
|
||||
try:
|
||||
sort_order = int(sort_raw)
|
||||
except ValueError:
|
||||
sort_order = 999
|
||||
sort_order = max(1, min(sort_order, 999))
|
||||
|
||||
if not name or not role or not work:
|
||||
flash("Bitte Name, Rolle und Arbeit ausfüllen.", "error")
|
||||
return redirect(url_for("admin_team"))
|
||||
|
||||
current = None
|
||||
if member_id:
|
||||
try:
|
||||
current = col.find_one({"_id": ObjectId(member_id)})
|
||||
except Exception:
|
||||
flash("Ungültige Team-ID.", "error")
|
||||
return redirect(url_for("admin_team"))
|
||||
|
||||
photo_identifier = member_id or name[:20]
|
||||
photo_path = _save_team_photo(request.files.get("photo"), photo_identifier)
|
||||
|
||||
if request.files.get("photo") and request.files.get("photo").filename and not photo_path:
|
||||
flash("Foto muss JPG, JPEG, PNG oder WEBP sein.", "error")
|
||||
return redirect(url_for("admin_team"))
|
||||
|
||||
if not photo_path:
|
||||
photo_path = (current or {}).get("photo", "")
|
||||
|
||||
if action == "create":
|
||||
if not photo_path:
|
||||
flash("Bitte ein Foto für das neue Teammitglied hochladen.", "error")
|
||||
return redirect(url_for("admin_team"))
|
||||
col.insert_one(
|
||||
{
|
||||
"name": name,
|
||||
"role": role,
|
||||
"work": work,
|
||||
"bio": bio,
|
||||
"photo": photo_path,
|
||||
"sort_order": sort_order,
|
||||
"created_by": session.get("username") or "admin",
|
||||
"created_at": _utc_now_iso(),
|
||||
"updated_at": _utc_now_iso(),
|
||||
}
|
||||
)
|
||||
flash("Teammitglied hinzugefuegt.", "success")
|
||||
elif action == "update":
|
||||
if not member_id:
|
||||
flash("Team-ID fehlt.", "error")
|
||||
return redirect(url_for("admin_team"))
|
||||
try:
|
||||
result = col.update_one(
|
||||
{"_id": ObjectId(member_id)},
|
||||
{
|
||||
"$set": {
|
||||
"name": name,
|
||||
"role": role,
|
||||
"work": work,
|
||||
"bio": bio,
|
||||
"photo": photo_path,
|
||||
"sort_order": sort_order,
|
||||
"updated_by": session.get("username") or "admin",
|
||||
"updated_at": _utc_now_iso(),
|
||||
}
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
flash("Ungültige Team-ID.", "error")
|
||||
return redirect(url_for("admin_team"))
|
||||
if result.matched_count == 0:
|
||||
flash("Teammitglied nicht gefunden.", "error")
|
||||
return redirect(url_for("admin_team"))
|
||||
flash("Teammitglied aktualisiert.", "success")
|
||||
else:
|
||||
flash("Ungültige Aktion.", "error")
|
||||
return redirect(url_for("admin_team"))
|
||||
except PyMongoError:
|
||||
flash("Teamdaten konnten nicht gespeichert werden.", "error")
|
||||
finally:
|
||||
if client:
|
||||
client.close()
|
||||
|
||||
return redirect(url_for("admin_team"))
|
||||
|
||||
team_members = _get_team_members()
|
||||
return render_template("admin_team.html", team_members=team_members)
|
||||
|
||||
|
||||
@app.route('/admin/chats', methods=['GET', 'POST'])
|
||||
@admin_required
|
||||
def admin_chats():
|
||||
|
||||
Reference in New Issue
Block a user