fix(stats): count link_count per Telegram user, not per chat
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 2m11s

chat_id is shared by every member of a group chat, so all group
messages incremented one shared row and username kept getting
overwritten by whoever sent last. Track link counts in a new
user_links table keyed by the real from_user.id instead.
This commit is contained in:
vrubelroman 2026-07-03 14:29:35 +00:00
parent 87ef82ef7f
commit d5201df802
2 changed files with 40 additions and 9 deletions

View file

@ -61,11 +61,16 @@ def get_total_users() -> int:
def get_users_sent_link_count() -> int: def get_users_sent_link_count() -> int:
"""Возвращает количество пользователей, отправивших хотя бы одну ссылку""" """Возвращает количество пользователей, отправивших хотя бы одну ссылку.
Ключ реальный Telegram user_id (таблица user_links), а не chat_id: в
групповых чатах chat_id общий для всех участников и не годится для учёта
по отдельным людям.
"""
try: try:
conn = sqlite3.connect(str(DB_FILE)) conn = sqlite3.connect(str(DB_FILE))
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute('SELECT COUNT(*) FROM users WHERE link_count > 0') cursor.execute('SELECT COUNT(*) FROM user_links WHERE link_count > 0')
result = cursor.fetchone() result = cursor.fetchone()
conn.close() conn.close()
return result[0] if result else 0 return result[0] if result else 0
@ -75,12 +80,12 @@ def get_users_sent_link_count() -> int:
def get_top_active_users(limit: int = 5) -> list[tuple[int, str, str, int]]: def get_top_active_users(limit: int = 5) -> list[tuple[int, str, str, int]]:
"""Возвращает топ пользователей по количеству отправленных ссылок""" """Возвращает топ пользователей по количеству отправленных ссылок (по user_id)"""
try: try:
conn = sqlite3.connect(str(DB_FILE)) conn = sqlite3.connect(str(DB_FILE))
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute( cursor.execute(
'SELECT chat_id, username, first_name, link_count FROM users ' 'SELECT user_id, username, first_name, link_count FROM user_links '
'WHERE link_count > 0 ORDER BY link_count DESC LIMIT ?', 'WHERE link_count > 0 ORDER BY link_count DESC LIMIT ?',
(limit,) (limit,)
) )

36
bot.py
View file

@ -227,7 +227,20 @@ def init_database():
if 'link_count' not in columns: if 'link_count' not in columns:
cursor.execute("ALTER TABLE users ADD COLUMN link_count INTEGER DEFAULT 0") cursor.execute("ALTER TABLE users ADD COLUMN link_count INTEGER DEFAULT 0")
logger.info("Добавлена колонка link_count в таблицу users") logger.info("Добавлена колонка link_count в таблицу users")
# Таблица счётчиков ссылок по реальному Telegram user_id (а не chat_id —
# в групповых чатах chat_id общий для всех участников, поэтому счётчик
# ссылок ведём отдельно от таблицы users, которая ключуется по chat_id)
cursor.execute('''
CREATE TABLE IF NOT EXISTS user_links (
user_id INTEGER PRIMARY KEY,
username TEXT,
first_name TEXT,
link_count INTEGER DEFAULT 0,
last_seen TEXT
)
''')
# Таблица статистики # Таблица статистики
cursor.execute(''' cursor.execute('''
CREATE TABLE IF NOT EXISTS stats ( CREATE TABLE IF NOT EXISTS stats (
@ -380,12 +393,24 @@ def add_user(chat_id: int, username: str = None, first_name: str = None, locale:
logger.error(f"Ошибка при добавлении пользователя: {e}") logger.error(f"Ошибка при добавлении пользователя: {e}")
def increment_user_link_count(chat_id: int): def record_user_link(user_id: int, username: str = None, first_name: str = None):
"""Увеличивает счётчик отправленных пользователем ссылок""" """Увеличивает счётчик отправленных пользователем ссылок (ключ — реальный
Telegram user_id, а не chat_id в группе chat_id общий для всех участников)"""
try: try:
conn = sqlite3.connect(str(DB_FILE)) conn = sqlite3.connect(str(DB_FILE))
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute('UPDATE users SET link_count = link_count + 1 WHERE chat_id = ?', (chat_id,)) now = datetime.now().isoformat()
cursor.execute('SELECT user_id FROM user_links WHERE user_id = ?', (user_id,))
if cursor.fetchone():
cursor.execute(
'UPDATE user_links SET link_count = link_count + 1, username = ?, first_name = ?, last_seen = ? WHERE user_id = ?',
(username, first_name, now, user_id)
)
else:
cursor.execute(
'INSERT INTO user_links (user_id, username, first_name, link_count, last_seen) VALUES (?, ?, ?, 1, ?)',
(user_id, username, first_name, now)
)
conn.commit() conn.commit()
conn.close() conn.close()
except Exception as e: except Exception as e:
@ -1265,7 +1290,8 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(get_text(locale, 'error_vk_not_video')) await update.message.reply_text(get_text(locale, 'error_vk_not_video'))
return return
increment_user_link_count(chat_id) user_id = update.message.from_user.id if update.message.from_user else chat_id
record_user_link(user_id, username, first_name)
# Отправляем сообщение о начале обработки # Отправляем сообщение о начале обработки
status_message = await update.message.reply_text(get_text(locale, 'processing')) status_message = await update.message.reply_text(get_text(locale, 'processing'))