Files
mnemosyne/mnemosyne/mcp_server/api/serializers.py
Robert Helewka 409da7d109
All checks were successful
CVE Scan & Docker Build / security-scan (push) Successful in 56s
CVE Scan & Docker Build / build-and-push (push) Successful in 3m30s
docs: replace daedalus-service basic auth with per-user DRF tokens
2026-05-22 22:59:59 -04:00

87 lines
2.7 KiB
Python

"""DRF serializers for the ``/mcp_server/api/teams/`` control plane.
These endpoints are the Daedalus → Mnemosyne control plane described
in §7 of ``docs/DAEDALUS_PALLAS_INTEGRATION_v1.md``. They are called
by Daedalus authenticated as the Mnemosyne user the team belongs to
(per-user DRF token).
"""
from __future__ import annotations
from rest_framework import serializers
from ..models import Team
class TeamCreateRequestSerializer(serializers.Serializer):
"""Inbound payload for ``POST /mcp_server/api/teams/``.
``id`` is the Daedalus ``PallasInstance.id`` UUID. It is supplied
by the caller (not generated by Mnemosyne) so the two control
planes share a stable key.
"""
id = serializers.UUIDField()
name = serializers.CharField(max_length=200)
class TeamPublicSerializer(serializers.ModelSerializer):
"""Outbound payload for team reads / updates.
Excludes the JWT — it is surfaced exactly once on create / rotate
and never recoverable after. Include ``workspace_ids`` so Daedalus
can diff its local state against what Mnemosyne actually holds.
"""
workspace_ids = serializers.SerializerMethodField()
class Meta:
model = Team
fields = [
"id",
"name",
"active",
"active_jti",
"created_at",
"updated_at",
"workspace_ids",
]
read_only_fields = fields
def get_workspace_ids(self, obj: Team) -> list[str]:
return list(
obj.workspace_assignments.order_by("workspace_id")
.values_list("workspace_id", flat=True)
)
class TeamWorkspacesUpdateSerializer(serializers.Serializer):
"""Inbound payload for ``PUT /mcp_server/api/teams/{id}/workspaces/``.
The request is an idempotent *replace* — the team's assignment set
after the call equals ``workspace_ids`` exactly. Daedalus is the
source of truth; Mnemosyne mirrors.
"""
workspace_ids = serializers.ListField(
child=serializers.CharField(max_length=64, allow_blank=False),
allow_empty=True,
)
def validate_workspace_ids(self, value: list[str]) -> list[str]:
# De-duplicate while preserving order; strip whitespace. ``unique_together``
# would already reject dupes at the DB layer but failing earlier gives
# the caller a cleaner 400.
seen = set()
out = []
for ws in value:
ws = ws.strip()
if not ws:
raise serializers.ValidationError(
"workspace_ids entries must be non-empty strings."
)
if ws not in seen:
seen.add(ws)
out.append(ws)
return out