Снижено дублирование кода, связанного с выводом статистики.

Дополнительная логика формирования списка молчунов перенесена в SQL-запрос.
This commit is contained in:
Kirill Kirilenko 2025-09-02 00:50:05 +03:00
parent ecfc83d5ad
commit d914ee5a00
3 changed files with 58 additions and 64 deletions

View file

@ -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,))

View file

@ -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)

View file

@ -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())