search patch
This commit is contained in:
		
							parent
							
								
									86d5e03157
								
							
						
					
					
						commit
						5306640238
					
				
							
								
								
									
										26
									
								
								app/core/models/search_models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								app/core/models/search_models.py
									
									
									
									
									
										Normal 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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										42
									
								
								app/core/services/search_service.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								app/core/services/search_service.py
									
									
									
									
									
										Normal 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}"
 | 
			
		||||
 | 
			
		||||
@ -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(
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user