Restructure: Move 43 files into 8 domain packages (backend-lehrer)
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 27s
CI / test-go-edu-search (push) Successful in 40s
CI / test-python-klausur (push) Failing after 2m30s
CI / test-python-agent-core (push) Successful in 28s
CI / test-nodejs-website (push) Successful in 20s

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-25 22:32:45 +02:00
parent 165c493d1e
commit dde45b29db
93 changed files with 9469 additions and 9290 deletions

View File

@@ -0,0 +1,139 @@
"""
Messenger API - Pydantic Models.
Data models for contacts, conversations, messages, and groups.
"""
from typing import List, Optional
from pydantic import BaseModel, Field
# ==========================================
# CONTACT MODELS
# ==========================================
class ContactBase(BaseModel):
"""Basis-Modell fuer Kontakte."""
name: str = Field(..., min_length=1, max_length=200)
email: Optional[str] = None
phone: Optional[str] = None
role: str = Field(default="parent", description="parent, teacher, staff, student")
student_name: Optional[str] = Field(None, description="Name des zugehoerigen Schuelers")
class_name: Optional[str] = Field(None, description="Klasse z.B. 10a")
notes: Optional[str] = None
tags: List[str] = Field(default_factory=list)
matrix_id: Optional[str] = Field(None, description="Matrix-ID z.B. @user:matrix.org")
preferred_channel: str = Field(default="email", description="email, matrix, pwa")
class ContactCreate(ContactBase):
"""Model fuer neuen Kontakt."""
pass
class Contact(ContactBase):
"""Vollstaendiger Kontakt mit ID."""
id: str
created_at: str
updated_at: str
online: bool = False
last_seen: Optional[str] = None
class ContactUpdate(BaseModel):
"""Update-Model fuer Kontakte."""
name: Optional[str] = None
email: Optional[str] = None
phone: Optional[str] = None
role: Optional[str] = None
student_name: Optional[str] = None
class_name: Optional[str] = None
notes: Optional[str] = None
tags: Optional[List[str]] = None
matrix_id: Optional[str] = None
preferred_channel: Optional[str] = None
# ==========================================
# GROUP MODELS
# ==========================================
class GroupBase(BaseModel):
"""Basis-Modell fuer Gruppen."""
name: str = Field(..., min_length=1, max_length=100)
description: Optional[str] = None
group_type: str = Field(default="class", description="class, department, custom")
class GroupCreate(GroupBase):
"""Model fuer neue Gruppe."""
member_ids: List[str] = Field(default_factory=list)
class Group(GroupBase):
"""Vollstaendige Gruppe mit ID."""
id: str
member_ids: List[str] = []
created_at: str
updated_at: str
# ==========================================
# MESSAGE MODELS
# ==========================================
class MessageBase(BaseModel):
"""Basis-Modell fuer Nachrichten."""
content: str = Field(..., min_length=1)
content_type: str = Field(default="text", description="text, file, image")
file_url: Optional[str] = None
send_email: bool = Field(default=False, description="Nachricht auch per Email senden")
class MessageCreate(MessageBase):
"""Model fuer neue Nachricht."""
conversation_id: str
class Message(MessageBase):
"""Vollstaendige Nachricht mit ID."""
id: str
conversation_id: str
sender_id: str # "self" fuer eigene Nachrichten
timestamp: str
read: bool = False
read_at: Optional[str] = None
email_sent: bool = False
email_sent_at: Optional[str] = None
email_error: Optional[str] = None
# ==========================================
# CONVERSATION MODELS
# ==========================================
class ConversationBase(BaseModel):
"""Basis-Modell fuer Konversationen."""
name: Optional[str] = None
is_group: bool = False
class Conversation(ConversationBase):
"""Vollstaendige Konversation mit ID."""
id: str
participant_ids: List[str] = []
group_id: Optional[str] = None
created_at: str
updated_at: str
last_message: Optional[str] = None
last_message_time: Optional[str] = None
unread_count: int = 0
class CSVImportResult(BaseModel):
"""Ergebnis eines CSV-Imports."""
imported: int
skipped: int
errors: List[str]
contacts: List[Contact]