Skip to content

Commit 703f5e1

Browse files
committed
last fixes
1 parent cd676c6 commit 703f5e1

File tree

11 files changed

+56
-100
lines changed

11 files changed

+56
-100
lines changed

backend/app/api/deps.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -123,18 +123,6 @@ def get_current_active_superuser_org(current_user: CurrentUserOrg) -> User:
123123
return current_user
124124

125125

126-
async def http_exception_handler(request: Request, exc: HTTPException):
127-
"""
128-
Global handler for HTTPException to return standardized response format.
129-
"""
130-
return JSONResponse(
131-
status_code=exc.status_code,
132-
content=APIResponse.failure_response(exc.detail).model_dump()
133-
# TEMPORARY: Keep "detail" for backward compatibility
134-
| {"detail": exc.detail},
135-
)
136-
137-
138126
def verify_user_project_organization(
139127
db: SessionDep,
140128
current_user: CurrentUserOrg,

backend/app/api/main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,6 @@
3333
api_router.include_router(users.router)
3434
api_router.include_router(utils.router)
3535

36+
3637
if settings.ENVIRONMENT == "local":
3738
api_router.include_router(private.router)

backend/app/api/routes/api_keys.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@ def create_key(
2727
"""
2828
Generate a new API key for the user's organization.
2929
"""
30-
validate_organization(session, organization_id)
30+
organization = validate_organization(session, organization_id)
31+
if not organization:
32+
raise HTTPException(404, "Organization not found")
3133

3234
existing_api_key = get_api_key_by_user_org(session, organization_id, user_id)
3335
if existing_api_key:
3436
raise HTTPException(
35-
status_code=400,
36-
detail="API Key already exists for this user and organization",
37+
400,
38+
"API Key already exists for this user and organization",
3739
)
3840
api_key = create_api_key(session, organization_id=organization_id, user_id=user_id)
3941
return APIResponse.success_response(api_key)
@@ -48,7 +50,9 @@ def list_keys(
4850
"""
4951
Retrieve all API keys for the user's organization.
5052
"""
51-
validate_organization(session, organization_id)
53+
organization = validate_organization(session, organization_id)
54+
if not organization:
55+
raise HTTPException(404, "Organization not found")
5256
api_keys = get_api_keys_by_organization(session, organization_id)
5357
return APIResponse.success_response(api_keys)
5458

@@ -64,7 +68,7 @@ def get_key(
6468
"""
6569
api_key = get_api_key(session, api_key_id)
6670
if not api_key:
67-
raise HTTPException(status_code=404, detail="API Key does not exist")
71+
raise HTTPException(404, "API Key does not exist")
6872

6973
return APIResponse.success_response(api_key)
7074

@@ -78,5 +82,11 @@ def revoke_key(
7882
"""
7983
Soft delete an API key (revoke access).
8084
"""
85+
api_key = get_api_key(session, api_key_id)
86+
87+
if not api_key:
88+
raise HTTPException(404, "API key not found or already deleted")
89+
8190
delete_api_key(session, api_key_id)
91+
8292
return APIResponse.success_response({"message": "API key revoked successfully"})

backend/app/api/routes/credentials.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
update_creds_for_org,
1212
remove_provider_credential,
1313
)
14+
from app.crud.organization import validate_organization
1415
from app.models import CredsCreate, CredsPublic, CredsUpdate
1516
from app.models.organization import Organization
1617
from app.models.project import Project
@@ -30,9 +31,7 @@
3031
)
3132
def create_new_credential(*, session: SessionDep, creds_in: CredsCreate):
3233
# Validate organization
33-
organization = session.get(Organization, creds_in.organization_id)
34-
if not organization:
35-
raise HTTPException(status_code=404, detail="Organization not found")
34+
validate_organization(session, creds_in.organization_id)
3635

3736
# Validate project if provided
3837
if creds_in.project_id:
@@ -65,7 +64,7 @@ def create_new_credential(*, session: SessionDep, creds_in: CredsCreate):
6564
# Create credentials
6665
new_creds = set_creds_for_org(session=session, creds_add=creds_in)
6766
if not new_creds:
68-
raise HTTPException(status_code=500, detail="Failed to create credentials")
67+
raise Exception(status_code=500, detail="Failed to create credentials")
6968

7069
return APIResponse.success_response([cred.to_public() for cred in new_creds])
7170

@@ -116,10 +115,7 @@ def read_provider_credential(
116115
description="Updates credentials for a specific organization and project combination. Can update specific provider credentials or add new providers. If project_id is provided in the update, credentials will be moved to that project. This endpoint requires superuser privileges.",
117116
)
118117
def update_credential(*, session: SessionDep, org_id: int, creds_in: CredsUpdate):
119-
organization = session.get(Organization, org_id)
120-
if not organization:
121-
raise HTTPException(status_code=404, detail="Organization not found")
122-
118+
validate_organization(session, org_id)
123119
if not creds_in or not creds_in.provider or not creds_in.credential:
124120
raise HTTPException(
125121
status_code=400, detail="Provider and credential must be provided"
@@ -139,19 +135,25 @@ def update_credential(*, session: SessionDep, org_id: int, creds_in: CredsUpdate
139135
dependencies=[Depends(get_current_active_superuser)],
140136
response_model=APIResponse[dict],
141137
summary="Delete specific provider credentials for an organization and project",
142-
description="Removes credentials for a specific provider while keeping other provider credentials intact. If project_id is provided, only removes credentials for that project. This endpoint requires superuser privileges.",
143138
)
144139
def delete_provider_credential(
145140
*, session: SessionDep, org_id: int, provider: str, project_id: int | None = None
146141
):
147142
provider_enum = validate_provider(provider)
148-
149-
updated_creds = remove_provider_credential(
143+
if not provider_enum:
144+
raise HTTPException(status_code=400, detail="Invalid provider")
145+
provider_creds = get_provider_credential(
150146
session=session,
151147
org_id=org_id,
152148
provider=provider_enum,
153149
project_id=project_id,
154150
)
151+
if provider_creds is None:
152+
raise HTTPException(status_code=404, detail="Provider credentials not found")
153+
154+
updated_creds = remove_provider_credential(
155+
session=session, org_id=org_id, provider=provider_enum, project_id=project_id
156+
)
155157

156158
return APIResponse.success_response(
157159
{"message": "Provider credentials removed successfully"}

backend/app/api/routes/responses.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,4 @@ async def responses_sync(
129129
),
130130
)
131131
except openai.OpenAIError as e:
132-
return ResponsesAPIResponse.failure_response(error=handle_openai_error(e))
132+
return Exception(error=handle_openai_error(e))

backend/app/api/routes/threads.py

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import openai
33
import requests
44

5-
from fastapi import APIRouter, BackgroundTasks, Depends
5+
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException
66
from openai import OpenAI
77
from sqlmodel import Session
88
from langfuse.decorators import observe, langfuse_context
@@ -229,9 +229,8 @@ async def threads(
229229
project_id=request.get("project_id"),
230230
)
231231
if not credentials or "api_key" not in credentials:
232-
return APIResponse.failure_response(
233-
error="OpenAI API key not configured for this organization."
234-
)
232+
raise HTTPException(404, "OpenAI API key not configured for this organization.")
233+
235234
client = OpenAI(api_key=credentials["api_key"])
236235

237236
langfuse_credentials = get_provider_credential(
@@ -241,9 +240,7 @@ async def threads(
241240
project_id=request.get("project_id"),
242241
)
243242
if not langfuse_credentials:
244-
return APIResponse.failure_response(
245-
error="LANGFUSE keys not configured for this organization."
246-
)
243+
raise HTTPException(404, "LANGFUSE keys not configured for this organization.")
247244

248245
langfuse_context.configure(
249246
secret_key=langfuse_credentials["secret_key"],
@@ -253,12 +250,11 @@ async def threads(
253250
# Validate thread
254251
is_valid, error_message = validate_thread(client, request.get("thread_id"))
255252
if not is_valid:
256-
return APIResponse.failure_response(error=error_message)
257-
253+
raise Exception(error_message)
258254
# Setup thread
259255
is_success, error_message = setup_thread(client, request)
260256
if not is_success:
261-
return APIResponse.failure_response(error=error_message)
257+
raise Exception(error_message)
262258

263259
# Send immediate response
264260
initial_response = APIResponse.success_response(
@@ -291,21 +287,20 @@ async def threads_sync(
291287
project_id=request.get("project_id"),
292288
)
293289
if not credentials or "api_key" not in credentials:
294-
return APIResponse.failure_response(
295-
error="OpenAI API key not configured for this organization."
290+
raise HTTPException(
291+
404, error="OpenAI API key not configured for this organization."
296292
)
297293

298294
client = OpenAI(api_key=credentials["api_key"])
299295

300296
# Validate thread
301297
is_valid, error_message = validate_thread(client, request.get("thread_id"))
302298
if not is_valid:
303-
return APIResponse.failure_response(error=error_message)
304-
299+
raise Exception(error_message)
305300
# Setup thread
306301
is_success, error_message = setup_thread(client, request)
307302
if not is_success:
308-
return APIResponse.failure_response(error=error_message)
303+
raise Exception(error_message)
309304

310305
try:
311306
# Process run
@@ -337,7 +332,7 @@ async def threads_sync(
337332
)
338333

339334
except openai.OpenAIError as e:
340-
return APIResponse.failure_response(error=handle_openai_error(e))
335+
raise Exception(error=handle_openai_error(e))
341336

342337

343338
@router.post("/threads/start")
@@ -355,7 +350,7 @@ async def start_thread(
355350

356351
is_success, error = setup_thread(client, request)
357352
if not is_success:
358-
return APIResponse.failure_response(error=error)
353+
raise Exception(error)
359354

360355
thread_id = request["thread_id"]
361356

@@ -394,7 +389,7 @@ async def get_thread(
394389
result = get_thread_result(db, thread_id)
395390

396391
if not result:
397-
return APIResponse.failure_response(error="Thread not found.")
392+
raise HTTPException(404, "thread not found")
398393

399394
status = result.status or ("success" if result.response else "processing")
400395

backend/app/crud/api_key.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,6 @@ def delete_api_key(session: Session, api_key_id: int) -> None:
108108
"""
109109
api_key = session.get(APIKey, api_key_id)
110110

111-
if not api_key or api_key.is_deleted:
112-
raise HTTPException(
113-
status_code=404, detail="API key not found or already deleted"
114-
)
115-
116111
api_key.is_deleted = True
117112
api_key.deleted_at = now()
118113
api_key.updated_at = now()

backend/app/crud/credentials.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from app.core.providers import (
88
validate_provider,
99
validate_provider_credentials,
10+
get_supported_providers,
1011
)
1112
from app.core.security import encrypt_credentials, decrypt_credentials
1213
from app.core.util import now
@@ -18,7 +19,7 @@ def set_creds_for_org(*, session: Session, creds_add: CredsCreate) -> List[Crede
1819
created_credentials = []
1920

2021
if not creds_add.credential:
21-
raise ValueError("No credentials provided")
22+
raise HTTPException(400, "No credentials provided")
2223

2324
for provider, credentials in creds_add.credential.items():
2425
# Validate provider and credentials
@@ -136,9 +137,10 @@ def update_creds_for_org(
136137
else True,
137138
)
138139
creds = session.exec(statement).first()
139-
140-
if not creds:
141-
raise ValueError(f"No credentials found for provider {creds_in.provider}")
140+
if creds is None:
141+
raise HTTPException(
142+
status_code=404, detail="Credentials not found for this provider"
143+
)
142144

143145
creds.credential = encrypted_credentials
144146
creds.updated_at = now()
@@ -149,9 +151,6 @@ def update_creds_for_org(
149151
return [creds]
150152

151153

152-
from sqlalchemy.exc import IntegrityError
153-
154-
155154
def remove_provider_credential(
156155
session: Session, org_id: int, provider: str, project_id: Optional[int] = None
157156
) -> Credential:
@@ -165,11 +164,6 @@ def remove_provider_credential(
165164
)
166165
creds = session.exec(statement).first()
167166

168-
if not creds:
169-
raise HTTPException(
170-
status_code=404, detail=f"Credentials not found for provider '{provider}'"
171-
)
172-
173167
# Soft delete
174168
creds.is_active = False
175169
creds.updated_at = now()

backend/app/crud/organization.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from typing import Any, Optional
22
from datetime import datetime, timezone
33
from sqlmodel import Session, select
4+
from fastapi import HTTPException
45

56
from app.models import Organization, OrganizationCreate
67
from app.core.util import now
@@ -36,9 +37,9 @@ def validate_organization(session: Session, org_id: int) -> Organization:
3637
"""
3738
organization = get_organization_by_id(session, org_id)
3839
if not organization:
39-
raise ValueError("Organization not found")
40+
raise HTTPException(404, "Organization not found")
4041

4142
if not organization.is_active:
42-
raise ValueError("Organization is not active")
43+
raise HTTPException("Organization is not active")
4344

4445
return organization

backend/app/tests/api/routes/test_creds.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,8 @@ def test_delete_provider_credential_not_found(
223223
)
224224

225225
assert response.status_code == 404
226-
assert (
227-
response.json()["error"]
228-
== f"Credentials not found for provider '{Provider.OPENAI}'"
229-
)
226+
print(response.json())
227+
assert response.json()["error"] == f"Provider credentials not found"
230228

231229

232230
def test_delete_all_credentials(

0 commit comments

Comments
 (0)