mirror of
https://github.com/onyx-dot-app/onyx.git
synced 2026-04-05 23:12:43 +00:00
Compare commits
1 Commits
cli/v0.2.0
...
nikg/std-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2cf2c8bbf8 |
@@ -3,7 +3,6 @@ from http import HTTPStatus
|
||||
|
||||
from fastapi import APIRouter
|
||||
from fastapi import Depends
|
||||
from fastapi import HTTPException
|
||||
from fastapi import Query
|
||||
from fastapi.responses import JSONResponse
|
||||
from sqlalchemy import select
|
||||
@@ -53,6 +52,8 @@ from onyx.db.permission_sync_attempt import (
|
||||
from onyx.db.permission_sync_attempt import (
|
||||
get_recent_doc_permission_sync_attempts_for_cc_pair,
|
||||
)
|
||||
from onyx.error_handling.error_codes import OnyxErrorCode
|
||||
from onyx.error_handling.exceptions import OnyxError
|
||||
from onyx.redis.redis_connector import RedisConnector
|
||||
from onyx.redis.redis_connector_utils import get_deletion_attempt_snapshot
|
||||
from onyx.redis.redis_pool import get_redis_client
|
||||
@@ -87,8 +88,9 @@ def get_cc_pair_index_attempts(
|
||||
cc_pair_id, db_session, user, get_editable=False
|
||||
)
|
||||
if not user_has_access:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="CC Pair not found for current user permissions"
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.NOT_FOUND,
|
||||
"CC Pair not found for current user permissions",
|
||||
)
|
||||
|
||||
total_count = count_index_attempts_for_cc_pair(
|
||||
@@ -123,8 +125,9 @@ def get_cc_pair_permission_sync_attempts(
|
||||
cc_pair_id, db_session, user, get_editable=False
|
||||
)
|
||||
if not user_has_access:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="CC Pair not found for current user permissions"
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.NOT_FOUND,
|
||||
"CC Pair not found for current user permissions",
|
||||
)
|
||||
|
||||
# Get all permission sync attempts for this cc pair
|
||||
@@ -160,8 +163,9 @@ def get_cc_pair_full_info(
|
||||
cc_pair_id, db_session, user, get_editable=False
|
||||
)
|
||||
if not cc_pair:
|
||||
raise HTTPException(
|
||||
status_code=404, detail="CC Pair not found for current user permissions"
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.NOT_FOUND,
|
||||
"CC Pair not found for current user permissions",
|
||||
)
|
||||
editable_cc_pair = get_connector_credential_pair_from_id_for_user(
|
||||
cc_pair_id, db_session, user, get_editable=True
|
||||
@@ -264,9 +268,9 @@ def update_cc_pair_status(
|
||||
)
|
||||
|
||||
if not cc_pair:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Connection not found for current user's permissions",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.NOT_FOUND,
|
||||
"Connection not found for current user's permissions",
|
||||
)
|
||||
|
||||
redis_connector = RedisConnector(tenant_id, cc_pair_id)
|
||||
@@ -339,8 +343,9 @@ def update_cc_pair_name(
|
||||
get_editable=True,
|
||||
)
|
||||
if not cc_pair:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="CC Pair not found for current user's permissions"
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.NOT_FOUND,
|
||||
"CC Pair not found for current user's permissions",
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -351,7 +356,7 @@ def update_cc_pair_name(
|
||||
)
|
||||
except IntegrityError:
|
||||
db_session.rollback()
|
||||
raise HTTPException(status_code=400, detail="Name must be unique")
|
||||
raise OnyxError(OnyxErrorCode.CONFLICT, "Name must be unique")
|
||||
|
||||
|
||||
@router.put("/admin/cc-pair/{cc_pair_id}/property")
|
||||
@@ -368,8 +373,9 @@ def update_cc_pair_property(
|
||||
get_editable=True,
|
||||
)
|
||||
if not cc_pair:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="CC Pair not found for current user's permissions"
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.NOT_FOUND,
|
||||
"CC Pair not found for current user's permissions",
|
||||
)
|
||||
|
||||
# Can we centralize logic for updating connector properties
|
||||
@@ -387,8 +393,9 @@ def update_cc_pair_property(
|
||||
|
||||
msg = "Pruning frequency updated successfully"
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=400, detail=f"Property name {update_request.name} is not valid."
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
f"Property name {update_request.name} is not valid.",
|
||||
)
|
||||
|
||||
return StatusResponse(success=True, message=msg, data=cc_pair_id)
|
||||
@@ -407,9 +414,9 @@ def get_cc_pair_last_pruned(
|
||||
get_editable=False,
|
||||
)
|
||||
if not cc_pair:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="cc_pair not found for current user's permissions",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.NOT_FOUND,
|
||||
"cc_pair not found for current user's permissions",
|
||||
)
|
||||
|
||||
return cc_pair.last_pruned
|
||||
@@ -431,19 +438,16 @@ def prune_cc_pair(
|
||||
get_editable=False,
|
||||
)
|
||||
if not cc_pair:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Connection not found for current user's permissions",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.NOT_FOUND,
|
||||
"Connection not found for current user's permissions",
|
||||
)
|
||||
|
||||
r = get_redis_client()
|
||||
|
||||
redis_connector = RedisConnector(tenant_id, cc_pair_id)
|
||||
if redis_connector.prune.fenced:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.CONFLICT,
|
||||
detail="Pruning task already in progress.",
|
||||
)
|
||||
raise OnyxError(OnyxErrorCode.CONFLICT, "Pruning task already in progress.")
|
||||
|
||||
logger.info(
|
||||
f"Pruning cc_pair: cc_pair={cc_pair_id} "
|
||||
@@ -455,10 +459,7 @@ def prune_cc_pair(
|
||||
client_app, cc_pair, db_session, r, tenant_id
|
||||
)
|
||||
if not payload_id:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
||||
detail="Pruning task creation failed.",
|
||||
)
|
||||
raise OnyxError(OnyxErrorCode.INTERNAL_ERROR, "Pruning task creation failed.")
|
||||
|
||||
logger.info(f"Pruning queued: cc_pair={cc_pair.id} id={payload_id}")
|
||||
|
||||
@@ -588,20 +589,21 @@ def associate_credential_to_connector(
|
||||
delete_connector(db_session, connector_id)
|
||||
db_session.commit()
|
||||
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Connector validation error: " + str(e)
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.CONNECTOR_VALIDATION_FAILED,
|
||||
"Connector validation error: " + str(e),
|
||||
)
|
||||
except IntegrityError as e:
|
||||
logger.error(f"IntegrityError: {e}")
|
||||
delete_connector(db_session, connector_id)
|
||||
db_session.commit()
|
||||
|
||||
raise HTTPException(status_code=400, detail="Name must be unique")
|
||||
raise OnyxError(OnyxErrorCode.CONFLICT, "Name must be unique")
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"Unexpected error: {e}")
|
||||
|
||||
raise HTTPException(status_code=500, detail="Unexpected error")
|
||||
raise OnyxError(OnyxErrorCode.INTERNAL_ERROR, "Unexpected error")
|
||||
|
||||
|
||||
@router.delete(
|
||||
|
||||
@@ -11,7 +11,6 @@ from fastapi import APIRouter
|
||||
from fastapi import Depends
|
||||
from fastapi import File
|
||||
from fastapi import Form
|
||||
from fastapi import HTTPException
|
||||
from fastapi import Query
|
||||
from fastapi import Request
|
||||
from fastapi import Response
|
||||
@@ -115,6 +114,8 @@ from onyx.db.models import IndexAttempt
|
||||
from onyx.db.models import IndexingStatus
|
||||
from onyx.db.models import User
|
||||
from onyx.db.models import UserRole
|
||||
from onyx.error_handling.error_codes import OnyxErrorCode
|
||||
from onyx.error_handling.exceptions import OnyxError
|
||||
from onyx.file_processing.file_types import PLAIN_TEXT_MIME_TYPE
|
||||
from onyx.file_processing.file_types import WORD_PROCESSING_MIME_TYPE
|
||||
from onyx.file_store.file_store import FileStore
|
||||
@@ -180,7 +181,7 @@ def check_google_app_gmail_credentials_exist(
|
||||
try:
|
||||
return {"client_id": get_google_app_cred(DocumentSource.GMAIL).web.client_id}
|
||||
except KvKeyNotFoundError:
|
||||
raise HTTPException(status_code=404, detail="Google App Credentials not found")
|
||||
raise OnyxError(OnyxErrorCode.NOT_FOUND, "Google App Credentials not found")
|
||||
|
||||
|
||||
@router.put("/admin/connector/gmail/app-credential")
|
||||
@@ -190,7 +191,7 @@ def upsert_google_app_gmail_credentials(
|
||||
try:
|
||||
upsert_google_app_cred(app_credentials, DocumentSource.GMAIL)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
return StatusResponse(
|
||||
success=True, message="Successfully saved Google App Credentials"
|
||||
@@ -206,7 +207,7 @@ def delete_google_app_gmail_credentials(
|
||||
delete_google_app_cred(DocumentSource.GMAIL)
|
||||
cleanup_gmail_credentials(db_session=db_session)
|
||||
except KvKeyNotFoundError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
return StatusResponse(
|
||||
success=True, message="Successfully deleted Google App Credentials"
|
||||
@@ -222,7 +223,7 @@ def check_google_app_credentials_exist(
|
||||
"client_id": get_google_app_cred(DocumentSource.GOOGLE_DRIVE).web.client_id
|
||||
}
|
||||
except KvKeyNotFoundError:
|
||||
raise HTTPException(status_code=404, detail="Google App Credentials not found")
|
||||
raise OnyxError(OnyxErrorCode.NOT_FOUND, "Google App Credentials not found")
|
||||
|
||||
|
||||
@router.put("/admin/connector/google-drive/app-credential")
|
||||
@@ -232,7 +233,7 @@ def upsert_google_app_credentials(
|
||||
try:
|
||||
upsert_google_app_cred(app_credentials, DocumentSource.GOOGLE_DRIVE)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
return StatusResponse(
|
||||
success=True, message="Successfully saved Google App Credentials"
|
||||
@@ -248,7 +249,7 @@ def delete_google_app_credentials(
|
||||
delete_google_app_cred(DocumentSource.GOOGLE_DRIVE)
|
||||
cleanup_google_drive_credentials(db_session=db_session)
|
||||
except KvKeyNotFoundError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
return StatusResponse(
|
||||
success=True, message="Successfully deleted Google App Credentials"
|
||||
@@ -266,9 +267,7 @@ def check_google_service_gmail_account_key_exist(
|
||||
).client_email
|
||||
}
|
||||
except KvKeyNotFoundError:
|
||||
raise HTTPException(
|
||||
status_code=404, detail="Google Service Account Key not found"
|
||||
)
|
||||
raise OnyxError(OnyxErrorCode.NOT_FOUND, "Google Service Account Key not found")
|
||||
|
||||
|
||||
@router.put("/admin/connector/gmail/service-account-key")
|
||||
@@ -278,7 +277,7 @@ def upsert_google_service_gmail_account_key(
|
||||
try:
|
||||
upsert_service_account_key(service_account_key, DocumentSource.GMAIL)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
return StatusResponse(
|
||||
success=True, message="Successfully saved Google Service Account Key"
|
||||
@@ -294,7 +293,7 @@ def delete_google_service_gmail_account_key(
|
||||
delete_service_account_key(DocumentSource.GMAIL)
|
||||
cleanup_gmail_credentials(db_session=db_session)
|
||||
except KvKeyNotFoundError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
return StatusResponse(
|
||||
success=True, message="Successfully deleted Google Service Account Key"
|
||||
@@ -312,9 +311,7 @@ def check_google_service_account_key_exist(
|
||||
).client_email
|
||||
}
|
||||
except KvKeyNotFoundError:
|
||||
raise HTTPException(
|
||||
status_code=404, detail="Google Service Account Key not found"
|
||||
)
|
||||
raise OnyxError(OnyxErrorCode.NOT_FOUND, "Google Service Account Key not found")
|
||||
|
||||
|
||||
@router.put("/admin/connector/google-drive/service-account-key")
|
||||
@@ -324,7 +321,7 @@ def upsert_google_service_account_key(
|
||||
try:
|
||||
upsert_service_account_key(service_account_key, DocumentSource.GOOGLE_DRIVE)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
return StatusResponse(
|
||||
success=True, message="Successfully saved Google Service Account Key"
|
||||
@@ -340,7 +337,7 @@ def delete_google_service_account_key(
|
||||
delete_service_account_key(DocumentSource.GOOGLE_DRIVE)
|
||||
cleanup_google_drive_credentials(db_session=db_session)
|
||||
except KvKeyNotFoundError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
return StatusResponse(
|
||||
success=True, message="Successfully deleted Google Service Account Key"
|
||||
@@ -363,7 +360,7 @@ def upsert_service_account_credential(
|
||||
name="Service Account (uploaded)",
|
||||
)
|
||||
except KvKeyNotFoundError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
# first delete all existing service account credentials
|
||||
delete_service_account_credentials(user, db_session, DocumentSource.GOOGLE_DRIVE)
|
||||
@@ -389,7 +386,7 @@ def upsert_gmail_service_account_credential(
|
||||
primary_admin_email=service_account_credential_request.google_primary_admin,
|
||||
)
|
||||
except KvKeyNotFoundError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
# first delete all existing service account credentials
|
||||
delete_service_account_credentials(user, db_session, DocumentSource.GMAIL)
|
||||
@@ -440,9 +437,9 @@ def save_zip_metadata_to_file_store(
|
||||
json.loads(metadata_bytes)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.warning(f"Unable to load {ONYX_METADATA_FILENAME}: {e}")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Unable to load {ONYX_METADATA_FILENAME}: {e}",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
f"Unable to load {ONYX_METADATA_FILENAME}: {e}",
|
||||
)
|
||||
|
||||
# Save to file store
|
||||
@@ -500,7 +497,7 @@ def upload_files(
|
||||
|
||||
if is_zip_file(file):
|
||||
if seen_zip:
|
||||
raise HTTPException(status_code=400, detail=SEEN_ZIP_DETAIL)
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, SEEN_ZIP_DETAIL)
|
||||
seen_zip = True
|
||||
with zipfile.ZipFile(file.file, "r") as zf:
|
||||
zip_metadata_file_id = save_zip_metadata_to_file_store(
|
||||
@@ -554,7 +551,7 @@ def upload_files(
|
||||
deduped_file_names.append(file.filename)
|
||||
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
return FileUploadResponse(
|
||||
file_paths=deduped_file_paths,
|
||||
file_names=deduped_file_names,
|
||||
@@ -581,9 +578,9 @@ def _fetch_and_check_file_connector_cc_pair_permissions(
|
||||
) -> ConnectorCredentialPair:
|
||||
cc_pair = fetch_connector_credential_pair_for_connector(db_session, connector_id)
|
||||
if cc_pair is None:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="No Connector-Credential Pair found for this connector",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.NOT_FOUND,
|
||||
"No Connector-Credential Pair found for this connector",
|
||||
)
|
||||
|
||||
has_requested_access = verify_user_has_access_to_cc_pair(
|
||||
@@ -604,9 +601,9 @@ def _fetch_and_check_file_connector_cc_pair_permissions(
|
||||
):
|
||||
return cc_pair
|
||||
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail="Access denied. User cannot manage files for this connector.",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.UNAUTHORIZED,
|
||||
"Access denied. User cannot manage files for this connector.",
|
||||
)
|
||||
|
||||
|
||||
@@ -627,11 +624,12 @@ def list_connector_files(
|
||||
"""List all files in a file connector."""
|
||||
connector = fetch_connector_by_id(connector_id, db_session)
|
||||
if connector is None:
|
||||
raise HTTPException(status_code=404, detail="Connector not found")
|
||||
raise OnyxError(OnyxErrorCode.CONNECTOR_NOT_FOUND, "Connector not found")
|
||||
|
||||
if connector.source != DocumentSource.FILE:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="This endpoint only works with file connectors"
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
"This endpoint only works with file connectors",
|
||||
)
|
||||
|
||||
_ = _fetch_and_check_file_connector_cc_pair_permissions(
|
||||
@@ -700,11 +698,12 @@ def update_connector_files(
|
||||
files = files or []
|
||||
connector = fetch_connector_by_id(connector_id, db_session)
|
||||
if connector is None:
|
||||
raise HTTPException(status_code=404, detail="Connector not found")
|
||||
raise OnyxError(OnyxErrorCode.CONNECTOR_NOT_FOUND, "Connector not found")
|
||||
|
||||
if connector.source != DocumentSource.FILE:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="This endpoint only works with file connectors"
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
"This endpoint only works with file connectors",
|
||||
)
|
||||
|
||||
# Get the connector-credential pair for indexing/pruning triggers
|
||||
@@ -720,12 +719,14 @@ def update_connector_files(
|
||||
try:
|
||||
file_ids_list = json.loads(file_ids_to_remove)
|
||||
except json.JSONDecodeError:
|
||||
raise HTTPException(status_code=400, detail="Invalid file_ids_to_remove format")
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR, "Invalid file_ids_to_remove format"
|
||||
)
|
||||
|
||||
if not isinstance(file_ids_list, list):
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="file_ids_to_remove must be a JSON-encoded list",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
"file_ids_to_remove must be a JSON-encoded list",
|
||||
)
|
||||
|
||||
# Get current connector config
|
||||
@@ -750,9 +751,9 @@ def update_connector_files(
|
||||
current_zip_metadata = loaded_metadata
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to load existing metadata file: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Failed to load existing connector metadata file",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.INTERNAL_ERROR,
|
||||
"Failed to load existing connector metadata file",
|
||||
)
|
||||
|
||||
# Upload new files if any
|
||||
@@ -807,9 +808,9 @@ def update_connector_files(
|
||||
|
||||
# Validate that at least one file remains
|
||||
if not final_file_locations:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Cannot remove all files from connector. At least one file must remain.",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
"Cannot remove all files from connector. At least one file must remain.",
|
||||
)
|
||||
|
||||
# Merge and filter metadata (remove metadata for deleted files)
|
||||
@@ -852,8 +853,8 @@ def update_connector_files(
|
||||
|
||||
updated_connector = update_connector(connector_id, connector_base, db_session)
|
||||
if updated_connector is None:
|
||||
raise HTTPException(
|
||||
status_code=500, detail="Failed to update connector configuration"
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.INTERNAL_ERROR, "Failed to update connector configuration"
|
||||
)
|
||||
|
||||
# Trigger re-indexing for new files and pruning for removed files
|
||||
@@ -1541,7 +1542,7 @@ def create_connector_from_model(
|
||||
return connector_response
|
||||
except ValueError as e:
|
||||
logger.error(f"Error creating connector: {e}")
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
|
||||
@router.post("/admin/connector-with-mock-credential")
|
||||
@@ -1619,11 +1620,12 @@ def create_connector_with_mock_credential(
|
||||
return response
|
||||
|
||||
except ConnectorValidationError as e:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Connector validation error: " + str(e)
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.CONNECTOR_VALIDATION_FAILED,
|
||||
"Connector validation error: " + str(e),
|
||||
)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
|
||||
@router.patch("/admin/connector/{connector_id}", tags=PUBLIC_API_TAGS)
|
||||
@@ -1648,12 +1650,13 @@ def update_connector_from_model(
|
||||
)
|
||||
connector_base = connector_data.to_connector_base()
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
updated_connector = update_connector(connector_id, connector_base, db_session)
|
||||
if updated_connector is None:
|
||||
raise HTTPException(
|
||||
status_code=404, detail=f"Connector {connector_id} does not exist"
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.CONNECTOR_NOT_FOUND,
|
||||
f"Connector {connector_id} does not exist",
|
||||
)
|
||||
|
||||
return ConnectorSnapshot(
|
||||
@@ -1690,7 +1693,7 @@ def delete_connector_by_id(
|
||||
connector_id=connector_id,
|
||||
)
|
||||
except AssertionError:
|
||||
raise HTTPException(status_code=400, detail="Connector is not deletable")
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, "Connector is not deletable")
|
||||
|
||||
|
||||
@router.post("/admin/connector/run-once", tags=PUBLIC_API_TAGS)
|
||||
@@ -1711,9 +1714,9 @@ def connector_run_once(
|
||||
run_info.connector_id, db_session
|
||||
)
|
||||
except ValueError:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Connector by id {connector_id} does not exist.",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.CONNECTOR_NOT_FOUND,
|
||||
f"Connector by id {connector_id} does not exist.",
|
||||
)
|
||||
|
||||
if not specified_credential_ids:
|
||||
@@ -1722,15 +1725,15 @@ def connector_run_once(
|
||||
if set(specified_credential_ids).issubset(set(possible_credential_ids)):
|
||||
credential_ids = specified_credential_ids
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Not all specified credentials are associated with connector",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
"Not all specified credentials are associated with connector",
|
||||
)
|
||||
|
||||
if not credential_ids:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Connector has no valid credentials, cannot create index attempts.",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
"Connector has no valid credentials, cannot create index attempts.",
|
||||
)
|
||||
try:
|
||||
num_triggers = trigger_indexing_for_cc_pair(
|
||||
@@ -1741,7 +1744,7 @@ def connector_run_once(
|
||||
db_session,
|
||||
)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, str(e))
|
||||
|
||||
logger.info("connector_run_once - running check_for_indexing")
|
||||
|
||||
@@ -1795,8 +1798,8 @@ def gmail_callback(
|
||||
) -> StatusResponse:
|
||||
credential_id_cookie = request.cookies.get(_GMAIL_CREDENTIAL_ID_COOKIE_NAME)
|
||||
if credential_id_cookie is None or not credential_id_cookie.isdigit():
|
||||
raise HTTPException(
|
||||
status_code=401, detail="Request did not pass CSRF verification."
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.CSRF_FAILURE, "Request did not pass CSRF verification."
|
||||
)
|
||||
credential_id = int(credential_id_cookie)
|
||||
verify_csrf(credential_id, callback.state)
|
||||
@@ -1809,8 +1812,8 @@ def gmail_callback(
|
||||
GoogleOAuthAuthenticationMethod.UPLOADED,
|
||||
)
|
||||
if credentials is None:
|
||||
raise HTTPException(
|
||||
status_code=500, detail="Unable to fetch Gmail access tokens"
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.INTERNAL_ERROR, "Unable to fetch Gmail access tokens"
|
||||
)
|
||||
|
||||
return StatusResponse(success=True, message="Updated Gmail access tokens")
|
||||
@@ -1825,8 +1828,8 @@ def google_drive_callback(
|
||||
) -> StatusResponse:
|
||||
credential_id_cookie = request.cookies.get(_GOOGLE_DRIVE_CREDENTIAL_ID_COOKIE_NAME)
|
||||
if credential_id_cookie is None or not credential_id_cookie.isdigit():
|
||||
raise HTTPException(
|
||||
status_code=401, detail="Request did not pass CSRF verification."
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.CSRF_FAILURE, "Request did not pass CSRF verification."
|
||||
)
|
||||
credential_id = int(credential_id_cookie)
|
||||
verify_csrf(credential_id, callback.state)
|
||||
@@ -1840,8 +1843,9 @@ def google_drive_callback(
|
||||
GoogleOAuthAuthenticationMethod.UPLOADED,
|
||||
)
|
||||
if credentials is None:
|
||||
raise HTTPException(
|
||||
status_code=500, detail="Unable to fetch Google Drive access tokens"
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.INTERNAL_ERROR,
|
||||
"Unable to fetch Google Drive access tokens",
|
||||
)
|
||||
|
||||
return StatusResponse(success=True, message="Updated Google Drive access tokens")
|
||||
@@ -1881,8 +1885,9 @@ def get_connector_by_id(
|
||||
) -> ConnectorSnapshot | StatusResponse[int]:
|
||||
connector = fetch_connector_by_id(connector_id, db_session)
|
||||
if connector is None:
|
||||
raise HTTPException(
|
||||
status_code=404, detail=f"Connector {connector_id} does not exist"
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.CONNECTOR_NOT_FOUND,
|
||||
f"Connector {connector_id} does not exist",
|
||||
)
|
||||
|
||||
return ConnectorSnapshot(
|
||||
@@ -1915,7 +1920,9 @@ def submit_connector_request(
|
||||
connector_name = request_data.connector_name.strip()
|
||||
|
||||
if not connector_name:
|
||||
raise HTTPException(status_code=400, detail="Connector name cannot be empty")
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR, "Connector name cannot be empty"
|
||||
)
|
||||
|
||||
# Get user identifier for telemetry
|
||||
user_email = user.email if user else None
|
||||
|
||||
@@ -4,7 +4,6 @@ from fastapi import APIRouter
|
||||
from fastapi import Depends
|
||||
from fastapi import File
|
||||
from fastapi import Form
|
||||
from fastapi import HTTPException
|
||||
from fastapi import Query
|
||||
from fastapi import UploadFile
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -28,6 +27,8 @@ from onyx.db.credentials import update_credential
|
||||
from onyx.db.engine.sql_engine import get_session
|
||||
from onyx.db.models import DocumentSource
|
||||
from onyx.db.models import User
|
||||
from onyx.error_handling.error_codes import OnyxErrorCode
|
||||
from onyx.error_handling.exceptions import OnyxError
|
||||
from onyx.server.documents.models import CredentialBase
|
||||
from onyx.server.documents.models import CredentialDataUpdateRequest
|
||||
from onyx.server.documents.models import CredentialSnapshot
|
||||
@@ -176,18 +177,18 @@ def create_credential_with_private_key(
|
||||
try:
|
||||
credential_data = json.loads(credential_json)
|
||||
except json.JSONDecodeError as e:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Invalid JSON in credential_json: {str(e)}",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
f"Invalid JSON in credential_json: {str(e)}",
|
||||
)
|
||||
|
||||
private_key_processor: ProcessPrivateKeyFileProtocol | None = (
|
||||
FILE_TYPE_TO_FILE_PROCESSOR.get(PrivateKeyFileTypes(type_definition_key))
|
||||
)
|
||||
if private_key_processor is None:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Invalid type definition key for private key file",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
"Invalid type definition key for private key file",
|
||||
)
|
||||
private_key_content: str = private_key_processor(uploaded_file)
|
||||
|
||||
@@ -251,9 +252,9 @@ def get_credential_by_id(
|
||||
get_editable=False,
|
||||
)
|
||||
if credential is None:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail=f"Credential {credential_id} does not exist or does not belong to user",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.CREDENTIAL_NOT_FOUND,
|
||||
f"Credential {credential_id} does not exist or does not belong to user",
|
||||
)
|
||||
|
||||
return CredentialSnapshot.from_credential_db_model(credential)
|
||||
@@ -275,9 +276,9 @@ def update_credential_data(
|
||||
)
|
||||
|
||||
if credential is None:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail=f"Credential {credential_id} does not exist or does not belong to user",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.CREDENTIAL_NOT_FOUND,
|
||||
f"Credential {credential_id} does not exist or does not belong to user",
|
||||
)
|
||||
|
||||
return CredentialSnapshot.from_credential_db_model(credential)
|
||||
@@ -297,18 +298,18 @@ def update_credential_private_key(
|
||||
try:
|
||||
credential_data = json.loads(credential_json)
|
||||
except json.JSONDecodeError as e:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Invalid JSON in credential_json: {str(e)}",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
f"Invalid JSON in credential_json: {str(e)}",
|
||||
)
|
||||
|
||||
private_key_processor: ProcessPrivateKeyFileProtocol | None = (
|
||||
FILE_TYPE_TO_FILE_PROCESSOR.get(PrivateKeyFileTypes(type_definition_key))
|
||||
)
|
||||
if private_key_processor is None:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Invalid type definition key for private key file",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
"Invalid type definition key for private key file",
|
||||
)
|
||||
private_key_content: str = private_key_processor(uploaded_file)
|
||||
credential_data[field_key] = private_key_content
|
||||
@@ -322,9 +323,9 @@ def update_credential_private_key(
|
||||
)
|
||||
|
||||
if credential is None:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail=f"Credential {credential_id} does not exist or does not belong to user",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.CREDENTIAL_NOT_FOUND,
|
||||
f"Credential {credential_id} does not exist or does not belong to user",
|
||||
)
|
||||
|
||||
return CredentialSnapshot.from_credential_db_model(credential)
|
||||
@@ -341,9 +342,9 @@ def update_credential_from_model(
|
||||
credential_id, credential_data, user, db_session
|
||||
)
|
||||
if updated_credential is None:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail=f"Credential {credential_id} does not exist or does not belong to user",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.CREDENTIAL_NOT_FOUND,
|
||||
f"Credential {credential_id} does not exist or does not belong to user",
|
||||
)
|
||||
|
||||
# Get credential_json value - use masking for API responses
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from fastapi import APIRouter
|
||||
from fastapi import Depends
|
||||
from fastapi import HTTPException
|
||||
from fastapi import Query
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -14,6 +13,8 @@ from onyx.db.models import User
|
||||
from onyx.db.search_settings import get_current_search_settings
|
||||
from onyx.document_index.factory import get_default_document_index
|
||||
from onyx.document_index.interfaces import VespaChunkRequest
|
||||
from onyx.error_handling.error_codes import OnyxErrorCode
|
||||
from onyx.error_handling.exceptions import OnyxError
|
||||
from onyx.natural_language_processing.utils import get_tokenizer
|
||||
from onyx.prompts.prompt_utils import build_doc_context_str
|
||||
from onyx.server.documents.models import ChunkInfo
|
||||
@@ -43,7 +44,7 @@ def get_document_info(
|
||||
)
|
||||
|
||||
if not inference_chunks:
|
||||
raise HTTPException(status_code=404, detail="Document not found")
|
||||
raise OnyxError(OnyxErrorCode.DOCUMENT_NOT_FOUND, "Document not found")
|
||||
|
||||
contents = [chunk.content for chunk in inference_chunks]
|
||||
|
||||
@@ -95,7 +96,7 @@ def get_chunk_info(
|
||||
)
|
||||
|
||||
if not inference_chunks:
|
||||
raise HTTPException(status_code=404, detail="Chunk not found")
|
||||
raise OnyxError(OnyxErrorCode.NOT_FOUND, "Chunk not found")
|
||||
|
||||
chunk_content = inference_chunks[0].content
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@ import base64
|
||||
from enum import Enum
|
||||
from typing import Protocol
|
||||
|
||||
from fastapi import HTTPException
|
||||
from fastapi import UploadFile
|
||||
|
||||
from onyx.error_handling.error_codes import OnyxErrorCode
|
||||
from onyx.error_handling.exceptions import OnyxError
|
||||
from onyx.server.documents.document_utils import validate_pkcs12_content
|
||||
|
||||
|
||||
@@ -31,8 +32,9 @@ def process_sharepoint_private_key_file(file: UploadFile) -> str:
|
||||
"""
|
||||
# First check file extension (basic filter)
|
||||
if not (file.filename and file.filename.lower().endswith(".pfx")):
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Invalid file type. Only .pfx files are supported."
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
"Invalid file type. Only .pfx files are supported.",
|
||||
)
|
||||
|
||||
# Read file content for validation and processing
|
||||
@@ -40,9 +42,9 @@ def process_sharepoint_private_key_file(file: UploadFile) -> str:
|
||||
|
||||
# Validate file content to prevent extension spoofing attacks
|
||||
if not validate_pkcs12_content(private_key_bytes):
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Invalid file content. The uploaded file does not appear to be a valid PKCS#12 (.pfx) file.",
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
"Invalid file content. The uploaded file does not appear to be a valid PKCS#12 (.pfx) file.",
|
||||
)
|
||||
|
||||
# Convert to base64 if validation passes
|
||||
|
||||
@@ -5,7 +5,6 @@ from typing import cast
|
||||
|
||||
from fastapi import APIRouter
|
||||
from fastapi import Depends
|
||||
from fastapi import HTTPException
|
||||
from fastapi import Query
|
||||
from fastapi import Request
|
||||
from pydantic import BaseModel
|
||||
@@ -19,6 +18,8 @@ from onyx.connectors.interfaces import OAuthConnector
|
||||
from onyx.db.credentials import create_credential
|
||||
from onyx.db.engine.sql_engine import get_session
|
||||
from onyx.db.models import User
|
||||
from onyx.error_handling.error_codes import OnyxErrorCode
|
||||
from onyx.error_handling.exceptions import OnyxError
|
||||
from onyx.redis.redis_pool import get_redis_client
|
||||
from onyx.server.documents.models import CredentialBase
|
||||
from onyx.utils.logger import setup_logger
|
||||
@@ -69,12 +70,10 @@ def _get_additional_kwargs(
|
||||
# validate
|
||||
connector_cls.AdditionalOauthKwargs(**additional_kwargs_dict)
|
||||
except ValidationError:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=(
|
||||
f"Invalid additional kwargs. Got {additional_kwargs_dict}, expected "
|
||||
f"{connector_cls.AdditionalOauthKwargs.model_json_schema()}"
|
||||
),
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR,
|
||||
f"Invalid additional kwargs. Got {additional_kwargs_dict}, expected "
|
||||
f"{connector_cls.AdditionalOauthKwargs.model_json_schema()}",
|
||||
)
|
||||
|
||||
return additional_kwargs_dict
|
||||
@@ -97,7 +96,9 @@ def oauth_authorize(
|
||||
oauth_connectors = _discover_oauth_connectors()
|
||||
|
||||
if source not in oauth_connectors:
|
||||
raise HTTPException(status_code=400, detail=f"Unknown OAuth source: {source}")
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR, f"Unknown OAuth source: {source}"
|
||||
)
|
||||
|
||||
connector_cls = oauth_connectors[source]
|
||||
base_url = WEB_DOMAIN
|
||||
@@ -147,7 +148,9 @@ def oauth_callback(
|
||||
oauth_connectors = _discover_oauth_connectors()
|
||||
|
||||
if source not in oauth_connectors:
|
||||
raise HTTPException(status_code=400, detail=f"Unknown OAuth source: {source}")
|
||||
raise OnyxError(
|
||||
OnyxErrorCode.VALIDATION_ERROR, f"Unknown OAuth source: {source}"
|
||||
)
|
||||
|
||||
connector_cls = oauth_connectors[source]
|
||||
|
||||
@@ -157,7 +160,7 @@ def oauth_callback(
|
||||
bytes, redis_client.get(_OAUTH_STATE_KEY_FMT.format(state=state))
|
||||
)
|
||||
if not oauth_state_bytes:
|
||||
raise HTTPException(status_code=400, detail="Invalid OAuth state")
|
||||
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, "Invalid OAuth state")
|
||||
oauth_state = json.loads(oauth_state_bytes.decode("utf-8"))
|
||||
|
||||
desired_return_url = cast(str, oauth_state[_DESIRED_RETURN_URL_KEY])
|
||||
|
||||
Reference in New Issue
Block a user