company flows

This commit is contained in:
debu-2 2026-10-04 20:01:29 +05:30
parent 6541284a4c
commit cc3f3f3de5
17 changed files with 1960 additions and 66 deletions

View file

@ -0,0 +1,109 @@
"""Distribution group management."""
from __future__ import annotations
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from app.models import Account, MailGroup, MailGroupMember
from app.schemas import MailGroupCreate, MailGroupRead
def _group_read(group: MailGroup) -> MailGroupRead:
return MailGroupRead(
id=group.id,
name=group.name,
email=group.email,
group_type=group.group_type,
member_count=len(group.members),
created_at=group.created_at,
)
async def list_mail_groups(
session: AsyncSession,
company_domain: str,
) -> tuple[list[MailGroupRead], dict[str, int]]:
result = await session.scalars(
select(MailGroup)
.options(selectinload(MailGroup.members))
.where(MailGroup.company_domain == company_domain)
.order_by(MailGroup.created_at.desc())
)
groups = list(result.all())
items = [_group_read(group) for group in groups]
counts = {
"all": len(items),
"distribution": sum(1 for item in items if item.group_type == "distribution"),
"dynamic": sum(1 for item in items if item.group_type == "dynamic"),
}
return items, counts
async def _validate_member_ids(
session: AsyncSession,
company_domain: str,
member_ids: list,
) -> list[Account]:
if not member_ids:
return []
result = await session.scalars(
select(Account).where(
Account.id.in_(member_ids),
Account.company_domain == company_domain,
Account.member_status != "suspended",
)
)
members = list(result.all())
if len(members) != len(set(member_ids)):
raise ValueError("One or more selected members are invalid.")
return members
async def create_mail_group(
session: AsyncSession,
*,
manager: Account,
payload: MailGroupCreate,
) -> MailGroupRead:
company_domain = manager.company_domain
if company_domain is None:
raise ValueError("Company domain is required.")
email = str(payload.email).lower()
if not email.endswith(f"@{company_domain}"):
raise ValueError(f"Group email must use @{company_domain}.")
existing = await session.scalar(
select(MailGroup).where(func.lower(MailGroup.email) == email)
)
if existing:
raise ValueError("That group email address is already in use.")
members = await _validate_member_ids(
session,
company_domain,
payload.member_ids,
)
group = MailGroup(
company_domain=company_domain,
name=payload.name.strip(),
email=email,
group_type=payload.group_type,
created_by_id=manager.id,
)
session.add(group)
await session.flush()
for member in members:
session.add(
MailGroupMember(
group_id=group.id,
account_id=member.id,
)
)
await session.flush()
await session.refresh(group, attribute_names=["members"])
return _group_read(group)