Skip to content

Commit 2cb53f7

Browse files
committed
fix(spp_api_v2_change_request): use Literal type for finite-valued str fields
Replace plain str with Literal for fields that have a known, fixed set of valid values: ChangeRequestResponse.status and ChangeRequestTypeInfo.target_type. This provides stricter validation and clearer API documentation.
1 parent 74114b5 commit 2cb53f7

File tree

3 files changed

+7
-33
lines changed

3 files changed

+7
-33
lines changed

spp_api_v2/services/schema_builder.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,12 @@ def _extract_selection_choices(self, field) -> list[dict[str, str]]:
189189
Handles both list-of-tuples and callable selections.
190190
"""
191191
selection = field.selection
192+
field_name = field.name
192193
if callable(selection):
193194
try:
194195
selection = selection(self.env[field.model_name])
195196
except Exception:
196-
_logger.warning("Could not evaluate callable selection for %s", field.name, exc_info=True)
197+
_logger.warning("Could not evaluate callable selection for %s", field_name, exc_info=True)
197198
return []
198199
if not selection:
199200
return []
@@ -202,7 +203,7 @@ def _extract_selection_choices(self, field) -> list[dict[str, str]]:
202203
if isinstance(item, (list, tuple)) and len(item) >= 2:
203204
result.append({"value": item[0], "label": item[1]})
204205
else:
205-
_logger.debug("Skipping unparseable selection item for %s: %r", field.name, item)
206+
_logger.debug("Skipping unparseable selection item for %s: %r", field_name, item)
206207
return result
207208

208209
def _extract_vocabulary_info_from_domain(

spp_api_v2_change_request/__manifest__.py

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,32 +25,4 @@
2525
"summary": """
2626
REST API endpoints for Change Request V2.
2727
""",
28-
"description": """
29-
OpenSPP API V2 - Change Request
30-
================================
31-
32-
Extends OpenSPP API V2 with Change Request endpoints.
33-
34-
Endpoints
35-
---------
36-
- ``POST /ChangeRequest`` - Create a new change request
37-
- ``GET /ChangeRequest/{identifier}`` - Read a change request by reference
38-
- ``GET /ChangeRequest`` - Search change requests
39-
- ``PUT /ChangeRequest/{identifier}`` - Update change request detail data
40-
- ``POST /ChangeRequest/{identifier}/$submit`` - Submit for approval
41-
- ``POST /ChangeRequest/{identifier}/$approve`` - Approve (requires permission)
42-
- ``POST /ChangeRequest/{identifier}/$reject`` - Reject (requires permission)
43-
- ``POST /ChangeRequest/{identifier}/$request-revision`` - Request revision (requires permission)
44-
- ``POST /ChangeRequest/{identifier}/$apply`` - Apply changes to registrant
45-
- ``POST /ChangeRequest/{identifier}/$reset`` - Reset rejected/revision CR to draft
46-
- ``GET /ChangeRequest/$types`` - List all active CR types
47-
- ``GET /ChangeRequest/$types/{code}`` - Get field schema for a CR type
48-
49-
Design Principles
50-
-----------------
51-
- Uses CR reference (CR/2024/00001), NOT database IDs
52-
- Returns appropriate HTTP status codes
53-
- Follows OpenSPP API V2 patterns
54-
- Requires authentication via OAuth 2.0
55-
""",
5628
}

spp_api_v2_change_request/schemas/change_request.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,9 @@ class ChangeRequestResponse(BaseModel):
103103
request_type: ChangeRequestType = Field(..., alias="requestType")
104104

105105
# Status
106-
status: str = Field(
106+
status: Literal["draft", "pending", "revision", "approved", "rejected", "applied"] = Field(
107107
...,
108108
description="Current status",
109-
json_schema_extra={"enum": ["draft", "pending", "revision", "approved", "rejected", "applied"]},
110109
)
111110

112111
# Target registrant
@@ -202,7 +201,9 @@ class ChangeRequestTypeInfo(BaseModel):
202201

203202
code: str = Field(..., description="Type code (e.g., add_member)")
204203
name: str = Field(..., description="Human-readable type name")
205-
target_type: str = Field(..., alias="targetType", description="Target registrant type (individual, group, both)")
204+
target_type: Literal["individual", "group", "both"] = Field(
205+
..., alias="targetType", description="Target registrant type"
206+
)
206207
requires_applicant: bool = Field(False, alias="requiresApplicant", description="Whether an applicant is required")
207208

208209
class Config:

0 commit comments

Comments
 (0)