fix(backend): address PR review feedback from majdyz

- Remove try/except blocks from admin routes, rely on global exception
  handlers in rest_api.py
- Rename schema relation fields to PascalCase (WaitlistEntries,
  JoinedWaitlists, JoinedUsers) to match codebase convention
- Update all Prisma include/data references in db.py accordingly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nicholas Tindle
2026-03-05 19:50:56 -06:00
parent 676fc6647b
commit 09c5bc205f
4 changed files with 111 additions and 172 deletions

View File

@@ -2,7 +2,6 @@ import logging
import autogpt_libs.auth
import fastapi
import fastapi.responses
import backend.api.features.store.db as store_db
import backend.api.features.store.model as store_model
@@ -35,18 +34,10 @@ async def create_waitlist(
Returns:
WaitlistAdminResponse with the created waitlist details
"""
try:
waitlist = await store_db.create_waitlist_admin(
admin_user_id=user_id,
data=request,
)
return waitlist
except Exception as e:
logger.exception("Error creating waitlist: %s", e)
return fastapi.responses.JSONResponse(
status_code=500,
content={"detail": "An error occurred while creating the waitlist"},
)
return await store_db.create_waitlist_admin(
admin_user_id=user_id,
data=request,
)
@router.get(
@@ -61,14 +52,7 @@ async def list_waitlists():
Returns:
WaitlistAdminListResponse with all waitlists
"""
try:
return await store_db.get_waitlists_admin()
except Exception as e:
logger.exception("Error listing waitlists: %s", e)
return fastapi.responses.JSONResponse(
status_code=500,
content={"detail": "An error occurred while fetching waitlists"},
)
return await store_db.get_waitlists_admin()
@router.get(
@@ -88,20 +72,7 @@ async def get_waitlist(
Returns:
WaitlistAdminResponse with waitlist details
"""
try:
return await store_db.get_waitlist_admin(waitlist_id)
except ValueError:
logger.warning("Waitlist not found: %s", waitlist_id)
return fastapi.responses.JSONResponse(
status_code=404,
content={"detail": "Waitlist not found"},
)
except Exception as e:
logger.exception("Error fetching waitlist: %s", e)
return fastapi.responses.JSONResponse(
status_code=500,
content={"detail": "An error occurred while fetching the waitlist"},
)
return await store_db.get_waitlist_admin(waitlist_id)
@router.put(
@@ -123,20 +94,7 @@ async def update_waitlist(
Returns:
WaitlistAdminResponse with updated waitlist details
"""
try:
return await store_db.update_waitlist_admin(waitlist_id, request)
except ValueError:
logger.warning("Waitlist not found for update: %s", waitlist_id)
return fastapi.responses.JSONResponse(
status_code=404,
content={"detail": "Waitlist not found"},
)
except Exception as e:
logger.exception("Error updating waitlist: %s", e)
return fastapi.responses.JSONResponse(
status_code=500,
content={"detail": "An error occurred while updating the waitlist"},
)
return await store_db.update_waitlist_admin(waitlist_id, request)
@router.delete(
@@ -155,21 +113,8 @@ async def delete_waitlist(
Returns:
Success message
"""
try:
await store_db.delete_waitlist_admin(waitlist_id)
return {"message": "Waitlist deleted successfully"}
except ValueError:
logger.warning(f"Waitlist not found for deletion: {waitlist_id}")
return fastapi.responses.JSONResponse(
status_code=404,
content={"detail": "Waitlist not found"},
)
except Exception as e:
logger.exception("Error deleting waitlist: %s", e)
return fastapi.responses.JSONResponse(
status_code=500,
content={"detail": "An error occurred while deleting the waitlist"},
)
await store_db.delete_waitlist_admin(waitlist_id)
return {"message": "Waitlist deleted successfully"}
@router.get(
@@ -189,20 +134,7 @@ async def get_waitlist_signups(
Returns:
WaitlistSignupListResponse with all signups
"""
try:
return await store_db.get_waitlist_signups_admin(waitlist_id)
except ValueError:
logger.warning("Waitlist not found for signups: %s", waitlist_id)
return fastapi.responses.JSONResponse(
status_code=404,
content={"detail": "Waitlist not found"},
)
except Exception as e:
logger.exception("Error fetching waitlist signups: %s", e)
return fastapi.responses.JSONResponse(
status_code=500,
content={"detail": "An error occurred while fetching waitlist signups"},
)
return await store_db.get_waitlist_signups_admin(waitlist_id)
@router.post(
@@ -229,23 +161,4 @@ async def link_waitlist_to_listing(
Returns:
WaitlistAdminResponse with updated waitlist details
"""
try:
return await store_db.link_waitlist_to_listing_admin(
waitlist_id, store_listing_id
)
except ValueError:
logger.warning(
"Link failed - waitlist or listing not found: %s, %s",
waitlist_id,
store_listing_id,
)
return fastapi.responses.JSONResponse(
status_code=404,
content={"detail": "Waitlist or store listing not found"},
)
except Exception as e:
logger.exception("Error linking waitlist to listing: %s", e)
return fastapi.responses.JSONResponse(
status_code=500,
content={"detail": "An error occurred while linking the waitlist"},
)
return await store_db.link_waitlist_to_listing_admin(waitlist_id, store_listing_id)

View File

@@ -2046,11 +2046,11 @@ async def get_user_waitlist_memberships(user_id: str) -> list[str]:
try:
user = await prisma.models.User.prisma().find_unique(
where={"id": user_id},
include={"joinedWaitlists": True},
include={"JoinedWaitlists": True},
)
if not user or not user.joinedWaitlists:
if not user or not user.JoinedWaitlists:
return []
return [w.id for w in user.joinedWaitlists]
return [w.id for w in user.JoinedWaitlists]
except Exception as e:
logger.error(f"Error fetching user waitlist memberships: {e}")
raise DatabaseError("Failed to fetch waitlist memberships") from e
@@ -2072,7 +2072,7 @@ async def add_user_to_waitlist(
# Find the waitlist
waitlist = await prisma.models.WaitlistEntry.prisma().find_unique(
where={"id": waitlist_id},
include={"joinedUsers": True},
include={"JoinedUsers": True},
)
if not waitlist:
@@ -2089,7 +2089,7 @@ async def add_user_to_waitlist(
if user_id:
# Check if user already joined
joined_user_ids = [u.id for u in (waitlist.joinedUsers or [])]
joined_user_ids = [u.id for u in (waitlist.JoinedUsers or [])]
if user_id in joined_user_ids:
# Already joined - return waitlist info
logger.debug(f"User {user_id} already joined waitlist {waitlist_id}")
@@ -2097,7 +2097,7 @@ async def add_user_to_waitlist(
# Connect user to waitlist
await prisma.models.WaitlistEntry.prisma().update(
where={"id": waitlist_id},
data={"joinedUsers": {"connect": [{"id": user_id}]}},
data={"JoinedUsers": {"connect": [{"id": user_id}]}},
)
logger.info(f"User {user_id} joined waitlist {waitlist_id}")
@@ -2167,7 +2167,7 @@ def _waitlist_to_admin_response(
waitlist: prisma.models.WaitlistEntry,
) -> store_model.WaitlistAdminResponse:
"""Convert a WaitlistEntry to WaitlistAdminResponse."""
joined_count = len(waitlist.joinedUsers) if waitlist.joinedUsers else 0
joined_count = len(waitlist.JoinedUsers) if waitlist.JoinedUsers else 0
email_count = (
len(waitlist.unaffiliatedEmailUsers) if waitlist.unaffiliatedEmailUsers else 0
)
@@ -2213,7 +2213,7 @@ async def create_waitlist_admin(
owningUserId=admin_user_id,
status=prisma.enums.WaitlistExternalStatus.NOT_STARTED,
),
include={"joinedUsers": True},
include={"JoinedUsers": True},
)
return _waitlist_to_admin_response(waitlist)
@@ -2227,7 +2227,7 @@ async def get_waitlists_admin() -> store_model.WaitlistAdminListResponse:
try:
waitlists = await prisma.models.WaitlistEntry.prisma().find_many(
where=prisma.types.WaitlistEntryWhereInput(isDeleted=False),
include={"joinedUsers": True},
include={"JoinedUsers": True},
order={"createdAt": "desc"},
)
@@ -2247,7 +2247,7 @@ async def get_waitlist_admin(
try:
waitlist = await prisma.models.WaitlistEntry.prisma().find_unique(
where={"id": waitlist_id},
include={"joinedUsers": True},
include={"JoinedUsers": True},
)
if not waitlist:
@@ -2311,7 +2311,7 @@ async def update_waitlist_admin(
waitlist = await prisma.models.WaitlistEntry.prisma().update(
where={"id": waitlist_id},
data=prisma.types.WaitlistEntryUpdateInput(**update_data),
include={"joinedUsers": True},
include={"JoinedUsers": True},
)
# We already verified existence above, so this should never be None
@@ -2358,7 +2358,7 @@ async def get_waitlist_signups_admin(
try:
waitlist = await prisma.models.WaitlistEntry.prisma().find_unique(
where={"id": waitlist_id},
include={"joinedUsers": True},
include={"JoinedUsers": True},
)
if not waitlist:
@@ -2367,7 +2367,7 @@ async def get_waitlist_signups_admin(
signups: list[store_model.WaitlistSignup] = []
# Add user signups
for user in waitlist.joinedUsers or []:
for user in waitlist.JoinedUsers or []:
signups.append(
store_model.WaitlistSignup(
type="user",
@@ -2428,7 +2428,7 @@ async def link_waitlist_to_listing_admin(
updated_waitlist = await prisma.models.WaitlistEntry.prisma().update(
where={"id": waitlist_id},
data={"StoreListing": {"connect": {"id": store_listing_id}}},
include={"joinedUsers": True},
include={"JoinedUsers": True},
)
# We already verified existence above, so this should never be None
@@ -2473,7 +2473,7 @@ async def notify_waitlist_users_on_launch(
]
},
},
include={"joinedUsers": True},
include={"JoinedUsers": True},
)
if not waitlists:
@@ -2487,7 +2487,7 @@ async def notify_waitlist_users_on_launch(
for waitlist in waitlists:
# Track notification results for this waitlist
users_to_notify = waitlist.joinedUsers or []
users_to_notify = waitlist.JoinedUsers or []
failed_user_ids: list[str] = []
# Notify registered users

View File

@@ -73,8 +73,8 @@ model User {
OAuthRefreshTokens OAuthRefreshToken[]
// Waitlist relations
waitlistEntries WaitlistEntry[]
joinedWaitlists WaitlistEntry[] @relation("joinedWaitlists")
WaitlistEntries WaitlistEntry[]
JoinedWaitlists WaitlistEntry[] @relation("joinedWaitlists")
}
enum OnboardingStep {
@@ -993,7 +993,7 @@ model StoreListing {
// Relations
Versions StoreListingVersion[] @relation("ListingVersions")
waitlistEntries WaitlistEntry[]
WaitlistEntries WaitlistEntry[]
// Unique index on agentId to ensure only one listing per agent, regardless of number of versions the agent has.
@@unique([agentGraphId])
@@ -1158,7 +1158,7 @@ model WaitlistEntry {
//Waitlist specific fields
status WaitlistExternalStatus @default(NOT_STARTED)
votes Int @default(0) // Hide from frontend api
joinedUsers User[] @relation("joinedWaitlists")
JoinedUsers User[] @relation("joinedWaitlists")
// NOTE: DO NOT DOUBLE SEND TO THESE USERS, IF THEY HAVE SIGNED UP SINCE THEY MAY HAVE ALREADY RECEIVED AN EMAIL
// DOUBLE CHECK WHEN SENDING THAT THEY ARE NOT IN THE JOINED USERS LIST ALSO
unaffiliatedEmailUsers String[] @default([])

View File

@@ -2043,9 +2043,7 @@
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/backend__api__model__UploadFileResponse"
}
"schema": { "$ref": "#/components/schemas/UploadFileResponse" }
}
}
},
@@ -6864,34 +6862,6 @@
"summary": "Get waitlist IDs the current user has joined",
"description": "Returns list of waitlist IDs the authenticated user has joined.",
"operationId": "getV2Get waitlist ids the current user has joined",
"/api/workspace/files/upload": {
"post": {
"tags": ["workspace"],
"summary": "Upload file to workspace",
"description": "Upload a file to the user's workspace.\n\nFiles are stored in session-scoped paths when session_id is provided,\nso the agent's session-scoped tools can discover them automatically.",
"operationId": "postWorkspaceUpload file to workspace",
"security": [{ "HTTPBearerJWT": [] }],
"parameters": [
{
"name": "session_id",
"in": "query",
"required": false,
"schema": {
"anyOf": [{ "type": "string" }, { "type": "null" }],
"title": "Session Id"
}
}
],
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/Body_postWorkspaceUpload_file_to_workspace"
}
}
}
},
"responses": {
"200": {
"description": "Successful Response",
@@ -6901,7 +6871,6 @@
"items": { "type": "string" },
"type": "array",
"title": "Response Getv2Get Waitlist Ids The Current User Has Joined"
"$ref": "#/components/schemas/backend__api__features__workspace__routes__UploadFileResponse"
}
}
}
@@ -6942,6 +6911,67 @@
}
}
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/StoreWaitlistEntry" }
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/HTTPValidationError" }
}
}
}
}
}
},
"/api/workspace/files/upload": {
"post": {
"tags": ["workspace"],
"summary": "Upload file to workspace",
"description": "Upload a file to the user's workspace.\n\nFiles are stored in session-scoped paths when session_id is provided,\nso the agent's session-scoped tools can discover them automatically.",
"operationId": "postWorkspaceUpload file to workspace",
"security": [{ "HTTPBearerJWT": [] }],
"parameters": [
{
"name": "session_id",
"in": "query",
"required": false,
"schema": {
"anyOf": [{ "type": "string" }, { "type": "null" }],
"title": "Session Id"
}
}
],
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/Body_postWorkspaceUpload_file_to_workspace"
}
}
}
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/backend__api__features__workspace__routes__UploadFileResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/HTTP401NotAuthenticatedError"
},
"422": {
"description": "Validation Error",
@@ -6974,10 +7004,6 @@
"description": "Successful Response",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/StoreWaitlistEntry" }
}
}
},
"schema": { "$ref": "#/components/schemas/DeleteFileResponse" }
}
}
@@ -14339,6 +14365,24 @@
"required": ["timezone"],
"title": "UpdateTimezoneRequest"
},
"UploadFileResponse": {
"properties": {
"file_uri": { "type": "string", "title": "File Uri" },
"file_name": { "type": "string", "title": "File Name" },
"size": { "type": "integer", "title": "Size" },
"content_type": { "type": "string", "title": "Content Type" },
"expires_in_hours": { "type": "integer", "title": "Expires In Hours" }
},
"type": "object",
"required": [
"file_uri",
"file_name",
"size",
"content_type",
"expires_in_hours"
],
"title": "UploadFileResponse"
},
"UserHistoryResponse": {
"properties": {
"history": {
@@ -14876,24 +14920,6 @@
"type": "object",
"required": ["file_id", "name", "path", "mime_type", "size_bytes"],
"title": "UploadFileResponse"
},
"backend__api__model__UploadFileResponse": {
"properties": {
"file_uri": { "type": "string", "title": "File Uri" },
"file_name": { "type": "string", "title": "File Name" },
"size": { "type": "integer", "title": "Size" },
"content_type": { "type": "string", "title": "Content Type" },
"expires_in_hours": { "type": "integer", "title": "Expires In Hours" }
},
"type": "object",
"required": [
"file_uri",
"file_name",
"size",
"content_type",
"expires_in_hours"
],
"title": "UploadFileResponse"
}
},
"securitySchemes": {