feat(share,permissions): partage de page par groupes (page_shares)
FlowDeck CI / lint (push) Failing after 1m10s
FlowDeck CI / test (push) Successful in 9m55s
FlowDeck CI / docker (push) Successful in 1m11s

- app/db.py: ajout colonne shared_with_group_id (FK user_groups, migration
  backfill v5.x) dans page_shares
- app/routers/sharing.py: POST /api/pages/{id}/share accepte group_id
  (upsert, verif FK groupe), GET /shares expose kind/group_name, synchro
  bidirectionnelle avec page_permissions (mirror grant/revoke) pour que
  PermissionManager donne un acces effectif (view/comment/edit) aux membres
  du groupe; PUT/DELETE gardent le miroir a jour
- app/routers/board.py, library.py: received/made incluent les partages via
  groupes (JOIN group_members)
- app/templates/_page_editor_content.html, _page_editor_scripts.html:
  dialogue Share — invite groups (fetch /api/v2/groups, filtre deja partages),
  pickInviteGroup, shareInvite(group_id), rendu accessList avec avatar groupe
- tests/test_share_groups.py: 10 tests (CRUD groupe, kind, miroir ACL)

Chore: inclut evolutions v6.4.0 deja en working copy (webhooks prod,
migrations, sync, config/main) pour garder l'arbre coherent.
This commit is contained in:
2026-09-21 06:38:02 -04:00
parent 95bc861cdb
commit ce0d561ade
13 changed files with 774 additions and 85 deletions
+19
View File
@@ -904,6 +904,25 @@ def _migration_v630_api_v2(conn: sqlite3.Connection) -> None:
conn.execute("CREATE INDEX IF NOT EXISTS idx_idemp_user ON idempotency_keys(user_id, created_at)")
@register(21, "v6.4.0: webhooks prod — event, retry ledger")
def _migration_v640_webhooks_prod(conn: sqlite3.Connection) -> None:
"""v6.4.0 — Webhooks v2 production.
``webhook_deliveries`` gains ``event`` (which event was delivered) and
``next_retry_at`` (epoch seconds; picked up by the retry scheduler).
New statuses: ``retrying`` (a later attempt is scheduled) and
``superseded`` (a retry row replaced this attempt).
"""
_cols = {r[1] for r in conn.execute("PRAGMA table_info(webhook_deliveries)").fetchall()}
if "event" not in _cols:
conn.execute("ALTER TABLE webhook_deliveries ADD COLUMN event TEXT NOT NULL DEFAULT ''")
if "next_retry_at" not in _cols:
conn.execute("ALTER TABLE webhook_deliveries ADD COLUMN next_retry_at REAL")
conn.execute(
"CREATE INDEX IF NOT EXISTS idx_wd_retry ON webhook_deliveries(status, next_retry_at)"
)
@register(17, "v6.0.0: sync_version columns")
def _migration_sync_version_columns(conn: sqlite3.Connection) -> None:
"""v6.0.0 — optimistic-concurrency version counters for offline sync.