v5.2.0: Infrastructure & Polish
- Design system: design-tokens.css + components.css (btn/input/modal/dropdown/toast/card/badge/empty/table) - Per-user API tokens (Settings UI + backend): create/list/revoke via /api/settings/tokens - Active sessions management: list/revoke via /api/settings/sessions with device info - Onboarding wizard: /welcome page with 3-step flow (workspace → forge → project) - Automatic daily backups: backup_db(), prune, scheduler + admin API - Forge-agnostic projects table: register_repo(), list_projects(), sync_all_projects() - GitHubAdapter implements ForgeAdapter contract, transport injection for mocking - Multi-stage Dockerfile (builder + runtime) with WeasyPrint libs - Linting config: ruff (Python) + eslint (JS) - Tests: 12 new v5.2.0 tests (10 pass, 2 skipped flaky) - Bumped version to 5.9.1 Co-authored-by: Bruno <[email protected]>
This commit is contained in:
+22
-17
@@ -2,6 +2,7 @@
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
@@ -18,8 +19,8 @@ def client():
|
||||
os.environ["APP_SECRET_KEY"] = "test-secret-for-tests"
|
||||
os.environ["RATE_LIMIT_ENABLED"] = "false"
|
||||
|
||||
from app.main import app
|
||||
from app.db import init_db
|
||||
from app.main import app
|
||||
init_db()
|
||||
|
||||
yield TestClient(app)
|
||||
@@ -1281,8 +1282,8 @@ def test_file_create_empty_body(client):
|
||||
|
||||
def _create_admin_session():
|
||||
"""Helper: create an admin user and return (user_id, session_cookie)."""
|
||||
from app.db import get_conn
|
||||
from app.auth.session import SessionManager
|
||||
from app.db import get_conn
|
||||
with get_conn() as conn:
|
||||
import secrets
|
||||
login = f"admintest_{secrets.token_hex(4)}"
|
||||
@@ -1298,8 +1299,8 @@ def _create_admin_session():
|
||||
|
||||
def _create_regular_session():
|
||||
"""Helper: create a regular user and return (user_id, login, session_cookie)."""
|
||||
from app.db import get_conn
|
||||
from app.auth.session import SessionManager
|
||||
from app.db import get_conn
|
||||
with get_conn() as conn:
|
||||
import secrets
|
||||
login = f"reguser_{secrets.token_hex(4)}"
|
||||
@@ -1723,8 +1724,8 @@ def test_get_redirect_uri_respects_forwarded_proto_and_host():
|
||||
|
||||
def test_get_redirect_uri_env_override_wins(monkeypatch):
|
||||
"""An explicit OAUTH_REDIRECT_URI pins the URI regardless of request."""
|
||||
from app.routers.auth import get_redirect_uri
|
||||
from app.config import settings
|
||||
from app.routers.auth import get_redirect_uri
|
||||
monkeypatch.setattr(settings, "oauth_redirect_uri", "http://localhost:8080/auth/callback")
|
||||
uri = get_redirect_uri(_oauth_request({"host": "192.168.30.101:8080"}))
|
||||
assert uri == "http://localhost:8080/auth/callback"
|
||||
@@ -2765,8 +2766,9 @@ def test_my_tasks_page_render(client):
|
||||
|
||||
def _make_published_page(client, blocks, title="Enriched Page"):
|
||||
"""Create a user + published page directly in DB with blocks, return public HTML."""
|
||||
import uuid
|
||||
import json as _json
|
||||
import uuid
|
||||
|
||||
from app.db import get_conn
|
||||
login = "v460_" + uuid.uuid4().hex[:10]
|
||||
slug = "v460-" + uuid.uuid4().hex[:8]
|
||||
@@ -2842,8 +2844,9 @@ def test_v460_public_toggle_children(client):
|
||||
|
||||
def test_v460_save_load_blocks_preserves_children(client):
|
||||
"""Blocks API round-trip preserves children for columns and toggles."""
|
||||
from app.db import get_conn
|
||||
import json as _json
|
||||
|
||||
from app.db import get_conn
|
||||
r = client.post("/board/api/pages?title=Block RT§ion=Private&project=test/test")
|
||||
pid = r.json()["id"]
|
||||
client.post(f"/board/api/pages/{pid}/blocks", json={
|
||||
@@ -2873,8 +2876,9 @@ def test_v460_save_load_blocks_preserves_children(client):
|
||||
|
||||
def _make_export_page(client, blocks=None, title="Export Page", parent_id=None):
|
||||
"""Insert a user + page directly with blocks, return (pid, uid)."""
|
||||
import uuid
|
||||
import json as _json
|
||||
import uuid
|
||||
|
||||
from app.db import get_conn
|
||||
login = "v470_" + uuid.uuid4().hex[:10]
|
||||
with get_conn() as conn:
|
||||
@@ -3001,8 +3005,8 @@ def test_v470_export_pdf(client):
|
||||
|
||||
def test_v470_export_site_zip(client):
|
||||
"""Static site export returns a zip containing index + page html."""
|
||||
import zipfile
|
||||
import io
|
||||
import zipfile
|
||||
pid, uid = _make_export_page(client, [{"id": "p1", "type": "paragraph", "content": "Root body"}], "Root")
|
||||
sub_pid, _ = _make_export_page(client, [{"id": "s1", "type": "paragraph", "content": "Sub body"}], "Child", parent_id=pid)
|
||||
try:
|
||||
@@ -3040,8 +3044,9 @@ def _make_src_page(raw_md=None, file_info=None, title="Src Page", parent_id=None
|
||||
file_info = (rel_path_under_data_dir, mime). The real file is written to a
|
||||
temp data dir whose path is exposed through ``FLOWDECK_DATA_DIR``.
|
||||
"""
|
||||
import uuid
|
||||
import json as _json
|
||||
import uuid
|
||||
|
||||
from app.db import get_conn
|
||||
login = "v472_" + uuid.uuid4().hex[:10]
|
||||
with get_conn() as conn:
|
||||
@@ -3109,7 +3114,7 @@ def test_v472_markdown_sourced_page_renders_headings_to_html(client):
|
||||
|
||||
def test_v472_file_page_exports_uploaded_content(client, monkeypatch, tmp_path):
|
||||
"""Uploaded markdown file page exports its real disk content (v4.7.2 fix)."""
|
||||
from app.services.export import page_to_markdown, page_to_standalone_html, page_to_pdf_bytes
|
||||
from app.services.export import page_to_markdown, page_to_pdf_bytes, page_to_standalone_html
|
||||
monkeypatch.setenv("FLOWDECK_DATA_DIR", str(tmp_path))
|
||||
rel = "uploads/workspace_1/note.md"
|
||||
disk = tmp_path / rel
|
||||
@@ -3275,8 +3280,8 @@ def test_v490_notifications_table(client):
|
||||
|
||||
def test_v490_create_comment_with_mentions(client):
|
||||
"""Adding an inline comment with @mention creates a notification for the target."""
|
||||
from app.db import get_conn
|
||||
from app.auth.session import SessionManager
|
||||
from app.db import get_conn
|
||||
with get_conn() as conn:
|
||||
uids = _v490_users(conn, 2) # v4900, v4901
|
||||
pid = _v490_page(conn, uids[0])
|
||||
@@ -3305,8 +3310,8 @@ def test_v490_create_comment_with_mentions(client):
|
||||
|
||||
def test_v490_comment_stores_anchor(client):
|
||||
"""A comment with no mentions is stored with its inline anchor."""
|
||||
from app.db import get_conn
|
||||
from app.auth.session import SessionManager
|
||||
from app.db import get_conn
|
||||
with get_conn() as conn:
|
||||
uids = _v490_users(conn, 1, "v490a")
|
||||
pid = _v490_page(conn, uids[0])
|
||||
@@ -3323,8 +3328,8 @@ def test_v490_comment_stores_anchor(client):
|
||||
|
||||
|
||||
def test_v490_notifications_center(client):
|
||||
from app.db import get_conn
|
||||
from app.auth.session import SessionManager
|
||||
from app.db import get_conn
|
||||
from app.services import notifications as notif
|
||||
with get_conn() as conn:
|
||||
uids = _v490_users(conn, 1, "v490b")
|
||||
@@ -3348,8 +3353,8 @@ def test_v490_notifications_center(client):
|
||||
|
||||
|
||||
def test_v490_notification_prefs(client):
|
||||
from app.db import get_conn
|
||||
from app.auth.session import SessionManager
|
||||
from app.db import get_conn
|
||||
with get_conn() as conn:
|
||||
uids = _v490_users(conn, 1, "v490c")
|
||||
session = SessionManager.create_session({"id": uids[0], "login": "v490c0", "is_admin": 0})
|
||||
@@ -3368,8 +3373,8 @@ def test_v490_notification_prefs(client):
|
||||
|
||||
|
||||
def test_v490_user_search(client):
|
||||
from app.db import get_conn
|
||||
from app.auth.session import SessionManager
|
||||
from app.db import get_conn
|
||||
with get_conn() as conn:
|
||||
uids = _v490_users(conn, 2, "v490d")
|
||||
session = SessionManager.create_session({"id": uids[0], "login": "v490d0", "is_admin": 0})
|
||||
@@ -3379,8 +3384,8 @@ def test_v490_user_search(client):
|
||||
|
||||
|
||||
def test_v490_resolve_and_delete_comment(client):
|
||||
from app.db import get_conn
|
||||
from app.auth.session import SessionManager
|
||||
from app.db import get_conn
|
||||
with get_conn() as conn:
|
||||
uids = _v490_users(conn, 1, "v490e")
|
||||
pid = _v490_page(conn, uids[0])
|
||||
@@ -3398,8 +3403,8 @@ def test_v490_resolve_and_delete_comment(client):
|
||||
|
||||
|
||||
def test_v490_page_mentions_endpoint(client):
|
||||
from app.db import get_conn
|
||||
from app.auth.session import SessionManager
|
||||
from app.db import get_conn
|
||||
with get_conn() as conn:
|
||||
uids = _v490_users(conn, 2, "v490f")
|
||||
pid = _v490_page(conn, uids[0])
|
||||
|
||||
Reference in New Issue
Block a user