matplobbot-shared 0.1.26__py3-none-any.whl → 0.1.27__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of matplobbot-shared might be problematic. Click here for more details.
- {matplobbot_shared-0.1.26.dist-info → matplobbot_shared-0.1.27.dist-info}/METADATA +1 -1
- {matplobbot_shared-0.1.26.dist-info → matplobbot_shared-0.1.27.dist-info}/RECORD +5 -5
- shared_lib/database.py +83 -17
- {matplobbot_shared-0.1.26.dist-info → matplobbot_shared-0.1.27.dist-info}/WHEEL +0 -0
- {matplobbot_shared-0.1.26.dist-info → matplobbot_shared-0.1.27.dist-info}/top_level.txt +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
shared_lib/__init__.py,sha256=Wxuw1wbvCOsKqs6WfIQ05cx_vndhPs6rH2krMatFRqA,45
|
|
2
|
-
shared_lib/database.py,sha256=
|
|
2
|
+
shared_lib/database.py,sha256=qsZ3yrj--81XXVQ94R1i0DMZoSITAN0LpB6WeHwPMf4,18268
|
|
3
3
|
shared_lib/i18n.py,sha256=VBWQWVF-k_HDiidYo_RUPyUCM7oL897z5hOw9jvOoYY,1762
|
|
4
4
|
shared_lib/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
shared_lib/services/schedule_service.py,sha256=tKXgwZQWeaagQeqG_tKP2gLflWo_6kxKZOhW9PFvbK4,1835
|
|
6
6
|
shared_lib/services/university_api.py,sha256=Ui-zjfKOHCCf2Imh8CNtVOWegwuep7IB8gO9IKNUrrE,1898
|
|
7
|
-
matplobbot_shared-0.1.
|
|
8
|
-
matplobbot_shared-0.1.
|
|
9
|
-
matplobbot_shared-0.1.
|
|
10
|
-
matplobbot_shared-0.1.
|
|
7
|
+
matplobbot_shared-0.1.27.dist-info/METADATA,sha256=ESW_E1TGaLOtTLFjusGQZhQVvsgDUyOg6ZCW0vOYJ0U,395
|
|
8
|
+
matplobbot_shared-0.1.27.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
9
|
+
matplobbot_shared-0.1.27.dist-info/top_level.txt,sha256=L8mrC50YWCe19jmh_zrUZFvXSkhsnES5K6y027G1838,11
|
|
10
|
+
matplobbot_shared-0.1.27.dist-info/RECORD,,
|
shared_lib/database.py
CHANGED
|
@@ -262,28 +262,95 @@ async def get_activity_over_time_data_from_db(db_conn, period='day'):
|
|
|
262
262
|
rows = await db_conn.fetch(query)
|
|
263
263
|
return [{"period": row['period_start'], "count": row['actions_count']} for row in rows]
|
|
264
264
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
265
|
+
|
|
266
|
+
async def get_user_profile_data_from_db(
|
|
267
|
+
db_conn,
|
|
268
|
+
user_id: int,
|
|
269
|
+
page: int = 1,
|
|
270
|
+
page_size: int = 50,
|
|
271
|
+
sort_by: str = 'timestamp',
|
|
272
|
+
sort_order: str = 'desc'
|
|
273
|
+
):
|
|
274
|
+
"""Извлекает детали профиля пользователя и пагинированный список его действий."""
|
|
275
|
+
# --- Безопасная сортировка ---
|
|
276
|
+
allowed_sort_columns = ['id', 'action_type', 'action_details', 'timestamp'] # These are ua columns
|
|
277
|
+
if sort_by not in allowed_sort_columns:
|
|
278
|
+
sort_by = 'timestamp' # Значение по умолчанию
|
|
279
|
+
sort_order = 'ASC' if sort_order.lower() == 'asc' else 'DESC' # Безопасное определение порядка
|
|
280
|
+
|
|
281
|
+
# --- Единый запрос для получения всех данных ---
|
|
282
|
+
# Используем CTE и оконные функции для эффективности.
|
|
283
|
+
# 1. Выбираем все действия пользователя.
|
|
284
|
+
# 2. С помощью оконной функции COUNT(*) OVER () получаем общее количество действий без дополнительного запроса.
|
|
285
|
+
# 3. Присоединяем информацию о пользователе.
|
|
286
|
+
# 4. Применяем пагинацию и сортировку.
|
|
287
|
+
query = f"""
|
|
268
288
|
WITH UserActions AS (
|
|
269
|
-
SELECT
|
|
270
|
-
|
|
289
|
+
SELECT
|
|
290
|
+
id,
|
|
291
|
+
action_type,
|
|
292
|
+
action_details,
|
|
293
|
+
TO_CHAR(timestamp, 'YYYY-MM-DD HH24:MI:SS') AS timestamp
|
|
294
|
+
FROM user_actions
|
|
295
|
+
WHERE user_id = $1
|
|
271
296
|
)
|
|
272
|
-
SELECT
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
297
|
+
SELECT
|
|
298
|
+
u.user_id,
|
|
299
|
+
u.full_name,
|
|
300
|
+
COALESCE(u.username, 'Нет username') AS username,
|
|
301
|
+
u.avatar_pic_url,
|
|
302
|
+
(SELECT COUNT(*) FROM UserActions) as total_actions,
|
|
303
|
+
ua.id as action_id,
|
|
304
|
+
ua.action_type,
|
|
305
|
+
ua.action_details,
|
|
306
|
+
ua.timestamp
|
|
307
|
+
FROM users u
|
|
308
|
+
LEFT JOIN UserActions ua ON 1=1
|
|
309
|
+
WHERE u.user_id = $2
|
|
310
|
+
ORDER BY ua.{sort_by} {sort_order}
|
|
311
|
+
LIMIT $3 OFFSET $4;
|
|
277
312
|
"""
|
|
313
|
+
offset = (page - 1) * page_size
|
|
278
314
|
rows = await db_conn.fetch(query, user_id, user_id, page_size, offset)
|
|
279
|
-
if not rows:
|
|
280
|
-
|
|
315
|
+
if not rows:
|
|
316
|
+
# If user exists but has no actions, we might get no rows. Check user existence separately.
|
|
317
|
+
user_exists = await db_conn.fetchrow("SELECT 1 FROM users WHERE user_id = $1", user_id)
|
|
318
|
+
if not user_exists:
|
|
319
|
+
return None # User not found
|
|
320
|
+
# User exists but has no actions, return empty actions list
|
|
321
|
+
user_details_row = await db_conn.fetchrow("SELECT user_id, full_name, COALESCE(username, 'Нет username') AS username, avatar_pic_url FROM users WHERE user_id = $1", user_id)
|
|
322
|
+
return {
|
|
323
|
+
"user_details": dict(user_details_row),
|
|
324
|
+
"actions": [],
|
|
325
|
+
"total_actions": 0
|
|
326
|
+
}
|
|
327
|
+
|
|
281
328
|
first_row = dict(rows[0])
|
|
282
|
-
user_details = {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
329
|
+
user_details = {
|
|
330
|
+
"user_id": first_row["user_id"],
|
|
331
|
+
"full_name": first_row["full_name"],
|
|
332
|
+
"username": first_row["username"],
|
|
333
|
+
"avatar_pic_url": first_row["avatar_pic_url"]
|
|
334
|
+
}
|
|
335
|
+
total_actions = first_row["total_actions"]
|
|
336
|
+
|
|
337
|
+
# Собираем действия, если они есть (может быть пользователь без действий)
|
|
338
|
+
actions = []
|
|
339
|
+
for row in rows:
|
|
340
|
+
row_dict = dict(row)
|
|
341
|
+
if row_dict["action_id"] is not None: # action_id не NULL
|
|
342
|
+
actions.append({
|
|
343
|
+
"id": row_dict["action_id"],
|
|
344
|
+
"action_type": row_dict["action_type"],
|
|
345
|
+
"action_details": row_dict["action_details"],
|
|
346
|
+
"timestamp": row_dict["timestamp"]
|
|
347
|
+
})
|
|
286
348
|
|
|
349
|
+
return {
|
|
350
|
+
"user_details": user_details,
|
|
351
|
+
"actions": actions,
|
|
352
|
+
"total_actions": total_actions
|
|
353
|
+
}
|
|
287
354
|
|
|
288
355
|
async def get_users_for_action(db_conn, action_type: str, action_details: str, page: int = 1, page_size: int = 15, sort_by: str = 'full_name', sort_order: str = 'asc'):
|
|
289
356
|
"""Извлекает пагинированный список уникальных пользователей, совершивших определенное действие."""
|
|
@@ -326,7 +393,6 @@ async def get_users_for_action(db_conn, action_type: str, action_details: str, p
|
|
|
326
393
|
"users": users,
|
|
327
394
|
"total_users": total_users
|
|
328
395
|
}
|
|
329
|
-
|
|
330
396
|
|
|
331
397
|
async def get_all_user_actions(db_conn, user_id: int):
|
|
332
398
|
"""Извлекает ВСЕ действия для указанного пользователя без пагинации."""
|
|
File without changes
|
|
File without changes
|