| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- from sqlalchemy import select
- from sqlalchemy.orm import Session, sessionmaker
- from app.core.identifiers import new_ulid
- from app.domains.catalog.models import Plan, Product, ProductChangeLog, ProductVersion
- from app.domains.catalog.repository import CatalogRepository
- from app.domains.identity.models import AdminRole, AdminUser, AuthSession, H5User
- from app.domains.identity.repository import IdentityRepository
- from app.infrastructure.mysql.core_models import (
- AdminUserRecord,
- AuthSessionRecord,
- H5UserRecord,
- PermissionRecord,
- PlanRecord,
- ProductChangeLogRecord,
- ProductRecord,
- ProductVersionRecord,
- RoleRecord,
- )
- SessionFactory = sessionmaker[Session]
- class SqlAlchemyIdentityRepository(IdentityRepository):
- def __init__(self, session_factory: SessionFactory) -> None:
- self._session_factory = session_factory
- def get_h5_user_by_mobile(self, mobile: str) -> H5User | None:
- with self._session_factory() as session:
- record = session.scalar(select(H5UserRecord).where(H5UserRecord.mobile == mobile))
- return self._to_h5_user(record) if record else None
- def get_h5_user(self, user_id: str) -> H5User | None:
- with self._session_factory() as session:
- record = session.get(H5UserRecord, user_id)
- return self._to_h5_user(record) if record else None
- def list_h5_users(self) -> list[H5User]:
- with self._session_factory() as session:
- records = session.scalars(
- select(H5UserRecord).order_by(H5UserRecord.created_at.desc())
- ).all()
- return [self._to_h5_user(record) for record in records]
- def save_h5_user(self, user: H5User) -> None:
- with self._session_factory() as session:
- session.merge(
- H5UserRecord(
- id=user.id,
- mobile=user.mobile,
- mobile_masked=user.mobile_masked,
- display_name=user.display_name,
- status=user.status,
- created_at=user.created_at,
- )
- )
- session.commit()
- def get_admin_user_by_username(self, username: str) -> AdminUser | None:
- with self._session_factory() as session:
- record = session.scalar(
- select(AdminUserRecord).where(AdminUserRecord.username == username)
- )
- return self._to_admin_user(record) if record else None
- def get_admin_user(self, user_id: str) -> AdminUser | None:
- with self._session_factory() as session:
- record = session.get(AdminUserRecord, user_id)
- return self._to_admin_user(record) if record else None
- def list_admin_users(self) -> list[AdminUser]:
- with self._session_factory() as session:
- records = session.scalars(
- select(AdminUserRecord).order_by(AdminUserRecord.username)
- ).all()
- return [self._to_admin_user(record) for record in records]
- def save_admin_user(self, user: AdminUser) -> None:
- with self._session_factory() as session:
- roles: list[RoleRecord] = []
- for role_code in user.roles:
- role = session.scalar(select(RoleRecord).where(RoleRecord.code == role_code))
- if role is None:
- role = RoleRecord(
- id=new_ulid(),
- code=role_code,
- name=role_code,
- data_scope=user.data_scope,
- status="ACTIVE",
- )
- session.add(role)
- permissions: list[PermissionRecord] = []
- for permission_code in user.permissions:
- permission = session.scalar(
- select(PermissionRecord).where(PermissionRecord.code == permission_code)
- )
- if permission is None:
- resource, _, action = permission_code.partition(":")
- permission = PermissionRecord(
- id=new_ulid(),
- code=permission_code,
- name=permission_code,
- resource=resource,
- action=action or "read",
- )
- session.add(permission)
- permissions.append(permission)
- role.permissions = permissions
- roles.append(role)
- record = session.get(AdminUserRecord, user.id)
- if record is None:
- record = AdminUserRecord(
- id=user.id,
- username=user.username,
- password_hash=user.password_hash,
- display_name=user.display_name,
- status=user.status,
- )
- session.add(record)
- else:
- record.username = user.username
- record.password_hash = user.password_hash
- record.display_name = user.display_name
- record.status = user.status
- record.roles = roles
- session.commit()
- def list_roles(self) -> list[AdminRole]:
- with self._session_factory() as session:
- records = session.scalars(select(RoleRecord).order_by(RoleRecord.code)).all()
- return [
- AdminRole(
- code=record.code,
- name=record.name,
- data_scope=record.data_scope,
- status=record.status,
- permissions=tuple(sorted(permission.code for permission in record.permissions)),
- )
- for record in records
- ]
- def save_role(self, role: AdminRole) -> None:
- with self._session_factory() as session:
- record = session.scalar(select(RoleRecord).where(RoleRecord.code == role.code))
- if record is None:
- raise KeyError(role.code)
- permissions: list[PermissionRecord] = []
- for permission_code in role.permissions:
- permission = session.scalar(
- select(PermissionRecord).where(PermissionRecord.code == permission_code)
- )
- if permission is None:
- resource, _, action = permission_code.partition(":")
- permission = PermissionRecord(
- id=new_ulid(),
- code=permission_code,
- name=permission_code,
- resource=resource,
- action=action or "read",
- )
- session.add(permission)
- permissions.append(permission)
- record.name = role.name
- record.data_scope = role.data_scope
- record.status = role.status
- record.permissions = permissions
- session.commit()
- def get_session(self, session_id: str) -> AuthSession | None:
- with self._session_factory() as session:
- record = session.get(AuthSessionRecord, session_id)
- if record is None:
- return None
- return AuthSession(
- id=record.id,
- subject_type=record.subject_type,
- subject_id=record.subject_id,
- refresh_jti_hash=record.refresh_jti_hash,
- expires_at=record.expires_at,
- revoked_at=record.revoked_at,
- )
- def save_session(self, auth_session: AuthSession) -> None:
- with self._session_factory() as session:
- session.merge(
- AuthSessionRecord(
- id=auth_session.id,
- subject_type=auth_session.subject_type,
- subject_id=auth_session.subject_id,
- refresh_jti_hash=auth_session.refresh_jti_hash,
- expires_at=auth_session.expires_at,
- revoked_at=auth_session.revoked_at,
- )
- )
- session.commit()
- @staticmethod
- def _to_h5_user(record: H5UserRecord) -> H5User:
- return H5User(
- id=record.id,
- mobile=record.mobile,
- mobile_masked=record.mobile_masked,
- display_name=record.display_name,
- status=record.status,
- created_at=record.created_at,
- )
- @staticmethod
- def _to_admin_user(record: AdminUserRecord) -> AdminUser:
- permissions = {permission.code for role in record.roles for permission in role.permissions}
- scopes = {role.data_scope for role in record.roles}
- data_scope = "ALL" if "ALL" in scopes else sorted(scopes)[0]
- return AdminUser(
- id=record.id,
- username=record.username,
- password_hash=record.password_hash,
- display_name=record.display_name,
- status=record.status,
- roles=tuple(sorted(role.code for role in record.roles)),
- permissions=tuple(sorted(permissions)),
- data_scope=data_scope,
- )
- class SqlAlchemyCatalogRepository(CatalogRepository):
- def __init__(self, session_factory: SessionFactory) -> None:
- self._session_factory = session_factory
- def save_product(self, product: Product) -> None:
- with self._session_factory() as session:
- session.merge(
- ProductRecord(
- id=product.id,
- product_code=product.product_code,
- name=product.name,
- category=product.category,
- summary=product.summary,
- status=product.status,
- )
- )
- session.commit()
- def save_version(self, version: ProductVersion) -> None:
- with self._session_factory() as session:
- record = session.get(ProductVersionRecord, version.id)
- if record is None:
- record = ProductVersionRecord(
- id=version.id,
- product_id=version.product_id,
- version_no=version.version_no,
- )
- session.add(record)
- record.version_no = version.version_no
- record.status = version.status
- record.effective_from = version.effective_from
- record.effective_to = version.effective_to
- record.rule_version = version.rule_version
- record.rate_version = version.rate_version
- record.terms_summary = version.terms_summary
- record.plans = [
- PlanRecord(
- id=plan.id,
- plan_code=plan.code,
- name=plan.name,
- summary=plan.summary,
- status=plan.status,
- premium_cents=plan.premium_cents,
- coverage_amount_cents=plan.coverage_amount_cents,
- min_age=plan.min_age,
- max_age=plan.max_age,
- )
- for plan in version.plans
- ]
- session.commit()
- def delete_version(self, version_id: str) -> None:
- with self._session_factory() as session:
- record = session.get(ProductVersionRecord, version_id)
- if record is not None:
- session.delete(record)
- session.commit()
- def save_change_log(self, log: ProductChangeLog) -> None:
- with self._session_factory() as session:
- session.merge(
- ProductChangeLogRecord(
- id=log.id,
- product_id=log.product_id,
- version_id=log.version_id,
- action=log.action,
- actor_id=log.actor_id,
- actor_name=log.actor_name,
- detail_json=log.detail,
- created_at=log.created_at,
- )
- )
- session.commit()
- def list_change_logs(self, product_id: str) -> list[ProductChangeLog]:
- with self._session_factory() as session:
- records = session.scalars(
- select(ProductChangeLogRecord)
- .where(ProductChangeLogRecord.product_id == product_id)
- .order_by(ProductChangeLogRecord.created_at.desc())
- ).all()
- return [
- ProductChangeLog(
- id=record.id,
- product_id=record.product_id,
- version_id=record.version_id,
- action=record.action,
- actor_id=record.actor_id,
- actor_name=record.actor_name,
- detail=dict(record.detail_json),
- created_at=record.created_at,
- )
- for record in records
- ]
- def list_products(self) -> list[Product]:
- with self._session_factory() as session:
- records = session.scalars(select(ProductRecord)).all()
- return [
- Product(
- id=record.id,
- product_code=record.product_code,
- name=record.name,
- category=record.category,
- summary=record.summary,
- status=record.status,
- )
- for record in records
- ]
- def list_versions(self, product_id: str) -> list[ProductVersion]:
- with self._session_factory() as session:
- records = session.scalars(
- select(ProductVersionRecord).where(ProductVersionRecord.product_id == product_id)
- ).all()
- return [
- ProductVersion(
- id=record.id,
- product_id=record.product_id,
- version_no=record.version_no,
- status=record.status,
- effective_from=record.effective_from,
- effective_to=record.effective_to,
- rule_version=record.rule_version,
- rate_version=record.rate_version,
- terms_summary=record.terms_summary,
- plans=tuple(
- Plan(
- id=plan.id,
- code=plan.plan_code,
- name=plan.name,
- summary=plan.summary,
- status=plan.status,
- premium_cents=plan.premium_cents,
- coverage_amount_cents=plan.coverage_amount_cents,
- min_age=plan.min_age,
- max_age=plan.max_age,
- )
- for plan in record.plans
- ),
- )
- for record in records
- ]
|