261 lines
8.4 KiB
Python
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),
|
|
}
|
|
|