108 lines
4.8 KiB
Python
108 lines
4.8 KiB
Python
"""Онбординг: пошаговый тур по разделам для новых пользователей."""
|
||
from datetime import datetime, timezone
|
||
from flask import render_template, request, redirect, url_for, session, jsonify
|
||
from sqlmodel import Session, select
|
||
from ..db import engine
|
||
from ..models import UserOnboarding
|
||
from ..helpers import login_required
|
||
|
||
|
||
STEPS = [
|
||
{"key": "visited_schedule", "num": 1, "icon": "📅", "title": "Расписание",
|
||
"url": "/schedule",
|
||
"desc": "Календарь занятий, статус Никиты Сергеевича, ассистент. Спроси «Где сейчас?» — ответит."},
|
||
{"key": "visited_projects", "num": 2, "icon": "🗂", "title": "Проекты",
|
||
"url": "/projects",
|
||
"desc": "Каталог проектов команды: карточки, участники, канбан-доски, лента новостей."},
|
||
{"key": "visited_workshops", "num": 3, "icon": "🎓", "title": "Мастер-классы",
|
||
"url": "/workshops",
|
||
"desc": "Пайка, embedded, Linux, творчество. Регистрация на занятия, материалы, посещаемость."},
|
||
{"key": "visited_files", "num": 4, "icon": "📁", "title": "Файлы",
|
||
"url": "/files",
|
||
"desc": "Единое хранилище документов. Загружай PDF, картинки, схемы — коллеги скачают."},
|
||
{"key": "visited_feed", "num": 5, "icon": "📰", "title": "Лента",
|
||
"url": "/feed",
|
||
"desc": "Все новости из проектов и мастер-классов в одном потоке. Поиск и фильтры."},
|
||
{"key": "visited_profile", "num": 6, "icon": "👤", "title": "Профиль",
|
||
"url": "/profile",
|
||
"desc": "Подписки на уведомления, активные сессии, безопасность."},
|
||
]
|
||
|
||
_TOTAL = len(STEPS)
|
||
|
||
|
||
def ensure_onboarding(db_session, user_id):
|
||
"""Создать запись прогресса, если её нет. Вернуть объект."""
|
||
if not user_id:
|
||
return None
|
||
ob = db_session.exec(select(UserOnboarding).where(UserOnboarding.user_id == user_id)).first()
|
||
if not ob:
|
||
ob = UserOnboarding(user_id=user_id)
|
||
db_session.add(ob)
|
||
db_session.commit()
|
||
db_session.refresh(ob)
|
||
return ob
|
||
|
||
|
||
def _progress(ob):
|
||
completed = sum(1 for s in STEPS if getattr(ob, s["key"]))
|
||
return completed, _TOTAL
|
||
|
||
|
||
def register(app):
|
||
|
||
@app.route("/onboarding")
|
||
@login_required
|
||
def onboarding_page():
|
||
user_id = session.get("user_id")
|
||
with Session(engine) as db_session:
|
||
ob = ensure_onboarding(db_session, user_id)
|
||
completed, total = _progress(ob)
|
||
return render_template("onboarding.html", steps=STEPS,
|
||
ob=ob, completed=completed, total=total,
|
||
just_done=request.args.get("done") == "1")
|
||
|
||
@app.route("/onboarding/mark", methods=["POST"])
|
||
@login_required
|
||
def onboarding_mark():
|
||
data = request.get_json(silent=True) or {}
|
||
key = data.get("key")
|
||
value = bool(data.get("value", True))
|
||
if key not in {s["key"] for s in STEPS}:
|
||
return jsonify({"ok": False, "error": "bad_key"}), 400
|
||
user_id = session.get("user_id")
|
||
with Session(engine) as db_session:
|
||
ob = ensure_onboarding(db_session, user_id)
|
||
setattr(ob, key, value)
|
||
all_done = all(getattr(ob, s["key"]) for s in STEPS)
|
||
if all_done and ob.completed_at is None:
|
||
ob.completed_at = datetime.now(timezone.utc)
|
||
elif not all_done:
|
||
ob.completed_at = None
|
||
db_session.add(ob)
|
||
db_session.commit()
|
||
completed, total = _progress(ob)
|
||
is_complete = ob.completed_at is not None
|
||
return jsonify({"ok": True, "completed": completed, "total": total,
|
||
"is_complete": is_complete})
|
||
|
||
@app.route("/onboarding/skip", methods=["POST"])
|
||
@login_required
|
||
def onboarding_skip():
|
||
"""Пропустить тур (не отмечать ничего)."""
|
||
return redirect(url_for("index", skip_tour="1"))
|
||
|
||
@app.route("/onboarding/complete", methods=["POST"])
|
||
@login_required
|
||
def onboarding_complete():
|
||
"""Отметить всё сразу — для тех, кто уже разобрался."""
|
||
user_id = session.get("user_id")
|
||
with Session(engine) as db_session:
|
||
ob = ensure_onboarding(db_session, user_id)
|
||
for s in STEPS:
|
||
setattr(ob, s["key"], True)
|
||
ob.completed_at = datetime.now(timezone.utc)
|
||
db_session.add(ob)
|
||
db_session.commit()
|
||
return redirect(url_for("onboarding_page", done="1"))
|