diff --git a/backend/danswer/server/manage/users.py b/backend/danswer/server/manage/users.py index 3fbd15c7e..23ae68efa 100644 --- a/backend/danswer/server/manage/users.py +++ b/backend/danswer/server/manage/users.py @@ -34,10 +34,10 @@ from danswer.server.models import FullUserSnapshot from danswer.server.models import InvitedUserSnapshot from danswer.server.models import MinimalUserSnapshot from danswer.utils.logger import setup_logger +from ee.danswer.db.api_key import is_api_key_email_address logger = setup_logger() - router = APIRouter() @@ -91,7 +91,11 @@ def list_all_users( _: User | None = Depends(current_admin_user), db_session: Session = Depends(get_session), ) -> AllUsersResponse: - users = list_users(db_session, q=q) + users = [ + user + for user in list_users(db_session, q=q) + if not is_api_key_email_address(user.email) + ] accepted_emails = {user.email for user in users} invited_emails = get_invited_users() if q: diff --git a/backend/ee/danswer/db/api_key.py b/backend/ee/danswer/db/api_key.py index 491175229..cc9c37924 100644 --- a/backend/ee/danswer/db/api_key.py +++ b/backend/ee/danswer/db/api_key.py @@ -11,10 +11,17 @@ from ee.danswer.auth.api_key import ApiKeyDescriptor from ee.danswer.auth.api_key import build_displayable_api_key from ee.danswer.auth.api_key import generate_api_key from ee.danswer.auth.api_key import hash_api_key +from ee.danswer.db.constants import DANSWER_API_KEY_DUMMY_EMAIL_DOMAIN _DANSWER_API_KEY = "danswer_api_key" +def is_api_key_email_address(email: str) -> bool: + return email.endswith( + f"@{DANSWER_API_KEY_DUMMY_EMAIL_DOMAIN}" + ) and email.startswith(_DANSWER_API_KEY) + + def fetch_api_keys(db_session: Session) -> list[ApiKeyDescriptor]: api_keys = db_session.scalars(select(ApiKey)).all() return [ @@ -44,7 +51,7 @@ def insert_api_key(db_session: Session, user_id: uuid.UUID | None) -> ApiKeyDesc api_key_user_row = User( id=api_key_user_id, - email=f"{_DANSWER_API_KEY}__{api_key_user_id}", + email=f"{_DANSWER_API_KEY}__{api_key_user_id}@{DANSWER_API_KEY_DUMMY_EMAIL_DOMAIN}", # a random password for the "user" hashed_password=std_password_helper.hash(std_password_helper.generate()), is_active=True, diff --git a/backend/ee/danswer/db/constants.py b/backend/ee/danswer/db/constants.py new file mode 100644 index 000000000..a31f413b4 --- /dev/null +++ b/backend/ee/danswer/db/constants.py @@ -0,0 +1 @@ +DANSWER_API_KEY_DUMMY_EMAIL_DOMAIN = "danswerapikey.ai" diff --git a/web/src/app/ee/admin/api-key/page.tsx b/web/src/app/ee/admin/api-key/page.tsx index bd70085c3..f0ac7e1a7 100644 --- a/web/src/app/ee/admin/api-key/page.tsx +++ b/web/src/app/ee/admin/api-key/page.tsx @@ -23,6 +23,7 @@ import { Table } from "@tremor/react"; import { DeleteButton } from "@/components/DeleteButton"; import { FiCopy, FiRefreshCw, FiX } from "react-icons/fi"; import { Modal } from "@/components/Modal"; +import { Spinner } from "@/components/Spinner"; interface APIKey { api_key_id: number; @@ -95,6 +96,7 @@ function Main() { } = useSWR("/api/admin/api-key", errorHandlingFetcher); const [fullApiKey, setFullApiKey] = useState(null); + const [keyIsGenerating, setKeyIsGenerating] = useState(false); if (isLoading) { return ; @@ -115,9 +117,11 @@ function Main() { size="xs" className="mt-3" onClick={async () => { + setKeyIsGenerating(true); const response = await fetch("/api/admin/api-key", { method: "POST", }); + setKeyIsGenerating(false); if (!response.ok) { const errorMsg = await response.text(); setPopup({ @@ -154,6 +158,8 @@ function Main() { /> )} + {keyIsGenerating && } + {API_KEY_TEXT} {newApiKeyButton} @@ -187,12 +193,14 @@ function Main() { border-border text-sm`} onClick={async () => { + setKeyIsGenerating(true); const response = await fetch( `/api/admin/api-key/${apiKey.api_key_id}`, { method: "PATCH", } ); + setKeyIsGenerating(false); if (!response.ok) { const errorMsg = await response.text(); setPopup({ @@ -237,8 +245,6 @@ function Main() { ); - - return
{fullApiKey}
; } export default function Page() {