Skip to content

Commit b960c56

Browse files
Fix test failures
1 parent 1e360b6 commit b960c56

File tree

4 files changed

+56
-15
lines changed

4 files changed

+56
-15
lines changed

main.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,18 @@ async def password_validation_exception_handler(request: Request, exc: PasswordV
105105
@app.exception_handler(RequestValidationError)
106106
async def validation_exception_handler(request: Request, exc: RequestValidationError):
107107
errors = {}
108+
109+
# Map error types to user-friendly message templates
110+
error_templates = {
111+
"pattern_mismatch": "this field cannot be empty or contain only whitespace",
112+
"string_too_short": "this field is required",
113+
"missing": "this field is required",
114+
"string_pattern_mismatch": "this field cannot be empty or contain only whitespace",
115+
"enum": "invalid value"
116+
}
117+
108118
for error in exc.errors():
109-
# Handle different error locations more carefully
119+
# Handle different error locations carefully
110120
location = error["loc"]
111121

112122
# Skip type errors for the whole body
@@ -115,8 +125,21 @@ async def validation_exception_handler(request: Request, exc: RequestValidationE
115125

116126
# For form fields, the location might be just (field_name,)
117127
# For JSON body, it might be (body, field_name)
118-
field_name = location[-1] # Take the last item in the location tuple
119-
errors[field_name] = error["msg"]
128+
# For array items, it might be (field_name, array_index)
129+
field_name = location[-2] if isinstance(location[-1], int) else location[-1]
130+
131+
# Format the field name to be more user-friendly
132+
display_name = field_name.replace("_", " ").title()
133+
134+
# Use mapped message if available, otherwise use FastAPI's message
135+
error_type = error.get("type", "")
136+
message_template = error_templates.get(error_type, error["msg"])
137+
138+
# For array items, append the index to the message
139+
if isinstance(location[-1], int):
140+
message_template = f"Item {location[-1] + 1}: {message_template}"
141+
142+
errors[display_name] = message_template
120143

121144
return templates.TemplateResponse(
122145
request,

routers/organization.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
from fastapi import APIRouter, Depends, Form, Request
44
from fastapi.responses import RedirectResponse
55
from fastapi.templating import Jinja2Templates
6-
from pydantic import StringConstraints
76
from sqlmodel import Session, select
87
from utils.db import get_session, default_roles
98
from utils.dependencies import get_authenticated_user, get_user_with_relations
109
from utils.models import Organization, User, Role, utc_time
1110
from utils.enums import ValidPermissions
12-
from exceptions.http_exceptions import OrganizationNotFoundError, OrganizationNameTakenError, InsufficientPermissionsError
11+
from exceptions.http_exceptions import OrganizationNotFoundError, OrganizationNameTakenError, InsufficientPermissionsError, EmptyOrganizationNameError
1312

1413
logger = getLogger("uvicorn.error")
1514

@@ -41,10 +40,18 @@ async def read_organization(
4140

4241
@router.post("/create", response_class=RedirectResponse)
4342
def create_organization(
44-
name: Annotated[str, StringConstraints(min_length=1, strip_whitespace=True)] = Form(...),
43+
name: Annotated[str, Form(
44+
min_length=1,
45+
strip_whitespace=True,
46+
pattern=r"\S+",
47+
description="Organization name cannot be empty or contain only whitespace",
48+
title="Organization name"
49+
)],
4550
user: User = Depends(get_authenticated_user),
4651
session: Session = Depends(get_session)
4752
) -> RedirectResponse:
53+
logger.debug(f"Received organization name: '{name}' (length: {len(name)})")
54+
4855
# Check if organization already exists
4956
db_org = session.exec(select(Organization).where(
5057
Organization.name == name)).first()
@@ -81,7 +88,13 @@ def create_organization(
8188
@router.post("/update/{org_id}", name="update_organization", response_class=RedirectResponse)
8289
def update_organization(
8390
org_id: int,
84-
name: Annotated[str, StringConstraints(min_length=1, strip_whitespace=True)] = Form(...),
91+
name: Annotated[str, Form(
92+
min_length=1,
93+
strip_whitespace=True,
94+
pattern=r"\S+",
95+
description="Organization name cannot be empty or contain only whitespace",
96+
title="Organization name"
97+
)],
8598
user: User = Depends(get_user_with_relations),
8699
session: Session = Depends(get_session)
87100
) -> RedirectResponse:

routers/role.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
def create_role(
2222
name: str = Form(...),
2323
organization_id: int = Form(...),
24+
permissions: List[ValidPermissions] = Form(...),
2425
user: User = Depends(get_authenticated_user),
2526
session: Session = Depends(get_session)
2627
) -> RedirectResponse:
@@ -46,10 +47,10 @@ def create_role(
4647

4748
# Select Permission records corresponding to the user-selected permissions
4849
# and associate them with the newly created role
49-
permissions: Sequence[Permission] = session.exec(
50+
db_permissions: Sequence[Permission] = session.exec(
5051
select(Permission).where(col(Permission.name).in_(permissions))
5152
).all()
52-
db_role.permissions.extend(permissions)
53+
db_role.permissions.extend(db_permissions)
5354

5455
# Commit transaction
5556
session.commit()

tests/routers/test_organization.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,14 @@ def test_create_organization_empty_name(auth_client):
3939
"""Test organization creation with empty name"""
4040
response = auth_client.post(
4141
"/organizations/create",
42-
data={"name": " "} # Empty or whitespace name
42+
data={"name": " "},
43+
follow_redirects=True
4344
)
4445

45-
assert response.status_code == 400
46-
assert "Organization name cannot be empty" in response.text
46+
# Should get a 422 Unprocessable Entity for validation error
47+
assert response.status_code == 422
48+
assert "this field cannot be empty or contain only whitespace" in response.text
49+
assert "name" in response.text
4750

4851
def test_create_organization_duplicate_name(auth_client, session, test_organization):
4952
"""Test organization creation with duplicate name"""
@@ -173,11 +176,12 @@ def test_update_organization_empty_name(auth_client, session, test_organization,
173176
"id": test_organization.id,
174177
"name": " "
175178
},
176-
follow_redirects=False
179+
follow_redirects=True
177180
)
178181

179-
assert response.status_code == 400
180-
assert "organization name cannot be empty" in response.text.lower()
182+
assert response.status_code == 422
183+
assert "this field cannot be empty or contain only whitespace" in response.text.lower()
184+
assert "name" in response.text.lower()
181185

182186
def test_update_organization_unauthenticated(unauth_client, test_organization):
183187
"""Test organization update without authentication"""

0 commit comments

Comments
 (0)