Coverage for api/roles/schema.py: 100.00%

54 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-09-03 15:30 +0000

1from pydantic import BaseModel, Field 

2 

3from core.config import settings 

4 

5 

6class RoleResponse(BaseModel): 

7 id: str = Field(..., description="Role ID") 

8 name: str = Field(..., description="Role name") 

9 description: str | None = Field(None, description="Role description") 

10 level: int = Field(..., description="Role privilege level (higher is more privileged)") 

11 

12 

13class RolesListResponse(BaseModel): 

14 roles: list[RoleResponse] = Field(..., description="List of roles") 

15 actor_level: int = Field(..., description="Current user's role level") 

16 actor_role_id: str | None = Field( 

17 None, description="Current user's primary role ID (cannot self-edit/delete)" 

18 ) 

19 

20 

21class RoleCreate(BaseModel): 

22 name: str = Field(..., min_length=1, max_length=100, description="Role name") 

23 description: str | None = Field(None, max_length=500, description="Role description") 

24 level: int = Field( 

25 ..., 

26 ge=1, 

27 le=settings.MAX_CUSTOM_ROLE_LEVEL, 

28 description="Role privilege level (must be lower than the actor's level)", 

29 ) 

30 

31 

32class RoleUpdate(BaseModel): 

33 name: str | None = Field(None, min_length=1, max_length=100, description="Role name") 

34 description: str | None = Field(None, max_length=500, description="Role description") 

35 level: int | None = Field( 

36 None, 

37 ge=1, 

38 le=settings.MAX_CUSTOM_ROLE_LEVEL, 

39 description="Role privilege level (must be lower than the actor's level)", 

40 ) 

41 

42 

43class RoleAttributesMapping(BaseModel): 

44 attributes: dict[str, bool] = Field( 

45 ..., 

46 description="Role attributes mapping (attribute_name: value)", 

47 example={"view-users": True, "manage-users": False, "view-roles": True}, 

48 ) 

49 

50 @classmethod 

51 def get_example_response(cls): 

52 return { 

53 "code": 200, 

54 "message": "Role attributes mapping example", 

55 "data": {"attributes": {"view-users": True, "manage-users": False, "view-roles": True}}, 

56 } 

57 

58 

59class RoleAttributeDetail(BaseModel): 

60 name: str = Field(..., description="Attribute name", example="view-users") 

61 value: bool = Field(..., description="Whether the role has this attribute", example=True) 

62 

63 

64class RoleAttributesGroup(BaseModel): 

65 group: str = Field(..., description="Top-level group key", example="user-role-management") 

66 categories: dict[str, list[RoleAttributeDetail]] = Field( 

67 ..., description="Categories inside this group (category -> attributes)" 

68 ) 

69 

70 

71class RoleAttributesGroupedResponse(BaseModel): 

72 groups: list[RoleAttributesGroup] = Field( 

73 ..., description="Role attributes grouped by group and category" 

74 ) 

75 

76 @classmethod 

77 def get_example_response(cls): 

78 return { 

79 "code": 200, 

80 "message": "Successfully retrieved role attributes mapping", 

81 "data": { 

82 "groups": [ 

83 { 

84 "group": "user-role-management", 

85 "categories": { 

86 "user": [ 

87 {"name": "view-users", "value": True}, 

88 {"name": "manage-users", "value": False}, 

89 ], 

90 "role": [{"name": "view-roles", "value": True}], 

91 }, 

92 } 

93 ] 

94 }, 

95 } 

96 

97 

98class AttributeMappingResult(BaseModel): 

99 attribute_id: str = Field(..., description="Attribute ID") 

100 status: str = Field( 

101 ..., description="Processing status: success, failed", pattern="^(success|failed)$" 

102 ) 

103 message: str = Field(..., description="Result message") 

104 

105 

106class RoleAttributeMappingBatchResponse(BaseModel): 

107 results: list[AttributeMappingResult] = Field( 

108 ..., description="Individual attribute mapping results" 

109 ) 

110 total_attributes: int = Field(..., description="Total number of attributes processed") 

111 success_count: int = Field(..., description="Number of successfully processed attributes") 

112 failed_count: int = Field(..., description="Number of failed attributes") 

113 

114 

115class PermissionCheckRequest(BaseModel): 

116 attributes: list[str] | None = Field( 

117 None, 

118 min_items=1, 

119 description=( 

120 "List of permission attributes to check. If not provided, returns all user permissions." 

121 ), 

122 example=["view-users", "manage-roles"], 

123 ) 

124 

125 

126class PermissionCheckResponse(BaseModel): 

127 permissions: dict[str, bool] = Field( 

128 ..., 

129 description="Permission check results (attribute_name: has_permission)", 

130 example={ 

131 "view-users": True, 

132 "manage-users": False, 

133 "view-roles": True, 

134 "manage-roles": False, 

135 }, 

136 ) 

137 

138 @classmethod 

139 def get_example_response(cls): 

140 return { 

141 "code": 200, 

142 "message": "User permissions retrieved", 

143 "data": { 

144 "permissions": { 

145 "view-users": True, 

146 "manage-users": False, 

147 "view-roles": True, 

148 "manage-roles": False, 

149 } 

150 }, 

151 } 

152 

153 

154role_attributes_success_response_example = { 

155 "code": 200, 

156 "message": "All role attributes processed successfully", 

157 "data": { 

158 "results": [ 

159 {"attribute_id": "attr-001", "status": "success", "message": "Updated successfully"}, 

160 {"attribute_id": "attr-002", "status": "success", "message": "Updated successfully"}, 

161 ], 

162 "total_attributes": 2, 

163 "success_count": 2, 

164 "failed_count": 0, 

165 }, 

166} 

167 

168role_attributes_partial_response_example = { 

169 "code": 207, 

170 "message": "Role attributes processed with partial success", 

171 "data": { 

172 "results": [ 

173 {"attribute_id": "attr-001", "status": "success", "message": "Updated successfully"}, 

174 {"attribute_id": "attr-002", "status": "failed", "message": "Invalid attribute ID"}, 

175 ], 

176 "total_attributes": 2, 

177 "success_count": 1, 

178 "failed_count": 1, 

179 }, 

180} 

181 

182role_attributes_failed_response_example = { 

183 "code": 400, 

184 "message": "All role attributes failed to process", 

185 "data": { 

186 "results": [ 

187 { 

188 "attribute_id": "invalid-attr-001", 

189 "status": "failed", 

190 "message": "Invalid attribute ID", 

191 }, 

192 { 

193 "attribute_id": "invalid-attr-002", 

194 "status": "failed", 

195 "message": "Invalid attribute ID", 

196 }, 

197 ], 

198 "total_attributes": 2, 

199 "success_count": 0, 

200 "failed_count": 2, 

201 }, 

202}