"""Poste.io mail server deployment playbook. Defines the steps required to: 1. Perform initial setup via Playwright automation (configure hostname, create admin account) Tenant servers must have stacks and env templates under /opt/letsbe. """ import uuid from typing import Any from urllib.parse import urlparse from sqlalchemy.ext.asyncio import AsyncSession from app.models.task import Task, TaskStatus # LetsBe standard paths POSTE_STACK_DIR = "/opt/letsbe/stacks/poste" # ============================================================================= # Initial Setup via Playwright # ============================================================================= def build_poste_initial_setup_step( *, base_url: str, admin_email: str, admin_password: str | None = None, ) -> dict[str, Any]: """ Build a PLAYWRIGHT task payload for Poste.io initial setup. This configures the mail server hostname and creates the admin account on a fresh Poste.io installation. Args: base_url: The base URL for Poste.io (e.g., "https://mail.example.com") admin_email: Email address for the admin account (e.g., admin@example.com) admin_password: Password for the admin account (auto-generated if None) Returns: Task payload dict with type="PLAYWRIGHT" """ # Extract domain from URL for allowlist parsed = urlparse(base_url) allowed_domain = parsed.netloc # e.g., "mail.example.com" inputs: dict[str, Any] = { "base_url": base_url, "admin_email": admin_email, } # Only include password if provided - scenario will auto-generate if missing if admin_password: inputs["admin_password"] = admin_password return { "scenario": "poste_initial_setup", "inputs": inputs, "options": { "allowed_domains": [allowed_domain], }, "timeout": 120, } async def create_poste_initial_setup_task( *, db: AsyncSession, tenant_id: uuid.UUID, agent_id: uuid.UUID, base_url: str, admin_email: str, admin_password: str | None = None, ) -> Task: """ Create and persist a PLAYWRIGHT task for Poste.io initial setup. Args: db: Async database session tenant_id: UUID of the tenant agent_id: UUID of the agent to assign the task to base_url: The base URL for Poste.io admin_email: Email address for the admin account admin_password: Password for admin (auto-generated if None) Returns: The created Task object with type="PLAYWRIGHT" """ payload = build_poste_initial_setup_step( base_url=base_url, admin_email=admin_email, admin_password=admin_password, ) task = Task( tenant_id=tenant_id, agent_id=agent_id, type="PLAYWRIGHT", payload=payload, status=TaskStatus.PENDING.value, ) db.add(task) await db.commit() await db.refresh(task) return task