company flows
This commit is contained in:
parent
c04a6ce6fe
commit
a3a6464a99
15 changed files with 963 additions and 60 deletions
|
|
@ -12,6 +12,7 @@ from app.routers.auth import get_current_account
|
|||
from app.schemas import (
|
||||
DnsVerificationResponse,
|
||||
DomainCreate,
|
||||
DomainNameCreate,
|
||||
MailDomainRead,
|
||||
SmtpCredentialCreate,
|
||||
SmtpCredentialCreated,
|
||||
|
|
@ -20,11 +21,14 @@ from app.schemas import (
|
|||
from app.services.dns_verification import verify_company_dns
|
||||
from app.services.domain_policy import assert_company_domain_allowed
|
||||
from app.services.domain_provisioning import (
|
||||
account_is_domain_owner,
|
||||
activate_company_domain,
|
||||
create_smtp_credential,
|
||||
ensure_ownership_dns_record,
|
||||
ensure_platform_domain,
|
||||
get_account_company_domain,
|
||||
get_owned_domain,
|
||||
list_owned_domains,
|
||||
provision_mail_domain,
|
||||
validate_domain,
|
||||
)
|
||||
|
|
@ -32,6 +36,56 @@ from app.services.domain_provisioning import (
|
|||
router = APIRouter(prefix="/domains", tags=["domains"])
|
||||
|
||||
|
||||
async def require_domain_owner(
|
||||
account: Account,
|
||||
session: AsyncSession,
|
||||
) -> None:
|
||||
if account.account_type != "company":
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Company accounts only.",
|
||||
)
|
||||
if not await account_is_domain_owner(session, account.id, account.company_domain):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Only the domain owner can manage domains.",
|
||||
)
|
||||
|
||||
|
||||
async def verify_owned_domain_dns(
|
||||
session: AsyncSession,
|
||||
domain: MailDomain,
|
||||
) -> DnsVerificationResponse:
|
||||
settings = get_settings()
|
||||
if domain.status == "active":
|
||||
return DnsVerificationResponse(
|
||||
domain=domain.domain_name,
|
||||
status=domain.status,
|
||||
verified=True,
|
||||
checks=[],
|
||||
)
|
||||
|
||||
verification_token = await ensure_ownership_dns_record(session, domain)
|
||||
checks = verify_company_dns(
|
||||
domain_name=domain.domain_name,
|
||||
shared_mail_host=settings.smtp_public_host,
|
||||
dkim_selector=domain.dkim_selector,
|
||||
dkim_public_key=domain.dkim_public_key,
|
||||
platform_spf_include=settings.platform_spf_include,
|
||||
verification_token=verification_token,
|
||||
)
|
||||
verified = all(check["verified"] for check in checks)
|
||||
if verified:
|
||||
await activate_company_domain(session, domain)
|
||||
await session.commit()
|
||||
return DnsVerificationResponse(
|
||||
domain=domain.domain_name,
|
||||
status=domain.status if not verified else "active",
|
||||
verified=verified,
|
||||
checks=checks,
|
||||
)
|
||||
|
||||
|
||||
async def get_domain_or_404(
|
||||
domain_id: UUID,
|
||||
session: AsyncSession,
|
||||
|
|
@ -104,25 +158,86 @@ async def verify_my_company_dns(
|
|||
checks=[],
|
||||
)
|
||||
|
||||
verification_token = await ensure_ownership_dns_record(session, domain)
|
||||
checks = verify_company_dns(
|
||||
domain_name=domain.domain_name,
|
||||
shared_mail_host=settings.smtp_public_host,
|
||||
dkim_selector=domain.dkim_selector,
|
||||
dkim_public_key=domain.dkim_public_key,
|
||||
platform_spf_include=settings.platform_spf_include,
|
||||
verification_token=verification_token,
|
||||
return await verify_owned_domain_dns(session, domain)
|
||||
|
||||
|
||||
@router.get("/me/domains", response_model=list[MailDomainRead])
|
||||
async def list_my_domains(
|
||||
account: Account = Depends(get_current_account),
|
||||
session: AsyncSession = Depends(get_postgres_session),
|
||||
) -> list[MailDomain]:
|
||||
await require_domain_owner(account, session)
|
||||
return await list_owned_domains(session, account.id)
|
||||
|
||||
|
||||
@router.post("/me/domains", response_model=MailDomainRead, status_code=status.HTTP_201_CREATED)
|
||||
async def add_my_domain(
|
||||
payload: DomainNameCreate,
|
||||
account: Account = Depends(get_current_account),
|
||||
session: AsyncSession = Depends(get_postgres_session),
|
||||
) -> MailDomain:
|
||||
settings = get_settings()
|
||||
await require_domain_owner(account, session)
|
||||
try:
|
||||
normalized = assert_company_domain_allowed(
|
||||
payload.domain_name,
|
||||
settings.platform_domain,
|
||||
)
|
||||
except ValueError as error:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=str(error),
|
||||
) from error
|
||||
|
||||
existing = await session.scalar(
|
||||
select(MailDomain).where(MailDomain.domain_name == normalized)
|
||||
)
|
||||
verified = all(check["verified"] for check in checks)
|
||||
if verified:
|
||||
await activate_company_domain(session, domain)
|
||||
await session.commit()
|
||||
return DnsVerificationResponse(
|
||||
domain=domain.domain_name,
|
||||
status=domain.status if not verified else "active",
|
||||
verified=verified,
|
||||
checks=checks,
|
||||
if existing:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT,
|
||||
detail="That domain is already registered.",
|
||||
)
|
||||
|
||||
domain = await provision_mail_domain(
|
||||
session,
|
||||
domain_name=normalized,
|
||||
domain_type="company",
|
||||
account_id=account.id,
|
||||
)
|
||||
await session.commit()
|
||||
return await get_owned_domain(session, domain.id, account.id)
|
||||
|
||||
|
||||
@router.get("/me/domains/{domain_id}", response_model=MailDomainRead)
|
||||
async def get_my_domain(
|
||||
domain_id: UUID,
|
||||
account: Account = Depends(get_current_account),
|
||||
session: AsyncSession = Depends(get_postgres_session),
|
||||
) -> MailDomain:
|
||||
await require_domain_owner(account, session)
|
||||
domain = await get_owned_domain(session, domain_id, account.id)
|
||||
if domain is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Domain not found.",
|
||||
)
|
||||
return domain
|
||||
|
||||
|
||||
@router.post("/me/domains/{domain_id}/verify-dns", response_model=DnsVerificationResponse)
|
||||
async def verify_my_domain_dns(
|
||||
domain_id: UUID,
|
||||
account: Account = Depends(get_current_account),
|
||||
session: AsyncSession = Depends(get_postgres_session),
|
||||
) -> DnsVerificationResponse:
|
||||
await require_domain_owner(account, session)
|
||||
domain = await get_owned_domain(session, domain_id, account.id)
|
||||
if domain is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Domain not found.",
|
||||
)
|
||||
return await verify_owned_domain_dns(session, domain)
|
||||
|
||||
|
||||
@router.get("/platform", response_model=MailDomainRead)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue