morozovka-portal/app/modules/dashboard_routes.py

122 lines
5.1 KiB
Python
Raw Permalink 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.

"""Дашборд участника — персональный экран после входа (§3.6 ТЗ)."""
from datetime import datetime, timezone
from flask import render_template, session
from sqlmodel import Session, select
from ..db import engine
from ..models import (
Event, Project, ProjectMember, ProjectTask,
Workshop, WorkshopMaterial, WorkshopRegistration,
Notification,
)
from ..helpers import login_required
from .. import gitea_api
# Приоритеты в порядке важности (0 = самый важный)
_PRIORITY_ORDER = {"critical": 0, "high": 1, "medium": 2, "low": 3}
def register(app):
@app.route("/dashboard")
@login_required
def dashboard():
user_id = session.get("user_id")
now = datetime.now(timezone.utc)
with Session(engine) as db_session:
# ── 1. Ближайшие события (5) ─────────────────────────────
upcoming_events = db_session.exec(
select(Event)
.where(Event.is_public == True)
.where(Event.start_time >= now)
.order_by(Event.start_time)
.limit(5)
).all()
# ── 2. Мои проекты ────────────────────────────────────────
my_projects = db_session.exec(
select(Project, ProjectMember)
.join(ProjectMember, ProjectMember.project_id == Project.id)
.where(ProjectMember.user_id == user_id)
.order_by(Project.created_at.desc())
).all()
# ── 3. Мои задачи (не done, топ-10) ───────────────────────
my_tasks_raw = list(db_session.exec(
select(ProjectTask, Project)
.join(Project, ProjectTask.project_id == Project.id)
.where(ProjectTask.assignee_id == user_id)
.where(ProjectTask.status != "done")
).all())
# Сортируем в Python: по приоритету (critical → low), потом по due_date
my_tasks_raw.sort(key=lambda row: (
_PRIORITY_ORDER.get(row[0].priority, 4),
row[0].due_date or "9999-12-31",
))
my_tasks = my_tasks_raw[:10]
# ── 4. Непрочитанные уведомления (10) ────────────────────
unread = db_session.exec(
select(Notification)
.where(Notification.user_id == user_id)
.where(Notification.is_read == False)
.order_by(Notification.created_at.desc())
.limit(10)
).all()
unread_count = len(unread)
# ── 5. Новые материалы МК (где записан, 5) ───────────────
my_workshop_ids = [
r.workshop_id for r in db_session.exec(
select(WorkshopRegistration)
.where(WorkshopRegistration.user_id == user_id)
.where(WorkshopRegistration.status.in_(("registered", "attended")))
).all()
]
new_materials = []
if my_workshop_ids:
new_materials = db_session.exec(
select(WorkshopMaterial, Workshop)
.join(Workshop, WorkshopMaterial.workshop_id == Workshop.id)
.where(WorkshopMaterial.workshop_id.in_(my_workshop_ids))
.order_by(WorkshopMaterial.created_at.desc())
.limit(5)
).all()
# ── 6. Gitea-коммиты (топ-3 проекта с repo, по 3 коммита) ─
gitea_widget = []
for proj, _member in my_projects[:10]:
repo = proj.gitea_repo or (
gitea_api.extract_repo_from_url(proj.gitea_url) if proj.gitea_url else None
)
if not repo or "/" not in repo:
continue
try:
owner, name = repo.split("/", 1)
commits = gitea_api.get_latest_commits(owner, name, limit=3)
if commits:
gitea_widget.append({
"project_id": proj.id,
"project_title": proj.title,
"commits": commits,
})
except Exception as e:
print(f"[dashboard] gitea {repo}: {e}", flush=True)
if len(gitea_widget) >= 3:
break
return render_template(
"dashboard.html",
upcoming_events=upcoming_events,
my_projects=my_projects,
my_tasks=my_tasks,
unread=unread,
unread_count=unread_count,
new_materials=new_materials,
gitea_widget=gitea_widget,
)