2025-02-03 20:10:51 -08:00

129 lines
4.4 KiB
Python

from typing import cast
from fastapi import APIRouter
from fastapi import Depends
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from onyx.auth.users import current_admin_user
from onyx.auth.users import current_user
from onyx.auth.users import is_user_admin
from onyx.configs.constants import KV_REINDEX_KEY
from onyx.configs.constants import NotificationType
from onyx.db.engine import get_session
from onyx.db.models import User
from onyx.db.notification import create_notification
from onyx.db.notification import dismiss_all_notifications
from onyx.db.notification import get_notifications
from onyx.db.notification import update_notification_last_shown
from onyx.key_value_store.factory import get_kv_store
from onyx.key_value_store.interface import KvKeyNotFoundError
from onyx.server.settings.models import Notification
from onyx.server.settings.models import Settings
from onyx.server.settings.models import UserSettings
from onyx.server.settings.store import load_settings
from onyx.server.settings.store import store_settings
from onyx.utils.logger import setup_logger
logger = setup_logger()
admin_router = APIRouter(prefix="/admin/settings")
basic_router = APIRouter(prefix="/settings")
@admin_router.put("")
def put_settings(
settings: Settings, _: User | None = Depends(current_admin_user)
) -> None:
store_settings(settings)
@basic_router.get("")
def fetch_settings(
user: User | None = Depends(current_user),
db_session: Session = Depends(get_session),
) -> UserSettings:
"""Settings and notifications are stuffed into this single endpoint to reduce number of
Postgres calls"""
general_settings = load_settings()
settings_notifications = get_settings_notifications(user, db_session)
try:
kv_store = get_kv_store()
needs_reindexing = cast(bool, kv_store.load(KV_REINDEX_KEY))
except KvKeyNotFoundError:
needs_reindexing = False
return UserSettings(
**general_settings.model_dump(),
notifications=settings_notifications,
needs_reindexing=needs_reindexing,
)
def get_settings_notifications(
user: User | None, db_session: Session
) -> list[Notification]:
"""Get notifications for settings page, including product gating and reindex notifications"""
# Check for product gating notification
product_notif = get_notifications(
user=None,
notif_type=NotificationType.TRIAL_ENDS_TWO_DAYS,
db_session=db_session,
)
notifications = [Notification.from_model(product_notif[0])] if product_notif else []
# Only show reindex notifications to admins
is_admin = is_user_admin(user)
if not is_admin:
return notifications
# Check if reindexing is needed
kv_store = get_kv_store()
try:
needs_index = cast(bool, kv_store.load(KV_REINDEX_KEY))
if not needs_index:
dismiss_all_notifications(
notif_type=NotificationType.REINDEX, db_session=db_session
)
return notifications
except KvKeyNotFoundError:
# If something goes wrong and the flag is gone, better to not start a reindexing
# it's a heavyweight long running job and maybe this flag is cleaned up later
logger.warning("Could not find reindex flag")
return notifications
try:
# Need a transaction in order to prevent under-counting current notifications
reindex_notifs = get_notifications(
user=user, notif_type=NotificationType.REINDEX, db_session=db_session
)
if not reindex_notifs:
notif = create_notification(
user_id=user.id if user else None,
notif_type=NotificationType.REINDEX,
db_session=db_session,
)
db_session.flush()
db_session.commit()
notifications.append(Notification.from_model(notif))
return notifications
if len(reindex_notifs) > 1:
logger.error("User has multiple reindex notifications")
reindex_notif = reindex_notifs[0]
update_notification_last_shown(
notification=reindex_notif, db_session=db_session
)
db_session.commit()
notifications.append(Notification.from_model(reindex_notif))
return notifications
except SQLAlchemyError:
logger.exception("Error while processing notifications")
db_session.rollback()
return notifications