search patch

This commit is contained in:
unknown 2025-10-04 02:25:12 +03:00
parent 86d5e03157
commit 5306640238
3 changed files with 103 additions and 0 deletions

View File

@ -0,0 +1,26 @@
from uuid import UUID
from datetime import datetime
from typing import Optional, List, Any
from pydantic import BaseModel, Field
class UserSearchResult(BaseModel):
user_id: UUID
login: str
full_name: Optional[str] = None
custom_name: Optional[str] = None
created_at: datetime = Field(..., description="Дата регистрации")
profile: Optional[Any] = Field(None, description="Модель как у /profile/{user_id}")
class SearchData(BaseModel):
users: List[UserSearchResult]
groups: List[Any] = []
channels: List[Any] = []
messages: List[Any] = []
class SearchResponse(BaseModel):
status: str
data: SearchData

View File

@ -0,0 +1,42 @@
import httpx
from app.core import config
from app.core.localizer import localizer
from app.core.http_client import authorized_get
from app.core.models.search_models import SearchResponse, SearchData
async def search_by_query(login: str, token: str, query: str):
"""
Поиск по строке: пользователи (префикс), далее можно расширить под группы/каналы/сообщения.
:return: tuple (ok: bool, data: SearchData | str)
"""
url = f"{config.BASE_URL}/v1/feed/search"
headers = {"Authorization": f"Bearer {token}"}
params = {"query": query}
try:
response = await authorized_get(url, login=login, access_token=token, headers=headers, params=params)
print("response.status_code", response.status_code)
if response.status_code == 200:
data = response.json()
if data.get("status") == "fine":
model = SearchResponse(**data)
return True, model.data
return False, data.get("detail", localizer.translate("Произошла ошибка"))
if response.status_code in [401, 403]:
error_data = response.json()
return False, error_data.get("detail", localizer.translate("Недостаточно прав или неавторизован"))
if response.status_code == 422:
return False, localizer.translate("Некорректные параметры запроса")
return False, f"{localizer.translate('Неожиданный статус')}: {response.status_code}"
except httpx.RequestError as e:
return False, f"{localizer.translate('Сетевая ошибка')}: {e}"
except Exception as e:
return False, f"{localizer.translate('Внутренняя ошибка')}: {e}"

View File

@ -20,6 +20,7 @@ from app.ui.views.chat_view import ChatView
from app.core.services.chat_service import get_chat_history, send_private_message
from app.core.models.chat_models import PrivateMessageSendRequest, MessageItem
from uuid import UUID
from app.core.services.search_service import search_by_query
class YobbleHomeView(QWidget):
REQUIRED_PERMISSIONS = {
@ -271,6 +272,8 @@ class YobbleHomeView(QWidget):
self.search_input.setPlaceholderText("Поиск…")
self.search_input.hide()
top_bar_layout.addWidget(self.search_input, 1)
# Запуск поиска по Enter
self.search_input.returnPressed.connect(self.on_search_submit)
# Новые кнопки справа
self.search_button = QPushButton("🔍")
@ -664,6 +667,38 @@ class YobbleHomeView(QWidget):
self.search_button.show()
self.notification_button.show()
def on_search_submit(self):
"""Обработчик Enter в поле поиска."""
query = (self.search_input.text() or "").strip()
if len(query) < 1:
self.show_notification(localizer.translate("Введите минимум 1 символ"), is_error=True)
return
# Запускаем асинхронный поиск
asyncio.ensure_future(self._do_search(query))
async def _do_search(self, query: str):
"""Вызов серверного поиска и показ краткого результата."""
# Получаем текущие учётные данные
login = self.username
token = await get_current_access_token()
if not token:
self.show_notification(localizer.translate("Не найден токен авторизации"), is_error=True)
return
ok, data_or_error = await search_by_query(login, token, query)
if not ok:
self.show_notification(str(data_or_error), is_error=True)
return
data = data_or_error
users_cnt = len(getattr(data, 'users', []) or [])
groups_cnt = len(getattr(data, 'groups', []) or [])
channels_cnt = len(getattr(data, 'channels', []) or [])
messages_cnt = len(getattr(data, 'messages', []) or [])
self.show_notification(
localizer.translate(f"Найдено: пользователи {users_cnt}, беседы {groups_cnt}, паблики {channels_cnt}, сообщения {messages_cnt}")
)
def handle_notification_click(self):
"""Пустышка для кнопки уведомлений."""
show_themed_messagebox(