diff --git a/backend/danswer/auth/users.py b/backend/danswer/auth/users.py index cf3de018f..84f9d2791 100644 --- a/backend/danswer/auth/users.py +++ b/backend/danswer/auth/users.py @@ -87,6 +87,7 @@ from danswer.db.models import AccessToken from danswer.db.models import OAuthAccount from danswer.db.models import User from danswer.db.users import get_user_by_email +from danswer.server.utils import BasicAuthenticationError from danswer.utils.logger import setup_logger from danswer.utils.telemetry import optional_telemetry from danswer.utils.telemetry import RecordType @@ -99,11 +100,6 @@ from shared_configs.contextvars import CURRENT_TENANT_ID_CONTEXTVAR logger = setup_logger() -class BasicAuthenticationError(HTTPException): - def __init__(self, detail: str): - super().__init__(status_code=status.HTTP_403_FORBIDDEN, detail=detail) - - def is_user_admin(user: User | None) -> bool: if AUTH_TYPE == AuthType.DISABLED: return True diff --git a/backend/danswer/db/engine.py b/backend/danswer/db/engine.py index 5d4753e13..8ad8eca7a 100644 --- a/backend/danswer/db/engine.py +++ b/backend/danswer/db/engine.py @@ -37,6 +37,7 @@ from danswer.configs.app_configs import POSTGRES_PORT from danswer.configs.app_configs import POSTGRES_USER from danswer.configs.app_configs import USER_AUTH_SECRET from danswer.configs.constants import POSTGRES_UNKNOWN_APP_NAME +from danswer.server.utils import BasicAuthenticationError from danswer.utils.logger import setup_logger from shared_configs.configs import MULTI_TENANT from shared_configs.configs import POSTGRES_DEFAULT_SCHEMA @@ -426,7 +427,9 @@ def get_session() -> Generator[Session, None, None]: """Generate a database session with the appropriate tenant schema set.""" tenant_id = CURRENT_TENANT_ID_CONTEXTVAR.get() if tenant_id == POSTGRES_DEFAULT_SCHEMA and MULTI_TENANT: - raise HTTPException(status_code=401, detail="User must authenticate") + raise BasicAuthenticationError( + detail="User must authenticate", + ) engine = get_sqlalchemy_engine() diff --git a/backend/danswer/main.py b/backend/danswer/main.py index a90943997..752c5fbca 100644 --- a/backend/danswer/main.py +++ b/backend/danswer/main.py @@ -25,7 +25,6 @@ from danswer.auth.schemas import UserCreate from danswer.auth.schemas import UserRead from danswer.auth.schemas import UserUpdate from danswer.auth.users import auth_backend -from danswer.auth.users import BasicAuthenticationError from danswer.auth.users import create_danswer_oauth_router from danswer.auth.users import fastapi_users from danswer.configs.app_configs import APP_API_PREFIX @@ -92,6 +91,7 @@ from danswer.server.settings.api import basic_router as settings_router from danswer.server.token_rate_limits.api import ( router as token_rate_limit_settings_router, ) +from danswer.server.utils import BasicAuthenticationError from danswer.setup import setup_danswer from danswer.setup import setup_multitenant_danswer from danswer.utils.logger import setup_logger @@ -206,7 +206,7 @@ def log_http_error(_: Request, exc: Exception) -> JSONResponse: if isinstance(exc, BasicAuthenticationError): # For BasicAuthenticationError, just log a brief message without stack trace (almost always spam) - logger.error(f"Authentication failed: {str(exc)}") + logger.warning(f"Authentication failed: {str(exc)}") elif status_code >= 400: error_msg = f"{str(exc)}\n" diff --git a/backend/danswer/server/manage/users.py b/backend/danswer/server/manage/users.py index 12fe7ef29..2199fd766 100644 --- a/backend/danswer/server/manage/users.py +++ b/backend/danswer/server/manage/users.py @@ -26,7 +26,6 @@ from danswer.auth.noauth_user import fetch_no_auth_user from danswer.auth.noauth_user import set_no_auth_user_preferences from danswer.auth.schemas import UserRole from danswer.auth.schemas import UserStatus -from danswer.auth.users import BasicAuthenticationError from danswer.auth.users import current_admin_user from danswer.auth.users import current_curator_or_admin_user from danswer.auth.users import current_user @@ -60,6 +59,7 @@ from danswer.server.manage.models import UserRoleUpdateRequest from danswer.server.models import FullUserSnapshot from danswer.server.models import InvitedUserSnapshot from danswer.server.models import MinimalUserSnapshot +from danswer.server.utils import BasicAuthenticationError from danswer.server.utils import send_user_email_invite from danswer.utils.logger import setup_logger from danswer.utils.variable_functionality import fetch_ee_implementation_or_noop diff --git a/backend/danswer/server/utils.py b/backend/danswer/server/utils.py index 68e6dc8d0..f59066f9c 100644 --- a/backend/danswer/server/utils.py +++ b/backend/danswer/server/utils.py @@ -6,6 +6,9 @@ from email.mime.text import MIMEText from textwrap import dedent from typing import Any +from fastapi import HTTPException +from fastapi import status + from danswer.configs.app_configs import SMTP_PASS from danswer.configs.app_configs import SMTP_PORT from danswer.configs.app_configs import SMTP_SERVER @@ -14,6 +17,11 @@ from danswer.configs.app_configs import WEB_DOMAIN from danswer.db.models import User +class BasicAuthenticationError(HTTPException): + def __init__(self, detail: str): + super().__init__(status_code=status.HTTP_403_FORBIDDEN, detail=detail) + + class DateTimeEncoder(json.JSONEncoder): """Custom JSON encoder that converts datetime objects to ISO format strings.""" diff --git a/deployment/cloud_kubernetes/workers/beat.yaml b/deployment/cloud_kubernetes/workers/beat.yaml index ecd5a1219..cfe7f79cd 100644 --- a/deployment/cloud_kubernetes/workers/beat.yaml +++ b/deployment/cloud_kubernetes/workers/beat.yaml @@ -14,7 +14,7 @@ spec: spec: containers: - name: celery-beat - image: danswer/danswer-backend-cloud:v0.12.0-cloud.beta.10 + image: danswer/danswer-backend-cloud:v0.14.0-cloud.beta.4 imagePullPolicy: IfNotPresent command: [ diff --git a/deployment/cloud_kubernetes/workers/heavy_worker.yaml b/deployment/cloud_kubernetes/workers/heavy_worker.yaml index 3a4ce1a38..349ebb4f2 100644 --- a/deployment/cloud_kubernetes/workers/heavy_worker.yaml +++ b/deployment/cloud_kubernetes/workers/heavy_worker.yaml @@ -14,7 +14,7 @@ spec: spec: containers: - name: celery-worker-heavy - image: danswer/danswer-backend-cloud:v0.12.0-cloud.beta.12 + image: danswer/danswer-backend-cloud:v0.14.0-cloud.beta.4 imagePullPolicy: IfNotPresent command: [ diff --git a/deployment/cloud_kubernetes/workers/indexing_worker.yaml b/deployment/cloud_kubernetes/workers/indexing_worker.yaml index 36ce0da14..443bf236e 100644 --- a/deployment/cloud_kubernetes/workers/indexing_worker.yaml +++ b/deployment/cloud_kubernetes/workers/indexing_worker.yaml @@ -14,7 +14,7 @@ spec: spec: containers: - name: celery-worker-indexing - image: danswer/danswer-backend-cloud:v0.12.0-cloud.beta.12 + image: danswer/danswer-backend-cloud:v0.14.0-cloud.beta.4 imagePullPolicy: IfNotPresent command: [ diff --git a/deployment/cloud_kubernetes/workers/light_worker.yaml b/deployment/cloud_kubernetes/workers/light_worker.yaml index 171aa284f..eaa2ad7b9 100644 --- a/deployment/cloud_kubernetes/workers/light_worker.yaml +++ b/deployment/cloud_kubernetes/workers/light_worker.yaml @@ -14,7 +14,7 @@ spec: spec: containers: - name: celery-worker-light - image: danswer/danswer-backend-cloud:v0.12.0-cloud.beta.12 + image: danswer/danswer-backend-cloud:v0.14.0-cloud.beta.4 imagePullPolicy: IfNotPresent command: [ diff --git a/deployment/cloud_kubernetes/workers/primary.yaml b/deployment/cloud_kubernetes/workers/primary.yaml index 3f30eeb0a..ae365b151 100644 --- a/deployment/cloud_kubernetes/workers/primary.yaml +++ b/deployment/cloud_kubernetes/workers/primary.yaml @@ -14,7 +14,7 @@ spec: spec: containers: - name: celery-worker-primary - image: danswer/danswer-backend-cloud:v0.12.0-cloud.beta.12 + image: danswer/danswer-backend-cloud:v0.14.0-cloud.beta.4 imagePullPolicy: IfNotPresent command: [ diff --git a/web/src/app/admin/embeddings/pages/EmbeddingFormPage.tsx b/web/src/app/admin/embeddings/pages/EmbeddingFormPage.tsx index 2e66b5b63..4995d9da9 100644 --- a/web/src/app/admin/embeddings/pages/EmbeddingFormPage.tsx +++ b/web/src/app/admin/embeddings/pages/EmbeddingFormPage.tsx @@ -3,7 +3,7 @@ import { usePopup } from "@/components/admin/connectors/Popup"; import { HealthCheckBanner } from "@/components/health/healthcheck"; import { EmbeddingModelSelection } from "../EmbeddingModelSelectionForm"; -import { useEffect, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import Text from "@/components/ui/text"; import { Button } from "@/components/ui/button"; import { ArrowLeft, ArrowRight, WarningCircle } from "@phosphor-icons/react"; @@ -158,6 +158,26 @@ export default function EmbeddingForm() { searchSettings?.multipass_indexing != advancedEmbeddingDetails.multipass_indexing; + const updateSearch = useCallback(async () => { + if (!selectedProvider) { + return false; + } + const searchSettings = combineSearchSettings( + selectedProvider, + advancedEmbeddingDetails, + rerankingDetails, + selectedProvider.provider_type?.toLowerCase() as EmbeddingProvider | null + ); + + const response = await updateSearchSettings(searchSettings); + if (response.ok) { + return true; + } else { + setPopup({ message: "Failed to update search settings", type: "error" }); + return false; + } + }, [selectedProvider, advancedEmbeddingDetails, rerankingDetails, setPopup]); + const ReIndexingButton = useMemo(() => { const ReIndexingButtonComponent = ({ needsReIndex, @@ -206,7 +226,7 @@ export default function EmbeddingForm() { }; ReIndexingButtonComponent.displayName = "ReIndexingButton"; return ReIndexingButtonComponent; - }, [needsReIndex]); + }, [needsReIndex, updateSearch]); if (!selectedProvider) { return ; @@ -222,23 +242,6 @@ export default function EmbeddingForm() { })); }; - const updateSearch = async () => { - const searchSettings = combineSearchSettings( - selectedProvider, - advancedEmbeddingDetails, - rerankingDetails, - selectedProvider.provider_type?.toLowerCase() as EmbeddingProvider | null - ); - - const response = await updateSearchSettings(searchSettings); - if (response.ok) { - return true; - } else { - setPopup({ message: "Failed to update search settings", type: "error" }); - return false; - } - }; - const navigateToEmbeddingPage = (changedResource: string) => { router.push("/admin/configuration/search?message=search-settings"); };