This commit is contained in:
Timothy Jaeryang Baek committed 2026-07-16 01:27:52 -04:00
1 parent 200d447f62
commit cf235738f5
7 files changed
+186 -126

No files matched your search

+18 -15
View File
@@ -51,7 +51,6 @@ from open_webui.utils.models import (
get_all_models,
get_filtered_models,
)
from open_webui.utils.webhook import post_webhook
from pydantic import BaseModel, field_validator
from sqlalchemy.ext.asyncio import AsyncSession
@@ -915,7 +914,6 @@ async def get_pinned_channel_messages(
async def send_notification(request, channel, message, active_user_ids, db=None):
name = request.app.state.WEBUI_NAME
webui_url = await Config.get('webui.url')
enable_user_webhooks = await Config.get('ui.enable_user_webhooks')
@@ -923,23 +921,28 @@ async def send_notification(request, channel, message, active_user_ids, db=None)
# Batch fetch channel members in 1 query (fixes N+1)
member_ids = {m.user_id for m in await Channels.get_members_by_channel_id(channel.id, db=db)}
url = f'{webui_url}/channels/{channel.id}'
for u in users:
if (u.id not in active_user_ids) and u.id in member_ids:
if enable_user_webhooks and u.settings:
webhook_url = u.settings.ui.get('notifications', {}).get('webhook_url', None)
if webhook_url:
await post_webhook(
name,
webhook_url,
f'#{channel.name} - {webui_url}/channels/{channel.id}\n\n{message.content}',
{
'action': 'channel',
'message': message.content,
'title': channel.name,
'url': f'{webui_url}/channels/{channel.id}',
},
)
await publish_event(
request,
EVENTS.CHANNEL_MESSAGE,
subject_id=channel.id,
subject_type='channel',
data={
'user_id': u.id,
'channel_id': channel.id,
'message_id': message.id,
'sender_id': message.user_id,
'message': f'#{channel.name} - {url}\n\n{message.content}',
'content_preview': message.content[:300],
'title': channel.name,
'url': url,
},
message=channel.name,
)
return True
+10 -13
View File
@@ -3,7 +3,7 @@ from __future__ import annotations
from typing import Any
from fastapi import APIRouter, Depends, HTTPException, Request, status
from pydantic import BaseModel, Field
from pydantic import BaseModel
from open_webui.constants import ERROR_MESSAGES
from open_webui.models.config import Config
@@ -12,6 +12,7 @@ from open_webui.utils.auth import get_verified_user
from open_webui.utils.notifications import (
create_target,
delete_target,
get_notification_event_catalog,
list_targets,
set_default_target,
test_target,
@@ -23,12 +24,11 @@ router = APIRouter()
class NotificationTargetForm(BaseModel):
id: str | None = None
type: str = 'webhook'
name: str = Field(default='Webhook')
enabled: bool = True
events: list[str] = Field(default_factory=lambda: ['chat.finished', 'chat.failed'])
delivery: str = 'away'
config: dict[str, Any] = Field(default_factory=dict)
type: str | None = None
enabled: bool | None = None
events: list[str] | None = None
delivery: str | None = None
config: dict[str, Any] | None = None
async def _check_notifications_access(user) -> None:
@@ -44,10 +44,7 @@ async def _check_notifications_access(user) -> None:
@router.get('/events')
async def get_notification_events(user=Depends(get_verified_user)):
await _check_notifications_access(user)
return [
{'event': 'chat.finished', 'label': 'Chat finished'},
{'event': 'chat.failed', 'label': 'Chat failed'},
]
return {'events': get_notification_event_catalog()}
@router.get('/targets')
@@ -60,7 +57,7 @@ async def get_notification_targets(user=Depends(get_verified_user)):
async def create_notification_target(form_data: NotificationTargetForm, user=Depends(get_verified_user)):
await _check_notifications_access(user)
try:
return await create_target(user.id, form_data.model_dump())
return await create_target(user.id, form_data.model_dump(exclude_unset=True))
except ValueError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
@@ -81,7 +78,7 @@ async def delete_notification_target(target_id: str, user=Depends(get_verified_u
await _check_notifications_access(user)
if not await delete_target(user.id, target_id):
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND)
return True
return {'ok': True}
@router.put('/targets/{target_id}/default')