105 lines
5.5 KiB
Python
105 lines
5.5 KiB
Python
"""Роуты админки: пользователи, роли, удаление."""
|
||
from flask import render_template, request, redirect, url_for, session
|
||
from sqlmodel import Session, select
|
||
from ..db import engine
|
||
from ..models import (
|
||
User, Project, PortalFile, ProjectMember, Workshop, WorkshopAssistant,
|
||
UserSession, EventSubscriber, ProjectTask, Notification,
|
||
ProjectPost, WorkshopPost,
|
||
)
|
||
from ..helpers import require_role
|
||
|
||
|
||
def register(app):
|
||
|
||
@app.route("/admin/users")
|
||
@require_role("admin")
|
||
def admin_users():
|
||
q = (request.args.get("q") or "").strip().lower()
|
||
with Session(engine) as db_session:
|
||
users = db_session.exec(select(User).order_by(User.username)).all()
|
||
if q:
|
||
users = [
|
||
u for u in users
|
||
if q in (u.username or "").lower()
|
||
or q in (u.full_name or "").lower()
|
||
or q in (u.email or "").lower()
|
||
]
|
||
return render_template("admin_users.html", users=users, q=q)
|
||
|
||
@app.route("/admin/users/<int:user_id>/role", methods=["POST"])
|
||
@require_role("admin")
|
||
def change_user_role(user_id):
|
||
new_role = request.form.get("role")
|
||
valid = ["admin", "professor", "lead", "member", "student", "guest"]
|
||
if new_role not in valid:
|
||
return "Ошибка", 400
|
||
with Session(engine) as db_session:
|
||
user = db_session.get(User, user_id)
|
||
if user:
|
||
if user.id == session.get("user_id") and new_role != "admin":
|
||
return "Нельзя снять с себя админа", 400
|
||
user.role = new_role
|
||
db_session.add(user)
|
||
db_session.commit()
|
||
return redirect(url_for("admin_users"))
|
||
|
||
@app.route("/admin/users/<int:user_id>/toggle_active", methods=["POST"])
|
||
@require_role("admin")
|
||
def toggle_user_active(user_id):
|
||
"""Блокировка/разблокировка вместо удаления — безопаснее."""
|
||
if user_id == session.get("user_id"):
|
||
return "Нельзя заблокировать себя", 400
|
||
with Session(engine) as db_session:
|
||
user = db_session.get(User, user_id)
|
||
if user:
|
||
user.is_active = not user.is_active
|
||
db_session.add(user)
|
||
db_session.commit()
|
||
return redirect(url_for("admin_users"))
|
||
|
||
@app.route("/admin/users/<int:user_id>/delete", methods=["POST"])
|
||
@require_role("admin")
|
||
def delete_user(user_id):
|
||
if user_id == session.get("user_id"):
|
||
return "Нельзя удалить себя", 400
|
||
with Session(engine) as db_session:
|
||
user = db_session.get(User, user_id)
|
||
if not user:
|
||
return redirect(url_for("admin_users"))
|
||
|
||
# ── Проверки: нельзя удалить, если есть hard-FK зависимости ──
|
||
if db_session.exec(select(Project).where(Project.owner_id == user_id)).all():
|
||
return "У пользователя есть проекты (передайте владение сначала)", 400
|
||
if db_session.exec(select(PortalFile).where(PortalFile.uploaded_by == user_id)).all():
|
||
return "У пользователя есть загруженные файлы", 400
|
||
if db_session.exec(select(Workshop).where(Workshop.lead_id == user_id)).all():
|
||
return "Пользователь ведёт мастер-классы", 400
|
||
# Ниже — FK с NOT NULL, без этих проверок DELETE упадёт
|
||
if db_session.exec(select(ProjectPost).where(ProjectPost.author_id == user_id)).all():
|
||
return "У пользователя есть посты в проектах (удалите/переатрибутируйте сначала)", 400
|
||
if db_session.exec(select(WorkshopPost).where(WorkshopPost.author_id == user_id)).all():
|
||
return "У пользователя есть посты в мастер-классах", 400
|
||
if db_session.exec(select(ProjectTask).where(ProjectTask.created_by == user_id)).all():
|
||
return "Пользователь создавал задачи (сначала переатрибутируйте)", 400
|
||
|
||
# ── Развязываем то, что можно обнулить / удалить каскадно ──
|
||
for pm in db_session.exec(select(ProjectMember).where(ProjectMember.user_id == user_id)).all():
|
||
db_session.delete(pm)
|
||
for wa in db_session.exec(select(WorkshopAssistant).where(WorkshopAssistant.user_id == user_id)).all():
|
||
db_session.delete(wa)
|
||
for ss in db_session.exec(select(UserSession).where(UserSession.user_id == user_id)).all():
|
||
db_session.delete(ss)
|
||
for sub in db_session.exec(select(EventSubscriber).where(EventSubscriber.user_id == user_id)).all():
|
||
sub.user_id = None
|
||
db_session.add(sub)
|
||
for t in db_session.exec(select(ProjectTask).where(ProjectTask.assignee_id == user_id)).all():
|
||
t.assignee_id = None
|
||
db_session.add(t)
|
||
for n in db_session.exec(select(Notification).where(Notification.user_id == user_id)).all():
|
||
db_session.delete(n)
|
||
|
||
db_session.delete(user)
|
||
db_session.commit()
|
||
return redirect(url_for("admin_users"))
|