Skip to content

Commit db4dd71

Browse files
committed
feat(search): Поддержка поиска по user_id и username
Signed-off-by: Roman Chursanov <[email protected]>
1 parent 03d749e commit db4dd71

File tree

2 files changed

+79
-11
lines changed

2 files changed

+79
-11
lines changed

infrastructure/database/repo/STP/employee.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22
from typing import Optional, Sequence, TypedDict, Unpack
33

4-
from sqlalchemy import and_, select
4+
from sqlalchemy import and_, or_, select
55
from sqlalchemy.exc import SQLAlchemyError
66

77
from infrastructure.database.models import Employee
@@ -187,6 +187,70 @@ async def get_users_by_fio_parts(
187187
logger.error(f"[БД] Ошибка получения пользователей по ФИО: {e}")
188188
return []
189189

190+
async def search_users(
191+
self, search_query: str, limit: int = 50
192+
) -> Sequence[Employee]:
193+
"""
194+
Универсальный поиск пользователей по различным критериям:
195+
- User ID (число)
196+
- Username Telegram (начинается с @)
197+
- Частичное/полное ФИО
198+
199+
Args:
200+
search_query: Поисковый запрос
201+
limit: Максимальное количество результатов
202+
203+
Returns:
204+
Список объектов Employee
205+
"""
206+
search_query = search_query.strip()
207+
if not search_query:
208+
return []
209+
210+
conditions = []
211+
212+
# Проверяем, является ли запрос числом (User ID)
213+
if search_query.isdigit():
214+
user_id = int(search_query)
215+
conditions.append(Employee.user_id == user_id)
216+
217+
# Поиск по username (с @ и без @)
218+
if search_query.startswith("@"):
219+
# Если начинается с @, ищем без @
220+
username = search_query[1:]
221+
if username: # Проверяем, что после @ что-то есть
222+
conditions.append(Employee.username.ilike(f"%{username}%"))
223+
else:
224+
# Всегда добавляем поиск по username
225+
conditions.append(Employee.username.ilike(f"%{search_query}%"))
226+
227+
# Поиск по частичному ФИО
228+
name_parts = search_query.split()
229+
if name_parts:
230+
# Создаём условия для каждой части имени
231+
name_conditions = []
232+
for part in name_parts:
233+
name_conditions.append(Employee.fullname.ilike(f"%{part}%"))
234+
235+
# Все части должны присутствовать в ФИО (AND)
236+
if len(name_conditions) == 1:
237+
conditions.append(name_conditions[0])
238+
else:
239+
conditions.append(and_(*name_conditions))
240+
241+
# Объединяем все условия через OR
242+
if not conditions:
243+
return []
244+
245+
query = select(Employee).where(or_(*conditions)).limit(limit)
246+
247+
try:
248+
result = await self.session.execute(query)
249+
return result.scalars().all()
250+
except SQLAlchemyError as e:
251+
logger.error(f"[БД] Ошибка универсального поиска пользователей: {e}")
252+
return []
253+
190254
async def get_users_by_head(self, head_name: str) -> Sequence[Employee]:
191255
"""
192256
Получить всех пользователей с указанным руководителем

tgbot/handlers/search/main.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,12 @@ async def start_search(callback: CallbackQuery, context: str, state: FSMContext)
268268
bot_message = await callback.message.edit_text(
269269
"""<b>🕵🏻 Поиск сотрудника</b>
270270
271-
Введи часть имени, фамилии или полное ФИО сотрудника:
271+
Введи:
272+
• Часть имени/фамилии или полное ФИО
273+
• ID пользователя (число)
274+
• Username Telegram (@username или username)
272275
273-
<i>Например: Иванов, Иван, Иванов И, Иванов Иван и т.д.</i>""",
276+
<i>Например: Иванов, 123456789, @username, username</i>""",
274277
reply_markup=search_back_kb(context=context),
275278
)
276279

@@ -299,18 +302,19 @@ async def process_search_query(
299302
300303
❌ Поисковый запрос слишком короткий (минимум 2 символа)
301304
302-
Введи часть имени, фамилии или полное ФИО сотрудника:
305+
Введи:
306+
• Часть имени/фамилии или полное ФИО
307+
• ID пользователя (число)
308+
• Username Telegram (@username или username)
303309
304-
<i>Например: Иванов, Иван, Иванов И, Иванов Иван и т.д.</i>""",
310+
<i>Например: Иванов, 123456789, @username, username</i>""",
305311
reply_markup=search_back_kb(context=context),
306312
)
307313
return
308314

309315
try:
310-
# Поиск пользователей по частичному совпадению ФИО
311-
found_users = await stp_repo.employee.get_users_by_fio_parts(
312-
search_query, limit=50
313-
)
316+
# Универсальный поиск пользователей (ФИО, user_id, username)
317+
found_users = await stp_repo.employee.search_users(search_query, limit=50)
314318

315319
if not found_users:
316320
await message.bot.edit_message_text(
@@ -322,7 +326,7 @@ async def process_search_query(
322326
323327
Попробуй другой запрос или проверь правильность написания
324328
325-
<i>Например: Иванов, Иван, Иванов И, Иванов Иван и т.д.</i>""",
329+
<i>Например: Иванов, 123456789, @username, username</i>""",
326330
reply_markup=search_back_kb(context=context),
327331
)
328332
return
@@ -373,7 +377,7 @@ async def process_search_query(
373377
374378
❌ Произошла ошибка при поиске. Попробуй позже
375379
376-
<i>Например: Иванов, Иван, Иванов И, Иванов Иван и т.д.</i>""",
380+
<i>Например: Иванов, 123456789, @username, username</i>""",
377381
reply_markup=search_back_kb(context=context),
378382
)
379383

0 commit comments

Comments
 (0)