user_service.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. """用户摘要、组织解析与列表查询。"""
  2. from __future__ import annotations
  3. from sqlalchemy import func, or_, select
  4. from dms.common.enums import AllowedModule, EnabledStatus, RoleCode
  5. from dms.common.errors import InvalidArgumentError, ResourceNotFoundError
  6. from dms.common.pagination import PageRequest, page_result
  7. from dms.common.response import serialize_id
  8. from dms.extensions import db
  9. from dms.models import Organization, User
  10. ALLOWED_MODULES = {
  11. RoleCode.USER: [AllowedModule.DOCUMENT_BROWSER.value],
  12. RoleCode.ADMIN: [
  13. AllowedModule.DOCUMENT_BROWSER.value,
  14. AllowedModule.BACKEND_MANAGEMENT.value,
  15. AllowedModule.AUDIT_LOG.value,
  16. ],
  17. }
  18. def effective_organization(user: User) -> tuple[int | None, str | None]:
  19. if user.organization_id is not None:
  20. organization = db.session.scalar(
  21. select(Organization).where(
  22. Organization.id == user.organization_id,
  23. Organization.is_deleted.is_(False),
  24. Organization.status == EnabledStatus.ENABLED.value,
  25. )
  26. )
  27. if organization is not None:
  28. return organization.id, organization.org_name
  29. return user.organization_id, user.organization_name
  30. def user_summary(user: User) -> dict[str, object]:
  31. organization_id, organization_name = effective_organization(user)
  32. return {
  33. "id": serialize_id(user.id),
  34. "username": user.username,
  35. "realName": user.real_name,
  36. "organizationId": serialize_id(organization_id),
  37. "organizationName": organization_name,
  38. "roleCode": user.role_code,
  39. "securityLevel": user.security_level,
  40. "status": user.status,
  41. "allowedModules": ALLOWED_MODULES[RoleCode(user.role_code)],
  42. }
  43. def parse_string_id(raw_value: str | None, *, name: str) -> int | None:
  44. if raw_value is None or raw_value == "":
  45. return None
  46. if not raw_value.isdecimal() or int(raw_value) <= 0:
  47. raise InvalidArgumentError(f"{name}必须是正整数形式的字符串ID")
  48. return int(raw_value)
  49. def _descendant_ids(root_id: int) -> set[int]:
  50. organizations = db.session.scalars(
  51. select(Organization).where(Organization.is_deleted.is_(False))
  52. ).all()
  53. if not any(item.id == root_id for item in organizations):
  54. raise ResourceNotFoundError("组织不存在")
  55. children: dict[int | None, list[int]] = {}
  56. for item in organizations:
  57. if item.status == EnabledStatus.ENABLED.value:
  58. children.setdefault(item.parent_id, []).append(item.id)
  59. found = {root_id}
  60. pending = [root_id]
  61. while pending:
  62. current = pending.pop()
  63. for child_id in children.get(current, []):
  64. if child_id not in found:
  65. found.add(child_id)
  66. pending.append(child_id)
  67. return found
  68. def list_users(
  69. *,
  70. organization_id: int | None,
  71. include_descendants: bool,
  72. keyword: str | None,
  73. status: str | None,
  74. page_request: PageRequest,
  75. ) -> dict[str, object]:
  76. filters = [User.is_deleted.is_(False)]
  77. if organization_id is not None:
  78. organization_ids = (
  79. _descendant_ids(organization_id)
  80. if include_descendants
  81. else {organization_id}
  82. )
  83. filters.append(User.organization_id.in_(organization_ids))
  84. if keyword:
  85. pattern = f"%{keyword.strip()}%"
  86. filters.append(or_(User.username.like(pattern), User.real_name.like(pattern)))
  87. if status:
  88. try:
  89. normalized_status = EnabledStatus(status).value
  90. except ValueError as exc:
  91. raise InvalidArgumentError("status必须是ENABLED或DISABLED") from exc
  92. filters.append(User.status == normalized_status)
  93. total = db.session.scalar(select(func.count(User.id)).where(*filters)) or 0
  94. users = db.session.scalars(
  95. select(User)
  96. .where(*filters)
  97. .order_by(User.real_name.asc(), User.id.asc())
  98. .offset(page_request.offset)
  99. .limit(page_request.page_size)
  100. ).all()
  101. return page_result(
  102. [user_summary(user) for user in users],
  103. page=page_request.page,
  104. page_size=page_request.page_size,
  105. total=total,
  106. )