errors.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. """DMS业务异常。"""
  2. from __future__ import annotations
  3. from typing import Any
  4. class DmsError(Exception):
  5. code = "INTERNAL_ERROR"
  6. status_code = 500
  7. default_message = "服务器内部错误"
  8. def __init__(
  9. self,
  10. message: str | None = None,
  11. *,
  12. details: Any = None,
  13. code: str | None = None,
  14. ) -> None:
  15. super().__init__(message or self.default_message)
  16. self.message = message or self.default_message
  17. self.details = details
  18. self.code = code or self.code
  19. class InvalidArgumentError(DmsError):
  20. code = "INVALID_ARGUMENT"
  21. status_code = 400
  22. default_message = "请求参数错误"
  23. class AuthenticationError(DmsError):
  24. code = "TOKEN_INVALID"
  25. status_code = 401
  26. default_message = "未认证或登录凭证无效"
  27. class InvalidCredentialsError(AuthenticationError):
  28. code = "INVALID_CREDENTIALS"
  29. default_message = "用户名或密码错误"
  30. class TokenExpiredError(AuthenticationError):
  31. code = "TOKEN_EXPIRED"
  32. default_message = "登录凭证已过期"
  33. class UserDisabledError(AuthenticationError):
  34. code = "USER_DISABLED"
  35. default_message = "用户已被禁用"
  36. class AuthVersionMismatchError(AuthenticationError):
  37. code = "AUTH_VERSION_MISMATCH"
  38. default_message = "登录状态已失效,请重新登录"
  39. class PortalTokenInvalidError(AuthenticationError):
  40. code = "PORTAL_TOKEN_INVALID"
  41. default_message = "门户跳转凭证无效或已过期"
  42. class PortalTicketInvalidError(AuthenticationError):
  43. code = "PORTAL_TICKET_INVALID"
  44. default_message = "设置密码凭证无效或已过期,请从门户重新跳转"
  45. class ForbiddenError(DmsError):
  46. code = "FORBIDDEN"
  47. status_code = 403
  48. default_message = "无权限执行此操作"
  49. class SecurityLevelForbiddenError(ForbiddenError):
  50. code = "SECURITY_LEVEL_FORBIDDEN"
  51. default_message = "用户密级不足,无法查看该文档"
  52. class DocumentViewForbiddenError(ForbiddenError):
  53. code = "DOCUMENT_VIEW_FORBIDDEN"
  54. default_message = "无权查看该文档"
  55. class DocumentDownloadForbiddenError(ForbiddenError):
  56. code = "DOCUMENT_DOWNLOAD_FORBIDDEN"
  57. default_message = "无权下载该文档"
  58. class DocumentActionForbiddenError(ForbiddenError):
  59. """写路径按文档权限(矩阵/ACL)拒绝:区别于密级不足与查看/下载拒绝。"""
  60. code = "DOCUMENT_ACTION_FORBIDDEN"
  61. default_message = "无权对该文档执行此操作"
  62. class ResourceNotFoundError(DmsError):
  63. code = "RESOURCE_NOT_FOUND"
  64. status_code = 404
  65. default_message = "请求的资源不存在"
  66. class ConflictError(DmsError):
  67. code = "DATA_VERSION_CONFLICT"
  68. status_code = 409
  69. default_message = "数据冲突"
  70. class CategoryInUseError(ConflictError):
  71. code = "CATEGORY_IN_USE"
  72. default_message = "分类仍被子分类或方案文档占用"
  73. class CategoryNotLeafError(ConflictError):
  74. code = "CATEGORY_NOT_LEAF"
  75. default_message = "只有有效叶子分类可以直接存放主案"
  76. class CategoryFlatModeConflictError(ConflictError):
  77. code = "CATEGORY_FLAT_MODE_CONFLICT"
  78. default_message = "该一级分类下已存在子方案或配套资料挂载,请先解绑后再切换为扁平模式"
  79. class MainPlanNotFoundError(ResourceNotFoundError):
  80. code = "MAIN_PLAN_NOT_FOUND"
  81. default_message = "主案不存在"
  82. class FileNotFoundError(ResourceNotFoundError):
  83. code = "FILE_NOT_FOUND"
  84. default_message = "文档文件不存在"
  85. class PreviewUnavailableError(DmsError):
  86. code = "PREVIEW_UNAVAILABLE"
  87. status_code = 415
  88. default_message = "当前文件类型不支持在线预览"
  89. class PreviewConverterUnavailableError(DmsError):
  90. code = "PREVIEW_CONVERTER_UNAVAILABLE"
  91. status_code = 503
  92. default_message = "预览转换器未配置或不可用"
  93. class PreviewConversionTimeoutError(DmsError):
  94. code = "PREVIEW_CONVERSION_TIMEOUT"
  95. status_code = 504
  96. default_message = "文档转换超时,请稍后重试"
  97. class PreviewConversionFailedError(DmsError):
  98. code = "PREVIEW_CONVERSION_FAILED"
  99. status_code = 502
  100. default_message = "文档转换为PDF失败"
  101. class BatchManifestMismatchError(InvalidArgumentError):
  102. code = "BATCH_MANIFEST_MISMATCH"
  103. default_message = "批量文件数量与元数据数量不一致"
  104. class MainPlanHasChildrenError(ConflictError):
  105. code = "MAIN_PLAN_HAS_CHILDREN"
  106. default_message = "主案仍存在有效子方案"
  107. class DocumentNameConflictError(ConflictError):
  108. code = "DOCUMENT_NAME_CONFLICT"
  109. default_message = "同一范围内已存在同名方案"
  110. class AttachmentInUseError(ConflictError):
  111. code = "ATTACHMENT_IN_USE"
  112. default_message = "共享附件仍被主案挂载"
  113. class AttachmentHasNoAclError(InvalidArgumentError):
  114. code = "ATTACHMENT_HAS_NO_ACL"
  115. default_message = "共享附件不配置访问权限"
  116. class SubPlanPermissionInheritedError(ConflictError):
  117. code = "SUB_PLAN_PERMISSION_INHERITED"
  118. default_message = "子方案动态继承主案权限,不能独立配置"
  119. class DuplicatePermissionSubjectError(InvalidArgumentError):
  120. code = "DUPLICATE_PERMISSION_SUBJECT"
  121. default_message = "权限主体不能重复"
  122. class UnsupportedFileTypeError(DmsError):
  123. code = "UNSUPPORTED_FILE_TYPE"
  124. status_code = 415
  125. default_message = "不支持的文件类型"
  126. class PayloadTooLargeError(DmsError):
  127. code = "PAYLOAD_TOO_LARGE"
  128. status_code = 413
  129. default_message = "请求内容过大"
  130. class InternalError(DmsError):
  131. code = "INTERNAL_ERROR"
  132. status_code = 500
  133. default_message = "服务器内部错误"
  134. class DocumentNotDeletedError(ConflictError):
  135. code = "DOCUMENT_NOT_DELETED"
  136. default_message = "文档当前不在回收站中"
  137. class FileIntegrityMismatchError(ConflictError):
  138. code = "FILE_INTEGRITY_MISMATCH"
  139. default_message = "文档文件完整性校验失败"
  140. class FilePathInvalidError(InternalError):
  141. code = "FILE_PATH_INVALID"
  142. default_message = "文档存储路径异常"
  143. class RestoreFileChangedError(ConflictError):
  144. code = "RESTORE_FILE_CHANGED"
  145. default_message = "校验期间文件发生变化"
  146. class RestoreCategoryInvalidError(ConflictError):
  147. code = "RESTORE_CATEGORY_INVALID"
  148. default_message = "原方案分类无效,无法恢复"
  149. class RestoreParentInvalidError(ConflictError):
  150. code = "RESTORE_PARENT_INVALID"
  151. default_message = "原所属主案无效,无法恢复"
  152. class RestorePermissionInvalidError(ConflictError):
  153. code = "RESTORE_PERMISSION_INVALID"
  154. default_message = "恢复后无法形成有效权限配置"
  155. class RestoreRelationConflictError(ConflictError):
  156. code = "RESTORE_RELATION_CONFLICT"
  157. default_message = "历史权限或挂载关系与当前有效关系冲突"
  158. class OrganizationInUseError(ConflictError):
  159. code = "ORGANIZATION_IN_USE"
  160. default_message = "机构仍存在下级机构或挂载用户"
  161. class UserSelfProtectionError(ForbiddenError):
  162. code = "USER_SELF_PROTECTION"
  163. default_message = "不能对本账号执行该操作"
  164. class RoleInUseError(ConflictError):
  165. code = "ROLE_IN_USE"
  166. default_message = "角色仍有关联用户,无法删除"
  167. class DocumentPasswordRequiredError(ForbiddenError):
  168. code = "DOCUMENT_PASSWORD_REQUIRED"
  169. default_message = "该方案已设置密码保护,请输入密码后重试"
  170. class DocumentPasswordInvalidError(ForbiddenError):
  171. code = "DOCUMENT_PASSWORD_INVALID"
  172. default_message = "方案密码错误"
  173. class LoginIpForbiddenError(ForbiddenError):
  174. code = "LOGIN_IP_FORBIDDEN"
  175. default_message = "当前IP不在该部门允许的登录IP范围内"