Coverage for postrfp/ref/handlers/designers.py: 100%

43 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-10-22 21:34 +0000

1""" 

2HTTP endpoints for managing ContentSchema objects 

3""" 

4 

5from typing import Optional 

6 

7from sqlalchemy.orm import Session 

8 

9from postrfp.shared.pager import Pager 

10from postrfp.authorisation import perms 

11from postrfp.shared.decorators import http 

12from postrfp.model.humans import User 

13from postrfp.model.ref import ContentSpec 

14from postrfp.shared.serial.refmodels import ContentSchema, ListResponse 

15 

16 

17@http 

18def get_specs( 

19 session: Session, 

20 user: User, 

21 q_name: Optional[str] = None, 

22 pager: Optional[Pager] = None, 

23) -> ListResponse: 

24 """ 

25 List all content schemas accessible to the user's organization 

26 

27 Content schemas define the structure, validation rules, and field definitions 

28 for content items. Schemas are organization-owned and control how structured 

29 content is created and validated within the system. 

30 

31 **Query Parameters:** 

32 - `q_name`: Filter schemas by name (case-insensitive partial match) 

33 - Standard pagination parameters supported 

34 

35 **Returns:** Paginated list of schema definitions accessible to the user 

36 

37 **Access Control:** 

38 Schemas are filtered to show only: 

39 - Schemas owned by the user's organization 

40 - Schemas shared with the user's organization (if sharing is implemented) 

41 

42 **Schema Information Includes:** 

43 - Schema identification (ID, name, description) 

44 - JSON Schema definition with validation rules 

45 - Creation and modification timestamps 

46 - Owning organization details 

47 - Current workflow status 

48 

49 **Use Cases:** 

50 - Browse available content templates 

51 - Find schemas for specific content types 

52 - Understand validation requirements before content creation 

53 - Manage organization's content structure standards 

54 

55 **Examples:** 

56 - Get all schemas: no query parameters 

57 - Search by name: `?q_name=financial report` 

58 """ 

59 if pager is None: 

60 pager = Pager(page=1, page_size=20) 

61 

62 # Start query with schemas owned by user's org or shared with them 

63 query = ( 

64 session.query(ContentSpec) 

65 .filter((ContentSpec.org_id == user.org_id)) 

66 .order_by(ContentSpec.name) 

67 ) 

68 

69 if q_name: 

70 query = query.filter(ContentSpec.name.ilike(f"%{q_name}%")) 

71 

72 total_records = query.count() 

73 records = query.slice(pager.startfrom, pager.goto).all() 

74 

75 return ListResponse( 

76 items=[ContentSchema.model_validate(schema) for schema in records], 

77 pagination=pager.as_pagination(total_records, len(records)), 

78 ) 

79 

80 

81@http 

82def get_spec(session: Session, user: User, spec_id: int) -> ContentSchema: 

83 """ 

84 Get a single content schema by ID 

85 

86 Retrieves the complete schema definition including all field specifications, 

87 validation rules, metadata, and documentation. Essential for understanding 

88 content structure requirements and implementing content creation interfaces. 

89 

90 **Path Parameters:** 

91 - `spec_id`: Unique identifier of the content schema 

92 

93 **Returns:** Complete schema definition including: 

94 - Schema identification and metadata 

95 - Full JSON Schema specification with all validation rules 

96 - Field definitions and constraints 

97 - Required vs optional field specifications 

98 - Data types and format requirements 

99 - Custom validation patterns 

100 - Creation and modification history 

101 

102 **JSON Schema Features:** 

103 The returned schema follows JSON Schema Draft 7+ specifications and may include: 

104 - Field type definitions (string, number, object, array, etc.) 

105 - Validation constraints (min/max length, patterns, enums) 

106 - Nested object structures 

107 - Array item specifications 

108 - Conditional field requirements 

109 - Custom format validators 

110 

111 **Use Cases:** 

112 - Generate content creation forms dynamically 

113 - Validate content before submission 

114 - Understand content structure for API integration 

115 - Document content requirements for users 

116 

117 **Raises:** 

118 - `NoResultFound`: If the schema ID does not exist 

119 - `AuthorizationFailure`: If the user lacks access to this schema 

120 """ 

121 content_spec = session.get_one(ContentSpec, spec_id) 

122 

123 return ContentSchema.model_validate(content_spec) 

124 

125 

126@http 

127def post_spec(session: Session, user: User, spec_doc: ContentSchema) -> ContentSchema: 

128 """ 

129 Create a new content schema 

130 

131 Creates a new JSON Schema definition that will control the structure and 

132 validation of content items. The schema becomes available for content creation 

133 within the user's organization and can define complex data structures. 

134 

135 **Request Body:** Schema document including: 

136 - `name`: Descriptive name for the schema (required) 

137 - `description`: Detailed explanation of the schema purpose 

138 - `spec_doc`: Complete JSON Schema definition (required) 

139 

140 **Returns:** Created schema with assigned ID and metadata 

141 

142 **JSON Schema Requirements:** 

143 The `spec_doc` must be a valid JSON Schema (Draft 7+ recommended) including: 

144 - Root `type` definition (typically "object") 

145 - `properties` defining all available fields 

146 - `required` array listing mandatory fields 

147 - Field-level validation constraints 

148 - Proper data type specifications 

149 

150 **Schema Validation:** 

151 The system validates that: 

152 - The JSON Schema syntax is correct 

153 - Required fields are properly defined 

154 - Type definitions are valid 

155 - Constraints are logically consistent 

156 

157 **Ownership:** 

158 - Schema is owned by the user's organization 

159 - Only the owning organization can modify the schema 

160 - Content created with this schema will reference the organization 

161 

162 **Best Practices:** 

163 - Use descriptive field names and documentation 

164 - Define appropriate validation constraints 

165 - Consider backward compatibility for schema updates 

166 - Include examples in the schema description 

167 

168 **@permissions REF_SPEC_SAVE** 

169 

170 **Examples:** 

171 ```json 

172 { 

173 "name": "Financial Report Schema", 

174 "description": "Quarterly financial reporting template", 

175 "spec_doc": { 

176 "type": "object", 

177 "properties": { 

178 "report_period": {"type": "string", "format": "date"}, 

179 "revenue": {"type": "number", "minimum": 0}, 

180 "expenses": {"type": "number", "minimum": 0} 

181 }, 

182 "required": ["report_period", "revenue", "expenses"] 

183 } 

184 } 

185 ``` 

186 """ 

187 user.check_permission(perms.REF_SPEC_SAVE) 

188 

189 # Create new schema 

190 new_content_spec = ContentSpec( 

191 name=spec_doc.name, 

192 description=spec_doc.description, 

193 spec_doc=spec_doc.spec_doc, 

194 auth_policy=spec_doc.auth_policy, 

195 org_id=user.org_id, # Always use the current user's org ID for ownership 

196 ) 

197 session.add(new_content_spec) 

198 

199 session.flush() 

200 return ContentSchema.model_validate(new_content_spec) 

201 

202 

203@http 

204def put_spec( 

205 session: Session, user: User, spec_id: int, spec_doc: ContentSchema 

206) -> ContentSchema: 

207 """ 

208 Update an existing content schema 

209 

210 Modifies an existing schema definition with new validation rules and structure. 

211 This is a potentially breaking change that may affect existing content items 

212 that use this schema, so it should be used carefully. 

213 

214 **Path Parameters:** 

215 - `spec_id`: ID of the schema to update 

216 

217 **Request Body:** Complete schema document (all fields will be updated) 

218 - `name`: Updated descriptive name for the schema 

219 - `description`: Updated explanation of schema purpose 

220 - `spec_doc`: Complete updated JSON Schema definition 

221 

222 **Returns:** Updated schema with new timestamps and metadata 

223 

224 **Breaking Change Considerations:** 

225 - Existing content may no longer validate against the updated schema 

226 - New required fields will cause validation failures for existing content 

227 - Changed field types or constraints may break existing content 

228 - Removed fields will be ignored in existing content but may cause confusion 

229 

230 **Schema Evolution Best Practices:** 

231 - Add new optional fields rather than required ones 

232 - Avoid removing existing fields that contain data 

233 - Use schema versioning for major structural changes 

234 - Consider deprecation warnings before removing fields 

235 - Test schema changes against existing content 

236 

237 **Validation Impact:** 

238 - Content validation occurs during content creation and updates 

239 - Existing content is not automatically re-validated 

240 - Invalid content may become accessible but not editable 

241 - New content must pass validation with the updated schema 

242 

243 **@permissions REF_SPEC_SAVE** 

244 

245 **Raises:** 

246 - `NoResultFound`: If the schema ID does not exist 

247 - `AuthorizationFailure`: If the user's organization doesn't own this schema 

248 - `ValidationError`: If the updated JSON Schema is invalid 

249 

250 **Migration Strategy:** 

251 For major schema changes, consider: 

252 1. Creating a new schema version 

253 2. Migrating content to the new schema gradually 

254 3. Deprecating the old schema after migration 

255 4. Providing clear migration documentation 

256 """ 

257 user.check_permission(perms.REF_SPEC_SAVE) 

258 

259 content_spec = session.get_one(ContentSpec, spec_id) 

260 

261 # Update schema fields 

262 content_spec.name = spec_doc.name 

263 content_spec.description = spec_doc.description 

264 content_spec.spec_doc = spec_doc.spec_doc 

265 content_spec.auth_policy = spec_doc.auth_policy 

266 

267 return ContentSchema.model_validate(content_spec) 

268 

269 

270@http 

271def delete_spec(session: Session, user: User, spec_id: int) -> None: 

272 """ 

273 Delete a content schema 

274 

275 Permanently removes a schema definition from the system. This is a destructive 

276 operation that will affect all content items using this schema and should be 

277 used with extreme caution. 

278 

279 **Path Parameters:** 

280 - `spec_id`: ID of the schema to delete 

281 

282 **Returns:** None (204 No Content status) 

283 

284 **Critical Impact:** 

285 - **All content using this schema will become invalid** 

286 - Content items will no longer pass validation 

287 - Existing content becomes uneditable (validation failures) 

288 - Content creation with this schema becomes impossible 

289 - API responses may include validation warnings 

290 

291 **What Gets Deleted:** 

292 - The schema definition itself 

293 - All validation rules and field specifications 

294 - Schema metadata and documentation 

295 - Workflow state information for the schema 

296 

297 **Content Impact:** 

298 Content items using this schema will: 

299 - Remain accessible for viewing (existing data preserved) 

300 - Fail validation checks during editing attempts 

301 - Display warnings about missing schema 

302 - Require schema reassignment or recreation for continued use 

303 

304 **Permission Requirements:** 

305 - User's organization must own the schema 

306 - Only the schema owner can delete it 

307 - Cannot be deleted if it would violate system constraints 

308 

309 **Recommended Alternatives:** 

310 Instead of deletion, consider: 

311 - Deprecating the schema (mark as inactive) 

312 - Creating a migration path to a new schema 

313 - Archiving content using the schema first 

314 - Updating the schema to a minimal valid state 

315 

316 **@permissions REF_SPEC_SAVE** 

317 

318 **Raises:** 

319 - `NoResultFound`: If the schema ID does not exist 

320 - `AuthorizationFailure`: If the user's organization doesn't own this schema 

321 - `IntegrityError`: If content still depends on this schema (depending on DB constraints) 

322 

323 **⚠️ Warning:** This action cannot be undone. Ensure all content using this schema 

324 has been migrated or archived before proceeding with deletion. 

325 """ 

326 user.check_permission(perms.REF_SPEC_SAVE) 

327 

328 schema = session.get_one(ContentSpec, spec_id) 

329 

330 session.delete(schema)