fix: UserRole.admin typo and defensive JSON parsing in JS

- Fix UserRole.admin to UserRole.ADMIN in events.py delete route
- Add content-type check before parsing JSON in event delete handler
- Add error handling and content-type check in animal selection hash computation
- Audited codebase: no other enum case issues found

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-02 09:49:45 +00:00
parent a1fed4ebcd
commit 9709a78dc6
3 changed files with 23 additions and 6 deletions

View File

@@ -335,7 +335,7 @@ async def event_delete(request: Request, event_id: str):
if not auth: if not auth:
return JSONResponse({"error": "Not authenticated"}, status_code=401) return JSONResponse({"error": "Not authenticated"}, status_code=401)
if auth.role != UserRole.admin: if auth.role != UserRole.ADMIN:
return JSONResponse({"error": "Admin role required"}, status_code=403) return JSONResponse({"error": "Admin role required"}, status_code=403)
# Parse form data # Parse form data

View File

@@ -157,13 +157,24 @@ def selection_script(total_count: int) -> Div:
from_location_id: fromLoc from_location_id: fromLoc
}}) }})
}}) }})
.then(response => response.json()) .then(response => {{
if (!response.ok) {{
console.error('Hash computation failed:', response.status);
return {{}};
}}
var contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {{
return response.json();
}}
return {{}};
}})
.then(data => {{ .then(data => {{
var hashField = document.getElementById('roster-hash-field'); var hashField = document.getElementById('roster-hash-field');
if (hashField) {{ if (hashField && data.roster_hash) {{
hashField.value = data.roster_hash; hashField.value = data.roster_hash;
}} }}
}}); }})
.catch(err => console.error('Hash computation error:', err));
}} }}
// Initialize hash on load // Initialize hash on load

View File

@@ -409,7 +409,12 @@ def delete_script() -> Script:
body: 'reason=Deleted via UI' body: 'reason=Deleted via UI'
}); });
const data = await response.json(); // Try to parse JSON, but handle non-JSON responses gracefully
let data = {};
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
data = await response.json();
}
if (response.ok) { if (response.ok) {
statusEl.innerHTML = '<span class="text-green-400">Event deleted successfully!</span>'; statusEl.innerHTML = '<span class="text-green-400">Event deleted successfully!</span>';
@@ -422,7 +427,8 @@ def delete_script() -> Script:
statusEl.innerHTML = '<span class="text-red-400">' + data.message + '</span>'; statusEl.innerHTML = '<span class="text-red-400">' + data.message + '</span>';
deleteBtn.disabled = false; deleteBtn.disabled = false;
} else { } else {
statusEl.innerHTML = '<span class="text-red-400">Error: ' + (data.error || 'Unknown error') + '</span>'; const errorMsg = data.error || 'Server error (' + response.status + ')';
statusEl.innerHTML = '<span class="text-red-400">Error: ' + errorMsg + '</span>';
deleteBtn.disabled = false; deleteBtn.disabled = false;
} }
} catch (err) { } catch (err) {