mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-03-26 17:51:54 +01:00
functional notifications
This commit is contained in:
parent
8f67f1715c
commit
8d66bdd061
@ -140,7 +140,7 @@ POSTGRES_PASSWORD = urllib.parse.quote_plus(
|
||||
os.environ.get("POSTGRES_PASSWORD") or "password"
|
||||
)
|
||||
POSTGRES_HOST = os.environ.get("POSTGRES_HOST") or "localhost"
|
||||
POSTGRES_PORT = os.environ.get("POSTGRES_PORT") or "5432"
|
||||
POSTGRES_PORT = os.environ.get("POSTGRES_PORT") or "5433"
|
||||
POSTGRES_DB = os.environ.get("POSTGRES_DB") or "postgres"
|
||||
|
||||
POSTGRES_API_SERVER_POOL_SIZE = int(
|
||||
|
@ -136,6 +136,7 @@ DocumentSourceRequiringTenantContext: list[DocumentSource] = [DocumentSource.FIL
|
||||
class NotificationType(str, Enum):
|
||||
REINDEX = "reindex"
|
||||
PERSONA_SHARED = "persona_shared"
|
||||
TRIAL_ENDS_TWO_DAYS = "two_day_trial_ending" # 2 days left in trial
|
||||
|
||||
|
||||
class BlobType(str, Enum):
|
||||
|
@ -4,6 +4,7 @@ from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from danswer.auth.schemas import UserRole
|
||||
from danswer.configs.constants import NotificationType
|
||||
from danswer.db.models import Notification
|
||||
from danswer.db.models import User
|
||||
@ -54,7 +55,9 @@ def get_notification_by_id(
|
||||
notif = db_session.get(Notification, notification_id)
|
||||
if not notif:
|
||||
raise ValueError(f"No notification found with id {notification_id}")
|
||||
if notif.user_id != user_id:
|
||||
if notif.user_id != user_id and not (
|
||||
notif.user_id is None and user.role == UserRole.ADMIN
|
||||
):
|
||||
raise PermissionError(
|
||||
f"User {user_id} is not authorized to access notification {notification_id}"
|
||||
)
|
||||
|
@ -79,6 +79,8 @@ def _get_answer_stream_processor(
|
||||
doc_id_to_rank_map: DocumentIdOrderMapping,
|
||||
answer_style_configs: AnswerStyleConfig,
|
||||
) -> StreamProcessor:
|
||||
print("ANSWERR STYES")
|
||||
print(answer_style_configs.__dict__)
|
||||
if answer_style_configs.citation_config:
|
||||
return build_citation_processor(
|
||||
context_docs=context_docs, doc_id_to_rank_map=doc_id_to_rank_map
|
||||
|
@ -226,6 +226,7 @@ def process_model_tokens(
|
||||
hold_quote = ""
|
||||
|
||||
for token in tokens:
|
||||
print(f"Token: {token}")
|
||||
model_previous = model_output
|
||||
model_output += token
|
||||
|
||||
|
@ -54,6 +54,7 @@ def fetch_settings(
|
||||
Postgres calls"""
|
||||
general_settings = load_settings()
|
||||
user_notifications = get_reindex_notification(user, db_session)
|
||||
product_gating_notification = get_product_gating_notification(db_session)
|
||||
|
||||
try:
|
||||
kv_store = get_kv_store()
|
||||
@ -61,11 +62,27 @@ def fetch_settings(
|
||||
except KvKeyNotFoundError:
|
||||
needs_reindexing = False
|
||||
|
||||
return UserSettings(
|
||||
print("product_gating_notification", product_gating_notification)
|
||||
# TODO: Clean up
|
||||
print("response is ", [product_gating_notification])
|
||||
response = UserSettings(
|
||||
**general_settings.model_dump(),
|
||||
notifications=user_notifications,
|
||||
notifications=[product_gating_notification]
|
||||
if product_gating_notification
|
||||
else user_notifications,
|
||||
needs_reindexing=needs_reindexing,
|
||||
)
|
||||
print("act is ", response)
|
||||
return response
|
||||
|
||||
|
||||
def get_product_gating_notification(db_session: Session) -> Notification | None:
|
||||
notification = get_notifications(
|
||||
user=None,
|
||||
notif_type=NotificationType.TRIAL_ENDS_TWO_DAYS,
|
||||
db_session=db_session,
|
||||
)
|
||||
return Notification.from_model(notification[0]) if notification else None
|
||||
|
||||
|
||||
def get_reindex_notification(
|
||||
|
@ -8,6 +8,7 @@ from danswer.auth.users import User
|
||||
from danswer.configs.app_configs import MULTI_TENANT
|
||||
from danswer.configs.app_configs import WEB_DOMAIN
|
||||
from danswer.db.engine import get_session_with_tenant
|
||||
from danswer.db.notification import create_notification
|
||||
from danswer.server.settings.store import load_settings
|
||||
from danswer.server.settings.store import store_settings
|
||||
from danswer.setup import setup_danswer
|
||||
@ -87,12 +88,17 @@ def gate_product(
|
||||
1) User has ended free trial without adding payment method
|
||||
2) User's card has declined
|
||||
"""
|
||||
token = current_tenant_id.set(current_tenant_id.get())
|
||||
tenant_id = product_gating_request.tenant_id
|
||||
token = current_tenant_id.set(tenant_id)
|
||||
|
||||
settings = load_settings()
|
||||
settings.product_gating = product_gating_request.product_gating
|
||||
store_settings(settings)
|
||||
|
||||
if product_gating_request.notification:
|
||||
with get_session_with_tenant(tenant_id) as db_session:
|
||||
create_notification(None, product_gating_request.notification, db_session)
|
||||
|
||||
if token is not None:
|
||||
current_tenant_id.reset(token)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
from danswer.configs.constants import NotificationType
|
||||
from danswer.server.settings.models import GatingType
|
||||
|
||||
|
||||
@ -15,6 +16,7 @@ class CreateTenantRequest(BaseModel):
|
||||
class ProductGatingRequest(BaseModel):
|
||||
tenant_id: str
|
||||
product_gating: GatingType
|
||||
notification: NotificationType | None = None
|
||||
|
||||
|
||||
class BillingInformation(BaseModel):
|
||||
|
@ -313,7 +313,7 @@ services:
|
||||
- POSTGRES_USER=${POSTGRES_USER:-postgres}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password}
|
||||
ports:
|
||||
- "5432:5432"
|
||||
- "5433:5432"
|
||||
volumes:
|
||||
- db_volume:/var/lib/postgresql/data
|
||||
|
||||
|
@ -313,7 +313,7 @@ services:
|
||||
- POSTGRES_USER=${POSTGRES_USER:-postgres}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password}
|
||||
ports:
|
||||
- "5432:5432"
|
||||
- "5433:5432"
|
||||
volumes:
|
||||
- db_volume:/var/lib/postgresql/data
|
||||
|
||||
|
@ -157,7 +157,7 @@ services:
|
||||
- POSTGRES_USER=${POSTGRES_USER:-postgres}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password}
|
||||
ports:
|
||||
- "5432"
|
||||
- "5433"
|
||||
volumes:
|
||||
- db_volume:/var/lib/postgresql/data
|
||||
|
||||
|
@ -18,6 +18,7 @@ export interface Settings {
|
||||
export enum NotificationType {
|
||||
PERSONA_SHARED = "persona_shared",
|
||||
REINDEX_NEEDED = "reindex_needed",
|
||||
TRIAL_ENDS_TWO_DAYS = "two_day_trial_ending",
|
||||
}
|
||||
|
||||
export interface Notification {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { CLOUD_ENABLED } from "@/lib/constants";
|
||||
import { NEXT_PUBLIC_CLOUD_ENABLED } from "@/lib/constants";
|
||||
import { getAuthTypeMetadataSS, logoutSS } from "@/lib/userSS";
|
||||
import { NextRequest } from "next/server";
|
||||
|
||||
@ -13,7 +13,7 @@ export const POST = async (request: NextRequest) => {
|
||||
}
|
||||
|
||||
// Delete cookies only if cloud is enabled (jwt auth)
|
||||
if (CLOUD_ENABLED) {
|
||||
if (NEXT_PUBLIC_CLOUD_ENABLED) {
|
||||
const cookiesToDelete = ["fastapiusersauth", "tenant_details"];
|
||||
const cookieOptions = {
|
||||
path: "/",
|
||||
|
@ -8,10 +8,8 @@ import {
|
||||
} from "@/lib/userSS";
|
||||
import { redirect } from "next/navigation";
|
||||
import { EmailPasswordForm } from "../login/EmailPasswordForm";
|
||||
import { Card, Title, Text } from "@tremor/react";
|
||||
import { Text } from "@tremor/react";
|
||||
import Link from "next/link";
|
||||
import { Logo } from "@/components/Logo";
|
||||
import { CLOUD_ENABLED } from "@/lib/constants";
|
||||
import { SignInButton } from "../login/SignInButton";
|
||||
import AuthFlowContainer from "@/components/auth/AuthFlowContainer";
|
||||
|
||||
|
@ -174,20 +174,6 @@ export default async function RootLayout({
|
||||
process.env.THEME_IS_DARK?.toLowerCase() === "true" ? "dark" : ""
|
||||
}`}
|
||||
>
|
||||
{productGating === GatingType.PARTIAL && (
|
||||
<div className="fixed top-0 left-0 right-0 z-50 bg-warning-100 text-warning-900 p-2 text-center">
|
||||
<p className="text-sm font-medium">
|
||||
Your account is pending payment!{" "}
|
||||
<a
|
||||
href="/admin/cloud-settings"
|
||||
className="font-bold underline hover:text-warning-700 transition-colors"
|
||||
>
|
||||
Update your billing information
|
||||
</a>{" "}
|
||||
or access will be suspended soon.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<UserProvider>
|
||||
<ProviderContextProvider>
|
||||
<SettingsProvider settings={combinedSettings}>
|
||||
|
@ -27,7 +27,6 @@ export async function Layout({ children }: { children: React.ReactNode }) {
|
||||
|
||||
const authTypeMetadata = results[0] as AuthTypeMetadata | null;
|
||||
const user = results[1] as User | null;
|
||||
console.log("authTypeMetadata", authTypeMetadata);
|
||||
const authDisabled = authTypeMetadata?.authType === "disabled";
|
||||
const requiresVerification = authTypeMetadata?.requiresVerification;
|
||||
|
||||
|
@ -15,6 +15,7 @@ export function AnnouncementBanner() {
|
||||
settings?.settings.notifications || []
|
||||
);
|
||||
|
||||
console.log("notifications", localNotifications);
|
||||
useEffect(() => {
|
||||
const filteredNotifications = (
|
||||
settings?.settings.notifications || []
|
||||
@ -32,7 +33,7 @@ export function AnnouncementBanner() {
|
||||
const handleDismiss = async (notificationId: number) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/settings/notifications/${notificationId}/dismiss`,
|
||||
`/api/notifications/${notificationId}/dismiss`,
|
||||
{
|
||||
method: "POST",
|
||||
}
|
||||
@ -61,12 +62,12 @@ export function AnnouncementBanner() {
|
||||
{localNotifications
|
||||
.filter((notification) => !notification.dismissed)
|
||||
.map((notification) => {
|
||||
if (notification.notif_type == "reindex") {
|
||||
return (
|
||||
<div
|
||||
key={notification.id}
|
||||
className="absolute top-0 left-1/2 transform -translate-x-1/2 bg-blue-600 rounded-sm text-white px-4 pr-8 py-3 mx-auto"
|
||||
>
|
||||
return (
|
||||
<div
|
||||
key={notification.id}
|
||||
className="absolute top-0 left-1/2 transform -translate-x-1/2 bg-blue-600 rounded-sm text-white px-4 pr-8 py-3 mx-auto"
|
||||
>
|
||||
{notification.notif_type == "reindex" ? (
|
||||
<p className="text-center">
|
||||
Your index is out of date - we strongly recommend updating
|
||||
your search settings.{" "}
|
||||
@ -77,24 +78,29 @@ export function AnnouncementBanner() {
|
||||
Update here
|
||||
</Link>
|
||||
</p>
|
||||
<button
|
||||
onClick={() => handleDismiss(notification.id)}
|
||||
className="absolute top-0 right-0 mt-2 mr-2"
|
||||
aria-label="Dismiss"
|
||||
>
|
||||
<CustomTooltip
|
||||
showTick
|
||||
citation
|
||||
delay={100}
|
||||
content="Dismiss"
|
||||
) : notification.notif_type == "two_day_trial_ending" ? (
|
||||
<p className="text-center">
|
||||
Your trial is ending soon - submit your billing information to
|
||||
continue using Danswer.{" "}
|
||||
<Link
|
||||
href="/admin/cloud-settings"
|
||||
className="ml-2 underline cursor-pointer"
|
||||
>
|
||||
<XIcon className="h-5 w-5" />
|
||||
</CustomTooltip>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
Update here
|
||||
</Link>
|
||||
</p>
|
||||
) : null}
|
||||
<button
|
||||
onClick={() => handleDismiss(notification.id)}
|
||||
className="absolute top-0 right-0 mt-2 mr-2"
|
||||
aria-label="Dismiss"
|
||||
>
|
||||
<CustomTooltip showTick citation delay={100} content="Dismiss">
|
||||
<XIcon className="h-5 w-5" />
|
||||
</CustomTooltip>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user