- OAuth2 Gitea (login/callback/logout) with fallback admin mode
- Session management with signed cookies (itsdangerous, 7 days)
- CSRF protection middleware on all POST/PUT/PATCH/DELETE
- Rate limiting in-memory (60 req/min per IP)
- Issue creation from FlowDeck (POST /api/issues/{owner}/{repo})
- Inline issue editing (PATCH /api/issues/{owner}/{repo}/{issue_id})
- Card detail modal (double-click): description, labels, comments
- Checklists with toggleable items (CRUD endpoints + UI)
- Priority + due date editable on cards
- Webhook receiver (POST /api/webhook) with HMAC-SHA256
- Auto-register/status webhooks for repos
- GiteaClient: create_issue, update_issue, get_comments, webhooks, collaborators
- New DB tables: users, user_tokens, checklists, checklist_items
- CSS: modal, forms, checklists, comments, PR section
79 lines
2.0 KiB
Python
79 lines
2.0 KiB
Python
"""FlowDeck — Kanban léger intégré à Gitea."""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.staticfiles import StaticFiles
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from starlette.middleware.sessions import SessionMiddleware
|
|
|
|
from app.config import settings
|
|
from app.db import init_db
|
|
from app.middleware.csrf import CSRFMiddleware
|
|
from app.routers import dashboard, board, notes, api, auth, webhooks
|
|
from app.services.gitea_client import gitea
|
|
|
|
# ── logging ──
|
|
|
|
logging.basicConfig(
|
|
level=getattr(logging, settings.log_level.upper(), logging.INFO),
|
|
format="%(asctime)s [%(levelname)s] %(message)s",
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# ── app ──
|
|
|
|
app = FastAPI(
|
|
title="FlowDeck",
|
|
version="0.3.0",
|
|
docs_url="/docs" if settings.log_level == "DEBUG" else None,
|
|
redoc_url=None,
|
|
)
|
|
|
|
# ── middleware (order matters) ──
|
|
|
|
# Session (for OAuth2 state)
|
|
app.add_middleware(
|
|
SessionMiddleware,
|
|
secret_key=settings.app_secret_key,
|
|
max_age=3600, # 1 hour for OAuth state
|
|
)
|
|
|
|
# CSRF protection
|
|
app.add_middleware(CSRFMiddleware)
|
|
|
|
# CORS for LAN access
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"],
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
# ── routers ──
|
|
|
|
app.include_router(auth.router)
|
|
app.include_router(dashboard.router)
|
|
app.include_router(board.router)
|
|
app.include_router(notes.router)
|
|
app.include_router(api.router)
|
|
app.include_router(webhooks.router)
|
|
|
|
# ── static ──
|
|
|
|
app.mount("/static", StaticFiles(directory="static"), name="static")
|
|
|
|
|
|
@app.on_event("startup")
|
|
async def startup():
|
|
init_db()
|
|
# Seed admin user for non-OAuth mode
|
|
from app.db import get_conn
|
|
with get_conn() as conn:
|
|
conn.execute(
|
|
"INSERT OR IGNORE INTO users (login, full_name, email, is_admin) VALUES ('admin', 'Admin', '', 1)"
|
|
)
|
|
conn.commit()
|
|
logger.info("FlowDeck v0.3.0 started on port %d", settings.app_port)
|