domain migration

This commit is contained in:
debu-2 2026-10-04 14:40:06 +05:30
parent 192b810eb4
commit c04a6ce6fe
26 changed files with 777 additions and 125 deletions

View file

@ -15,6 +15,8 @@ from app.config import get_settings
from app.database import get_postgres_session
from app.models import Account
from app.schemas import AccountRegister, AccountRead, AuthResponse, LoginRequest
from app.services.domain_policy import assert_company_domain_allowed
from app.services.domain_provisioning import account_is_domain_owner
from app.services.domain_provisioning import (
get_domain_by_name,
provision_mail_domain,
@ -50,7 +52,7 @@ def validate_password(value: str) -> None:
def build_email(payload: AccountRegister) -> tuple[str, str | None]:
domain = "getall.help"
domain = settings.platform_domain
company_domain = None
if payload.account_type == "company":
@ -59,12 +61,16 @@ def build_email(payload: AccountRegister) -> tuple[str, str | None]:
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Company domain is required for company accounts.",
)
domain = payload.company_domain.strip().lower().removeprefix("@")
if not domain_pattern.fullmatch(domain):
try:
domain = assert_company_domain_allowed(
payload.company_domain,
settings.platform_domain,
)
except ValueError as error:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Enter a valid company domain, such as example.com.",
)
detail=str(error),
) from error
company_domain = domain
email = f"{payload.email_name.lower()}@{domain}"
@ -88,6 +94,21 @@ def create_access_token(account: Account) -> str:
)
async def account_read(
session: AsyncSession,
account: Account,
) -> AccountRead:
is_owner = await account_is_domain_owner(
session,
account.id,
account.company_domain,
)
return AccountRead.model_validate(
account,
update={"is_domain_owner": is_owner},
)
async def get_current_account(
credentials: HTTPAuthorizationCredentials | None = Depends(bearer_scheme),
session: AsyncSession = Depends(get_postgres_session),
@ -180,7 +201,7 @@ async def register(
await session.refresh(account)
return AuthResponse(
access_token=create_access_token(account),
account=AccountRead.model_validate(account),
account=await account_read(session, account),
)
@ -203,10 +224,13 @@ async def login(
)
return AuthResponse(
access_token=create_access_token(account),
account=AccountRead.model_validate(account),
account=await account_read(session, account),
)
@router.get("/me", response_model=AccountRead)
async def get_me(account: Account = Depends(get_current_account)) -> Account:
return account
async def get_me(
account: Account = Depends(get_current_account),
session: AsyncSession = Depends(get_postgres_session),
) -> AccountRead:
return await account_read(session, account)

View file

@ -18,9 +18,11 @@ from app.schemas import (
SmtpCredentialRead,
)
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 (
activate_company_domain,
create_smtp_credential,
ensure_ownership_dns_record,
ensure_platform_domain,
get_account_company_domain,
provision_mail_domain,
@ -102,12 +104,14 @@ 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,
)
verified = all(check["verified"] for check in checks)
if verified:
@ -151,19 +155,16 @@ async def register_company_domain(
) -> MailDomain:
settings = get_settings()
try:
normalized = validate_domain(payload.domain_name)
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
if normalized == settings.platform_domain:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Use the platform domain endpoint for getall.help.",
)
existing = await session.scalar(
select(MailDomain).where(MailDomain.domain_name == normalized)
)