Introduce tenant-scoped Space/SpaceMembership with list and detail views. Document markdown-in-Forgejo as content SoR (ADR-0002). Run migrations on container start so app.coulomb.social picks up the new tables.
39 lines
1.2 KiB
Python
39 lines
1.2 KiB
Python
"""Space queries scoped by tenant membership."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from django.db.models import Q, QuerySet
|
|
|
|
from coulomb_social.apps.members.models import Member
|
|
|
|
from .models import Space, SpaceMembership
|
|
|
|
|
|
def spaces_for_member(member: Member | None) -> QuerySet[Space]:
|
|
"""Spaces visible to this member (same tenant, active).
|
|
|
|
Explicit SpaceMembership grants access; if none exist for the tenant yet,
|
|
all active tenant spaces are listed (operator-seeded MVP). Once any
|
|
memberships exist for the tenant, only membership + created_by apply.
|
|
"""
|
|
if member is None:
|
|
return Space.objects.none()
|
|
|
|
qs = Space.objects.filter(tenant_id=member.tenant_id, is_active=True)
|
|
tenant_has_memberships = SpaceMembership.objects.filter(
|
|
space__tenant_id=member.tenant_id
|
|
).exists()
|
|
if not tenant_has_memberships:
|
|
return qs.order_by("title", "slug")
|
|
|
|
return (
|
|
qs.filter(Q(memberships__member=member) | Q(created_by=member))
|
|
.distinct()
|
|
.order_by("title", "slug")
|
|
)
|
|
|
|
|
|
def get_space_for_member(member: Member | None, slug: str) -> Space | None:
|
|
if member is None:
|
|
return None
|
|
return spaces_for_member(member).filter(slug=slug).first()
|