mirror of
https://github.com/open-webui/open-webui.git
synced 2026-09-28 02:07:05 -04:00
refac
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
"""add last_read_at to chat
|
||||
|
||||
Revision ID: b7c8d9e0f1a2
|
||||
Revises: d4e5f6a7b8c9
|
||||
Create Date: 2026-04-01 04:00:00.000000
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'b7c8d9e0f1a2'
|
||||
down_revision = 'd4e5f6a7b8c9'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column('chat', sa.Column('last_read_at', sa.BigInteger(), nullable=True))
|
||||
# Set existing chats to be marked as read
|
||||
op.execute('UPDATE chat SET last_read_at = updated_at')
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_column('chat', 'last_read_at')
|
||||
@@ -57,6 +57,8 @@ class Chat(Base):
|
||||
tasks = Column(JSON, nullable=True)
|
||||
summary = Column(Text, nullable=True)
|
||||
|
||||
last_read_at = Column(BigInteger, nullable=True)
|
||||
|
||||
__table_args__ = (
|
||||
# Performance indexes for common queries
|
||||
# WHERE folder_id = ...
|
||||
@@ -93,6 +95,8 @@ class ChatModel(BaseModel):
|
||||
tasks: Optional[list] = None
|
||||
summary: Optional[str] = None
|
||||
|
||||
last_read_at: Optional[int] = None
|
||||
|
||||
|
||||
class ChatFile(Base):
|
||||
__tablename__ = 'chat_file'
|
||||
@@ -176,6 +180,7 @@ class ChatTitleIdResponse(BaseModel):
|
||||
title: str
|
||||
updated_at: int
|
||||
created_at: int
|
||||
last_read_at: Optional[int] = None
|
||||
|
||||
|
||||
class SharedChatResponse(BaseModel):
|
||||
@@ -397,6 +402,20 @@ class ChatTable:
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def update_chat_last_read_at_by_id(
|
||||
self, id: str, user_id: str, db: Optional[Session] = None
|
||||
) -> bool:
|
||||
try:
|
||||
with get_db_context(db) as db:
|
||||
chat = db.get(Chat, id)
|
||||
if chat and chat.user_id == user_id:
|
||||
chat.last_read_at = int(time.time())
|
||||
db.commit()
|
||||
return True
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def update_chat_title_by_id(self, id: str, title: str) -> Optional[ChatModel]:
|
||||
chat = self.get_chat_by_id(id)
|
||||
if chat is None:
|
||||
@@ -834,7 +853,7 @@ class ChatTable:
|
||||
query = query.filter_by(archived=False)
|
||||
|
||||
query = query.order_by(Chat.updated_at.desc(), Chat.id).with_entities(
|
||||
Chat.id, Chat.title, Chat.updated_at, Chat.created_at
|
||||
Chat.id, Chat.title, Chat.updated_at, Chat.created_at, Chat.last_read_at
|
||||
)
|
||||
|
||||
if skip:
|
||||
@@ -852,6 +871,7 @@ class ChatTable:
|
||||
'title': chat[1],
|
||||
'updated_at': chat[2],
|
||||
'created_at': chat[3],
|
||||
'last_read_at': chat[4],
|
||||
}
|
||||
)
|
||||
for chat in all_chats
|
||||
@@ -995,7 +1015,7 @@ class ChatTable:
|
||||
db.query(Chat)
|
||||
.filter_by(user_id=user_id, pinned=True, archived=False)
|
||||
.order_by(Chat.updated_at.desc())
|
||||
.with_entities(Chat.id, Chat.title, Chat.updated_at, Chat.created_at)
|
||||
.with_entities(Chat.id, Chat.title, Chat.updated_at, Chat.created_at, Chat.last_read_at)
|
||||
)
|
||||
return [
|
||||
ChatTitleIdResponse.model_validate(
|
||||
@@ -1004,6 +1024,7 @@ class ChatTable:
|
||||
'title': chat[1],
|
||||
'updated_at': chat[2],
|
||||
'created_at': chat[3],
|
||||
'last_read_at': chat[4],
|
||||
}
|
||||
)
|
||||
for chat in all_chats
|
||||
|
||||
@@ -644,7 +644,7 @@ async def get_chat_list_by_folder_id(
|
||||
skip = (page - 1) * limit
|
||||
|
||||
return [
|
||||
{'title': chat.title, 'id': chat.id, 'updated_at': chat.updated_at}
|
||||
{'title': chat.title, 'id': chat.id, 'updated_at': chat.updated_at, 'last_read_at': chat.last_read_at}
|
||||
for chat in Chats.get_chats_by_folder_id_and_user_id(folder_id, user.id, skip=skip, limit=limit, db=db)
|
||||
]
|
||||
|
||||
|
||||
@@ -491,6 +491,22 @@ async def channel_events(sid, data):
|
||||
Channels.update_member_last_read_at(data['channel_id'], user['id'])
|
||||
|
||||
|
||||
@sio.on('events:chat')
|
||||
async def chat_events(sid, data):
|
||||
user = SESSION_POOL.get(sid)
|
||||
if not user:
|
||||
return
|
||||
|
||||
event_data = data.get('data', {})
|
||||
event_type = event_data.get('type')
|
||||
|
||||
if event_type == 'last_read_at':
|
||||
await asyncio.to_thread(
|
||||
Chats.update_chat_last_read_at_by_id,
|
||||
data['chat_id'], user['id']
|
||||
)
|
||||
|
||||
|
||||
def normalize_document_id(document_id: str) -> str:
|
||||
"""Canonicalize document IDs to prevent auth bypass via prefix variants.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user