users.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. """当前用户、用户分页查询与用户维护写操作。"""
  2. from __future__ import annotations
  3. from flask import request
  4. from sqlalchemy import select
  5. from dms.api.v1.blueprint import api_v1
  6. from dms.common.errors import AuthenticationError, InvalidArgumentError
  7. from dms.common.pagination import PageRequest
  8. from dms.common.response import success_response
  9. from dms.extensions import db
  10. from dms.models import User
  11. from dms.security.auth_context import get_auth_context
  12. from dms.security.decorators import admin_required, bearer_auth_required
  13. from dms.services.user_service import (
  14. allowed_modules_for_user,
  15. create_user,
  16. delete_user,
  17. list_users,
  18. parse_string_id,
  19. reset_user_password,
  20. update_user,
  21. user_summary,
  22. )
  23. def _integer_query(name: str, default: int) -> int:
  24. raw_value = request.args.get(name)
  25. if raw_value is None or raw_value == "":
  26. return default
  27. try:
  28. return int(raw_value)
  29. except ValueError as exc:
  30. raise InvalidArgumentError(f"{name}必须是整数") from exc
  31. def _boolean_query(name: str, default: bool) -> bool:
  32. raw_value = request.args.get(name)
  33. if raw_value is None or raw_value == "":
  34. return default
  35. normalized = raw_value.lower()
  36. if normalized not in {"true", "false"}:
  37. raise InvalidArgumentError(f"{name}必须是true或false")
  38. return normalized == "true"
  39. def _json_body():
  40. if not request.is_json:
  41. raise InvalidArgumentError("请求体必须是JSON对象")
  42. body = request.get_json(silent=True)
  43. if not isinstance(body, dict):
  44. raise InvalidArgumentError("请求体必须是JSON对象")
  45. return body
  46. def _parse_user_id(value: str) -> int:
  47. if not value.isdecimal() or int(value) <= 0:
  48. raise InvalidArgumentError("id必须是正整数形式的字符串ID")
  49. return int(value)
  50. def _parse_delete_row_version(value: str | None) -> int:
  51. if value is None or not value.isdecimal():
  52. raise InvalidArgumentError("rowVersion必须是非负整数")
  53. return int(value)
  54. @api_v1.get("/users/me")
  55. @bearer_auth_required
  56. def current_user():
  57. context = get_auth_context()
  58. user = db.session.scalar(
  59. select(User).where(User.id == context.user_id, User.is_deleted.is_(False))
  60. )
  61. if user is None:
  62. raise AuthenticationError()
  63. # 会话自描述接口:模块可见性按该用户对文档的实际权限动态计算。
  64. return success_response(
  65. user_summary(user, allowed_modules=allowed_modules_for_user(user))
  66. )
  67. @api_v1.get("/users")
  68. @bearer_auth_required
  69. @admin_required
  70. def users():
  71. page_request = PageRequest(
  72. page=_integer_query("page", 1),
  73. page_size=_integer_query("pageSize", 20),
  74. )
  75. data = list_users(
  76. organization_id=parse_string_id(
  77. request.args.get("organizationId"),
  78. name="organizationId",
  79. ),
  80. include_descendants=_boolean_query("includeDescendants", False),
  81. keyword=request.args.get("keyword"),
  82. status=request.args.get("status"),
  83. page_request=page_request,
  84. )
  85. return success_response(data)
  86. @api_v1.post("/users")
  87. @bearer_auth_required
  88. @admin_required
  89. def create_user_route():
  90. return success_response(create_user(_json_body()), status=201)
  91. @api_v1.put("/users/<id>")
  92. @bearer_auth_required
  93. @admin_required
  94. def update_user_route(id: str):
  95. return success_response(update_user(_parse_user_id(id), _json_body()))
  96. @api_v1.delete("/users/<id>")
  97. @bearer_auth_required
  98. @admin_required
  99. def delete_user_route(id: str):
  100. return success_response(
  101. delete_user(
  102. _parse_user_id(id),
  103. _parse_delete_row_version(request.args.get("rowVersion")),
  104. )
  105. )
  106. @api_v1.post("/users/<id>/reset-password")
  107. @bearer_auth_required
  108. @admin_required
  109. def reset_user_password_route(id: str):
  110. return success_response(
  111. reset_user_password(_parse_user_id(id), _json_body())
  112. )