morozovka-portal/app/modules/admin_routes.py

105 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Роуты админки: пользователи, роли, удаление."""
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"))