Add federation/ActivityPub models, contracts, and services

Phase 0+1 of ActivityPub integration:
- 6 ORM models (ActorProfile, APActivity, APFollower, APInboxItem, APAnchor, IPFSPin)
- FederationService protocol + SqlFederationService implementation + stub
- 4 DTOs (ActorProfileDTO, APActivityDTO, APFollowerDTO, APAnchorDTO)
- Registry slot for federation service
- Alembic migration for federation tables
- IPFS async client (httpx-based)
- HTTP Signatures (RSA-2048 sign/verify)
- login_url() now uses AUTH_APP env var for flexible auth routing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-21 15:10:08 +00:00
parent 7abef48cf2
commit 8850a0106a
14 changed files with 1158 additions and 4 deletions

View File

@@ -11,7 +11,7 @@ from shared.config import init_config, config, pretty
from shared.models import KV # ensure shared models imported
# Register all app model classes with SQLAlchemy so cross-domain
# relationship() string references resolve correctly.
for _mod in ("blog.models", "market.models", "cart.models", "events.models"):
for _mod in ("blog.models", "market.models", "cart.models", "events.models", "federation.models"):
try:
__import__(_mod)
except ImportError:

View File

@@ -37,6 +37,10 @@ def events_url(path: str = "/") -> str:
return app_url("events", path)
def federation_url(path: str = "/") -> str:
return app_url("federation", path)
def page_cart_url(page_slug: str, path: str = "/") -> str:
if not path.startswith("/"):
path = "/" + path
@@ -62,6 +66,9 @@ def market_product_url(product_slug: str, suffix: str = "", market_place=None) -
def login_url(next_url: str = "") -> str:
# Auth lives in blog (coop) for now. Set AUTH_APP=federation to switch.
auth_app = os.getenv("AUTH_APP", "coop")
base = app_url(auth_app, "/auth/login/")
if next_url:
return coop_url(f"/auth/login/?next={quote(next_url, safe='')}")
return coop_url("/auth/login/")
return f"{base}?next={quote(next_url, safe='')}"
return base