Files
comiaunicaty/backend/app/services/serializers.py

261 lines
8.4 KiB
Python

from __future__ import annotations
from datetime import date, datetime
from typing import Any
from app.models import (
Announcement,
Event,
FileAsset,
Group,
HomeDevice,
HomeProfile,
Member,
MemberDevice,
Message,
Poll,
PollOption,
PollVote,
RemoteServerConnection,
Task,
Thread,
)
def iso(value: datetime | date | None) -> str | None:
if value is None:
return None
return value.isoformat()
def group_dict(group: Group) -> dict[str, Any]:
return {
"id": group.id,
"server_origin": group.server_origin,
"name": group.name,
"description": group.description,
"visibility": group.visibility,
"legacy_channel_status": group.legacy_channel_status,
"transition_deadline": iso(group.transition_deadline),
"created_at": iso(group.created_at),
"updated_at": iso(group.updated_at),
}
def member_dict(member: Member) -> dict[str, Any]:
return {
"id": member.id,
"group_id": member.group_id,
"home_profile_id": member.home_profile_id,
"display_name": member.display_name,
"role": member.role,
"status": member.status,
"joined_at": iso(member.joined_at),
"last_seen_at": iso(member.last_seen_at),
"notification_enabled_at": iso(member.notification_enabled_at),
}
def profile_dict(profile: HomeProfile | None, member: Member | None = None) -> dict[str, Any] | None:
if profile:
return {
"id": profile.id,
"primary_display_name": profile.primary_display_name,
"status": profile.status,
"last_seen_at": iso(profile.last_seen_at),
}
if member:
return {
"id": None,
"primary_display_name": member.display_name,
"status": "membership_only",
"last_seen_at": iso(member.last_seen_at),
}
return None
def announcement_dict(announcement: Announcement, group: Group | None = None) -> dict[str, Any]:
return {
"id": announcement.id,
"group_id": announcement.group_id,
"group_name": group.name if group else None,
"source_type": "local",
"source_server_origin": group.server_origin if group else None,
"author_member_id": announcement.author_member_id,
"title": announcement.title,
"body": announcement.body,
"priority": announcement.priority,
"official": announcement.official,
"requires_ack": announcement.requires_ack,
"created_at": iso(announcement.created_at),
"updated_at": iso(announcement.updated_at),
}
def event_dict(event: Event, group: Group | None = None, rsvp_status: str | None = None) -> dict[str, Any]:
return {
"id": event.id,
"group_id": event.group_id,
"group_name": group.name if group else None,
"source_type": "local",
"source_server_origin": group.server_origin if group else None,
"created_by_member_id": event.created_by_member_id,
"title": event.title,
"description": event.description,
"starts_at": iso(event.starts_at),
"ends_at": iso(event.ends_at),
"location_name": event.location_name,
"location_address": event.location_address,
"rsvp_required": event.rsvp_required,
"rsvp_status": rsvp_status,
"changed_at": iso(event.changed_at),
"created_at": iso(event.created_at),
"updated_at": iso(event.updated_at),
}
def task_dict(task: Task, group: Group | None = None) -> dict[str, Any]:
return {
"id": task.id,
"group_id": task.group_id,
"group_name": group.name if group else None,
"source_type": "local",
"source_server_origin": group.server_origin if group else None,
"created_by_member_id": task.created_by_member_id,
"assigned_to_member_id": task.assigned_to_member_id,
"title": task.title,
"description": task.description,
"due_at": iso(task.due_at),
"status": task.status,
"created_at": iso(task.created_at),
"updated_at": iso(task.updated_at),
}
def poll_dict(poll: Poll, options: list[PollOption], votes: list[PollVote], group: Group | None = None) -> dict[str, Any]:
counts: dict[str, int] = {option.id: 0 for option in options}
for vote in votes:
counts[vote.option_id] = counts.get(vote.option_id, 0) + 1
return {
"id": poll.id,
"group_id": poll.group_id,
"group_name": group.name if group else None,
"source_type": "local",
"source_server_origin": group.server_origin if group else None,
"title": poll.title,
"description": poll.description,
"closes_at": iso(poll.closes_at),
"status": poll.status,
"created_by_member_id": poll.created_by_member_id,
"created_at": iso(poll.created_at),
"options": [{"id": option.id, "label": option.label, "position": option.position, "vote_count": counts.get(option.id, 0)} for option in options],
}
def file_dict(file: FileAsset, group: Group | None = None) -> dict[str, Any]:
return {
"id": file.id,
"group_id": file.group_id,
"group_name": group.name if group else None,
"source_type": "local",
"source_server_origin": group.server_origin if group else None,
"uploaded_by_member_id": file.uploaded_by_member_id,
"filename_original": file.filename_original,
"content_type": file.content_type,
"size_bytes": file.size_bytes,
"visibility": file.visibility,
"description": file.description,
"requires_ack": file.requires_ack,
"created_at": iso(file.created_at),
"download_url": f"/api/files/{file.id}/download",
}
def thread_dict(thread: Thread, messages: list[Message] | None = None, group: Group | None = None) -> dict[str, Any]:
return {
"id": thread.id,
"group_id": thread.group_id,
"group_name": group.name if group else None,
"source_type": "local",
"source_server_origin": group.server_origin if group else None,
"title": thread.title,
"kind": thread.kind,
"created_by_member_id": thread.created_by_member_id,
"created_at": iso(thread.created_at),
"updated_at": iso(thread.updated_at),
"messages": [message_dict(message) for message in messages or []],
}
def message_dict(message: Message) -> dict[str, Any]:
return {
"id": message.id,
"thread_id": message.thread_id,
"author_member_id": message.author_member_id,
"body": message.body,
"created_at": iso(message.created_at),
"edited_at": iso(message.edited_at),
"deleted_at": iso(message.deleted_at),
}
def action_dict(
*,
id: str,
source_type: str,
source_server_origin: str,
source_group_id: str,
source_group_name: str,
type: str,
priority: str,
title: str,
summary: str,
object_type: str,
object_id: str,
due_at: datetime | None = None,
status: str = "open",
) -> dict[str, Any]:
return {
"id": id,
"source_type": source_type,
"source_server_origin": source_server_origin,
"source_group_id": source_group_id,
"source_group_name": source_group_name,
"type": type,
"status": status,
"priority": priority,
"title": title,
"summary": summary,
"object_type": object_type,
"object_id": object_id,
"due_at": iso(due_at),
}
def device_dict(device: HomeDevice | MemberDevice, current_id: str | None = None) -> dict[str, Any]:
return {
"id": device.id,
"label": device.label,
"created_at": iso(device.created_at),
"last_seen_at": iso(device.last_seen_at),
"revoked_at": iso(device.revoked_at),
"trust_level": device.trust_level,
"current": device.id == current_id,
}
def remote_connection_dict(connection: RemoteServerConnection) -> dict[str, Any]:
return {
"id": connection.id,
"server_origin": connection.server_origin,
"server_name": connection.server_name,
"api_base": connection.api_base,
"protocol_version": connection.protocol_version,
"capabilities": connection.capabilities_json,
"status": connection.status,
"last_sync_at": iso(connection.last_sync_at),
"last_error": connection.last_error,
"created_at": iso(connection.created_at),
}