Files
webmail-client/plugins/webmail_plugin_contacts/webmail_plugin_contacts/schemas.py
T
lukasandClaude Opus 4.8 421b44a8ab Mail mark-all-read + iframe fixes; Contacts detail/selection/groups + resizable panels
Mail:
- New "More" (⋯) menu in the list sorting bar with "Mark all as read": POST
  /threads/mark-read marks every unread thread in the current view (unified /
  folder:<special> / account:<uuid>) as \Seen, pushes + publishes updates.
- Message iframe: no longer shows a spurious vertical scrollbar (display:block,
  getBoundingClientRect+ceil sizing, overflow-y:hidden on the doc) and has
  rounded corners.
- Deep links from Contacts: /mail?compose=1&to= opens a maximized prefilled
  composer; /mail?q= prefills the search box.

Contacts:
- Detail pane shows all populated fields (work subtitle, phones, address, urls,
  nickname, birthday). Company name is used as the display name when there's no
  personal name (existing rows too). Editable "Add notes".
- Selection: checkbox reveals on avatar hover only; Groups/More bulk menus in
  select mode; "N contacts selected" panel; filled yellow VIP star in list +
  detail; pagination bottom bar; Lato pinned on form controls.
- Groups: "+" on the GROUPS header and "Create new" in the group menus (bulk
  add/remove via POST /groups/{id}/add|remove, ownership-guarded).
- Rounded Mail-style list rows; removed the ⋯ button from the search bar;
  Compose→Mail, Find-all-conversations→Mail search; Message button removed;
  delete confirmation; resizable sidebar + list/detail split.

Calendar: the right panel (agenda / search) is now resizable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U72FZiF1W1pb8XxyWBTREA
2026-08-02 21:34:22 +02:00

64 lines
1.4 KiB
Python

"""Request models for the contacts API (SPEC §B.5)."""
from __future__ import annotations
from pydantic import BaseModel
class NameParts(BaseModel):
prefix: str = "" # "Title" in the edit form (Dr, Mr, …)
given: str = ""
middle: str = ""
family: str = ""
suffix: str = ""
class EmailEntry(BaseModel):
value: str
type: str = "personal" # personal | work | other
pref: bool = False
class PhoneEntry(BaseModel):
value: str
type: str = "mobile" # mobile | home | work | other
class UrlEntry(BaseModel):
value: str
type: str = "website"
class AddressEntry(BaseModel):
type: str = "home" # home | work | other
country: str = ""
street: str = ""
postal_code: str = ""
city: str = ""
class ContactIn(BaseModel):
display_name: str = "" # FN; derived from name parts / first email when blank
name_parts: NameParts = NameParts()
nickname: str = ""
org: str = "" # Company
department: str = ""
title: str = "" # Job title
birthday: str | None = None # "YYYY-MM-DD" (full date) or None
emails: list[EmailEntry] = []
default_email: str = ""
phones: list[PhoneEntry] = []
urls: list[UrlEntry] = []
addresses: list[AddressEntry] = []
notes: str = ""
starred: bool = False
group_ids: list[str] = []
class GroupIn(BaseModel):
name: str
class MembersIn(BaseModel):
ids: list[str] = [] # contact ids to add to / remove from a group