morozovka-portal/app/main.py

100 lines
3.2 KiB
Python

from flask import Flask, jsonify, redirect, url_for, session, render_template
from .db import engine
from . import config
from .helpers import register_filters
from .models import UserSession, GlobalStatus, UserOnboarding
from sqlmodel import Session, select
from .modules import (
auth_routes,
notifications_routes,
schedule_routes,
projects_routes,
workshops_routes,
files_routes,
admin_routes,
gitea_routes,
feed_routes,
onboarding_routes,
dashboard_routes,
)
app = Flask(__name__)
app.secret_key = config.WEB_SECRET
app.config['UPLOAD_FOLDER'] = '/var/lib/gitea/portal-files'
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024
with app.app_context():
# Схему создаёт Alembic. Seed базового GlobalStatus — если пусто.
try:
with Session(engine) as db_session:
if not db_session.exec(select(GlobalStatus)).first():
db_session.add(GlobalStatus(status="free", message="Вне расписания"))
db_session.commit()
except Exception as e:
print(f"[main] seed GlobalStatus skipped: {e}", flush=True)
@app.before_request
def validate_session():
if "session_id" in session:
with Session(engine) as db_session:
db_sess = db_session.exec(
select(UserSession).where(UserSession.session_token == session["session_id"])
).first()
if not db_sess:
session.clear()
return redirect(url_for("login"))
register_filters(app)
auth_routes.register(app)
notifications_routes.register(app)
schedule_routes.register(app)
projects_routes.register(app)
workshops_routes.register(app)
files_routes.register(app)
admin_routes.register(app)
gitea_routes.register(app)
feed_routes.register(app)
onboarding_routes.register(app)
dashboard_routes.register(app)
@app.route("/healthz")
def healthz():
try:
from sqlalchemy import text
from .llm_assistant import is_enabled as llm_is_enabled
with engine.connect() as conn:
conn.execute(text("SELECT 1"))
return jsonify({"status": "ok", "db": "ok",
"llm": "enabled" if llm_is_enabled() else "disabled"})
except Exception as e:
return jsonify({"status": "error", "db": str(e)}), 503
@app.route("/")
def index():
user_id = session.get("user_id")
onboarding_completed = False
if user_id:
try:
with Session(engine) as s:
ob = s.exec(select(UserOnboarding).where(UserOnboarding.user_id == user_id)).first()
onboarding_completed = bool(ob and ob.completed_at)
except Exception:
pass
return render_template("index.html", onboarding_completed=onboarding_completed)
@app.route("/api/public-status")
def api_public_status():
with Session(engine) as s:
gs = s.exec(select(GlobalStatus)).first()
if not gs:
return jsonify({"status": "free", "delay_minutes": 0, "message": None})
return jsonify({"status": gs.status, "delay_minutes": gs.delay_minutes or 0,
"message": gs.message,
"updated_at": gs.updated_at.isoformat() if gs.updated_at else None})