From d914ee5a0006ff62feda1b61744c0058eb328b22 Mon Sep 17 00:00:00 2001 From: Kirill Kirilenko Date: Tue, 2 Sep 2025 00:50:05 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=BD=D0=B8=D0=B6=D0=B5=D0=BD=D0=BE=20?= =?UTF-8?q?=D0=B4=D1=83=D0=B1=D0=BB=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=B4=D0=B0,=20=D1=81=D0=B2=D1=8F?= =?UTF-8?q?=D0=B7=D0=B0=D0=BD=D0=BD=D0=BE=D0=B3=D0=BE=20=D1=81=20=D0=B2?= =?UTF-8?q?=D1=8B=D0=B2=D0=BE=D0=B4=D0=BE=D0=BC=20=D1=81=D1=82=D0=B0=D1=82?= =?UTF-8?q?=D0=B8=D1=81=D1=82=D0=B8=D0=BA=D0=B8.=20=D0=94=D0=BE=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D0=BD=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D0=B0=20=D1=84=D0=BE?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0=20=D0=BC=D0=BE=D0=BB=D1=87?= =?UTF-8?q?=D1=83=D0=BD=D0=BE=D0=B2=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D1=81=D0=B5=D0=BD=D0=B0=20=D0=B2=20SQL-=D0=B7=D0=B0=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=81.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database.py | 22 +++++++++----- handlers/user.py | 79 ++++++++++++++++-------------------------------- tasks.py | 21 +++++++++++-- 3 files changed, 58 insertions(+), 64 deletions(-) diff --git a/database.py b/database.py index da6dbfe..095c07e 100644 --- a/database.py +++ b/database.py @@ -87,7 +87,7 @@ class Database: def get_top_messages_today(self, chat_id: int): self.cursor.execute(""" - SELECT user_id, messages_today FROM users + SELECT user_id, messages_today AS value FROM users WHERE chat_id = ? AND messages_today > 0 ORDER BY messages_today DESC """, (chat_id,)) @@ -95,23 +95,29 @@ class Database: def get_top_messages_month(self, chat_id: int): self.cursor.execute(""" - SELECT user_id, messages_month FROM users + SELECT user_id, messages_month AS value FROM users WHERE chat_id = ? AND messages_month > 0 ORDER BY messages_month DESC """, (chat_id,)) return self.cursor.fetchall() - def get_top_silent(self, chat_id: int, threshold_time: int): + def get_top_silent(self, chat_id: int, threshold_days: int): + # noinspection SpellCheckingInspection self.cursor.execute(""" - SELECT user_id, last_message FROM users - WHERE chat_id = ? AND last_message < ? - ORDER BY last_message ASC - """, (chat_id, threshold_time)) + SELECT user_id, + CASE + WHEN last_message = 0 THEN 'никогда' + ELSE (unixepoch() - last_message) / 86400 + END AS value + FROM users + WHERE chat_id = ? AND value >= ? + ORDER BY value DESC + """, (chat_id, threshold_days)) return self.cursor.fetchall() def get_top_warnings(self, chat_id: int): self.cursor.execute(""" - SELECT user_id, warnings FROM users + SELECT user_id, warnings AS value FROM users WHERE chat_id = ? AND warnings > 0 ORDER BY warnings DESC """, (chat_id,)) diff --git a/handlers/user.py b/handlers/user.py index c7c5a1a..442dd87 100644 --- a/handlers/user.py +++ b/handlers/user.py @@ -1,13 +1,32 @@ -from vkbottle import bold, italic +from typing import List, Any + +from vkbottle import bold, italic, API from vkbottle.bot import Message import database from messages import * -import utils from labeler import labeler +# top_users - массив sqlite3.Row с двумя столбцами: user_id и value +async def format_rating(top_users: List[Any], api: API) -> str: + top_user_ids = [user['user_id'] for user in top_users] + users_info = await api.users.get(user_ids=top_user_ids) + + result = '' + i = 1 + for user in top_users: + for info in users_info: + if info.id == user['user_id']: + result += '{}. {} {} - {}\n'.format(i, info.first_name, info.last_name, user['value']) + i = i + 1 + break + + return result + + +# noinspection SpellCheckingInspection @labeler.chat_message(text="!помощь") async def rules_handler(message: Message): chat_id = message.peer_id @@ -50,18 +69,8 @@ async def stats_today_handler(message: Message): await message.answer('Сегодня еще никто не писал.') return - top_user_ids = [user['user_id'] for user in top_users] - users_info = await message.ctx_api.users.get(user_ids=top_user_ids) - response = bold('Статистика за сегодня') + '\n' - i = 1 - for user in top_users: - for info in users_info: - if info.id == user['user_id']: - response += '{}. {} {} - {}\n'.format(i, info.first_name, info.last_name, user['messages_today']) - i = i + 1 - break - + response += await format_rating(top_users, message.ctx_api) await message.answer(response) @@ -78,18 +87,8 @@ async def stats_month_handler(message: Message): await message.answer('В этом месяце еще никто не писал.') return - top_user_ids = [user['user_id'] for user in top_users] - users_info = await message.ctx_api.users.get(user_ids=top_user_ids) - response = bold('Статистика за месяц') + '\n' - i = 1 - for user in top_users: - for info in users_info: - if info.id == user['user_id']: - response += '{}. {} {} - {}\n'.format(i, info.first_name, info.last_name, user['messages_month']) - i = i + 1 - break - + response += await format_rating(top_users, message.ctx_api) await message.answer(response) @@ -101,29 +100,13 @@ async def silent_handler(message: Message): await message.answer(MESSAGE_CHAT_NOT_ACTIVE) return - now = utils.posix_time() - threshold = now - 14 * 24 * 3600 - top_users = database.DB.get_top_silent(message.peer_id, threshold) + top_users = database.DB.get_top_silent(chat_id, 14) if len(top_users) == 0: await message.answer('Молчунов нет. Все молодцы!') return - top_user_ids = [user['user_id'] for user in top_users] - users_info = await message.ctx_api.users.get(user_ids=top_user_ids) - response = bold('Молчуны чата') + ' (не писали больше 2 недель)\n' - i = 1 - for user in top_users: - for info in users_info: - if info.id == user['user_id']: - if user['last_message'] == 0: - response += '{}. {} {} - никогда\n'.format(i, info.first_name, info.last_name) - else: - days_silent = round((now - user['last_message']) / 3600 / 24) - response += '{}. {} {} - {} дней\n'.format(i, info.first_name, info.last_name, days_silent) - i = i + 1 - break - + response += await format_rating(top_users, message.ctx_api) await message.answer(response) @@ -140,18 +123,8 @@ async def warnings_handler(message: Message): await message.answer('Пока все спокойно. Продолжайте в том же духе.') return - top_user_ids = [user['user_id'] for user in top_users] - users_info = await message.ctx_api.users.get(user_ids=top_user_ids) - response = bold('Участники с предупреждениями') + '\n' - i = 1 - for user in top_users: - for info in users_info: - if info.id == user['user_id']: - response += '{}. {} {} - {}\n'.format(i, info.first_name, info.last_name, user['warnings']) - i = i + 1 - break - + response += await format_rating(top_users, message.ctx_api) await message.answer(response) diff --git a/tasks.py b/tasks.py index 74cc6b3..7452c55 100644 --- a/tasks.py +++ b/tasks.py @@ -2,17 +2,32 @@ import datetime import traceback from asyncio import sleep -from vkbottle import API +from vkbottle import API, bold import database +from handlers.user import format_rating from messages import * -def reset_counters(reset_month: bool): +async def reset_counters(reset_month: bool, api: API): database.DB.reset_messages_today() print('Дневные счетчики сброшены.') if reset_month: + for chat in database.DB.get_chats(): + if chat['active'] == 0: + continue + + top_users = database.DB.get_top_messages_month(chat['id']) + if len(top_users) == 0: + continue + + message = bold('Итоговая статистика за прошедший месяц') + '\n' + message += await format_rating(top_users, api) + # noinspection PyArgumentList + await api.messages.send(random_id=0, peer_id=chat['id'], + message=str(message), format_data=message.as_raw_data()) + database.DB.reset_messages_month() print('Месячные счетчики сброшены.') @@ -76,7 +91,7 @@ async def daily_maintenance_task(api: API): await wait_until(target_datetime) try: - reset_counters(target_datetime.day == 1) + await reset_counters(target_datetime.day == 1, api) await check_birthdays(api) except Exception: print(traceback.format_exc())