Добавлена версия для Telegram.

Рефакторинг.
This commit is contained in:
Kirill Kirilenko 2025-10-25 02:19:35 +03:00
parent ac55d8700c
commit 5d07116ef2
19 changed files with 540 additions and 93 deletions

View file

@ -2,37 +2,12 @@ import sqlite3
from typing import List from typing import List
class Database: class BasicDatabase:
def __init__(self): def __init__(self):
self.conn = sqlite3.connect('bot.db') self.conn = sqlite3.connect('bot.db')
self.conn.row_factory = sqlite3.Row self.conn.row_factory = sqlite3.Row
self.cursor = self.conn.cursor() self.cursor = self.conn.cursor()
self.cursor.execute("""
CREATE TABLE IF NOT EXISTS chats (
"id" INTEGER,
"active" INTEGER NOT NULL DEFAULT 0,
"rules" TEXT,
"greeting_join" TEXT,
"greeting_rejoin" TEXT,
"birthday_message" TEXT,
PRIMARY KEY("id"))
""")
self.cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
"chat_id" INTEGER,
"user_id" INTEGER,
"last_message" INTEGER NOT NULL DEFAULT 0,
"messages_today" INTEGER NOT NULL DEFAULT 0,
"messages_month" INTEGER NOT NULL DEFAULT 0,
"warnings" INTEGER NOT NULL DEFAULT 0,
"happy_birthday" INTEGER NOT NULL DEFAULT 1,
PRIMARY KEY("chat_id","user_id"))
""")
self.conn.commit()
def get_chats(self): def get_chats(self):
self.cursor.execute("SELECT * FROM chats") self.cursor.execute("SELECT * FROM chats")
return self.cursor.fetchall() return self.cursor.fetchall()
@ -76,9 +51,6 @@ class Database:
def user_increment_warnings(self, chat_id: int, user_id: int): def user_increment_warnings(self, chat_id: int, user_id: int):
self.user_increment(chat_id, user_id, ['warnings']) self.user_increment(chat_id, user_id, ['warnings'])
def user_toggle_happy_birthday(self, chat_id: int, user_id: int, happy_birthday: int):
self.user_update(chat_id, user_id, happy_birthday=happy_birthday)
def user_increment(self, chat_id: int, user_id: int, fields: List[str]): def user_increment(self, chat_id: int, user_id: int, fields: List[str]):
self.cursor.execute("UPDATE users SET " + ", ".join(f + " = " + f + " + 1" for f in fields) + self.cursor.execute("UPDATE users SET " + ", ".join(f + " = " + f + " + 1" for f in fields) +
" WHERE chat_id = ? AND user_id = ?", (chat_id, user_id)) " WHERE chat_id = ? AND user_id = ?", (chat_id, user_id))
@ -143,21 +115,16 @@ class Database:
self.cursor.execute("UPDATE users SET messages_month = 0") self.cursor.execute("UPDATE users SET messages_month = 0")
self.conn.commit() self.conn.commit()
def create_chat_if_not_exists(self, chat_id: int):
DB = Database() chat = self.get_chat(chat_id)
def create_chat_if_not_exists(chat_id: int):
chat = DB.get_chat(chat_id)
if chat is None: if chat is None:
DB.add_chat(chat_id) self.add_chat(chat_id)
chat = DB.get_chat(chat_id) chat = self.get_chat(chat_id)
return chat return chat
def create_user_if_not_exists(self, chat_id: int, user_id: int):
def create_user_if_not_exists(chat_id: int, user_id: int): user = self.get_user(chat_id, user_id)
user = DB.get_user(chat_id, user_id)
if user is None: if user is None:
DB.add_user(chat_id, user_id) self.add_user(chat_id, user_id)
user = DB.get_user(chat_id, user_id) user = self.get_user(chat_id, user_id)
return user return user

View file

@ -1,7 +0,0 @@
import handlers.user
import handlers.admin
import handlers.action
import handlers.default
__all__ = []

View file

@ -1,4 +0,0 @@
from vkbottle.bot import BotLabeler
labeler = BotLabeler()

9
tg/handlers/__init__.py Normal file
View file

@ -0,0 +1,9 @@
from aiogram import Router
from . import user, admin, action, default
router = Router()
router.include_router(user.router)
router.include_router(admin.router)
router.include_router(action.router)
router.include_router(default.router)

40
tg/handlers/action.py Normal file
View file

@ -0,0 +1,40 @@
from aiogram import Router, F
from aiogram.enums import ContentType, ParseMode
from aiogram.types import Message
from messages import *
import tg.tg_database as database
router = Router()
@router.message(F.content_type == ContentType.NEW_CHAT_MEMBERS)
async def user_join_handler(message: Message):
chat_id = message.chat.id
chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return
for member in message.new_chat_members:
if member.is_bot:
continue
response = chat['greeting_join'] or MESSAGE_DEFAULT_GREETING_JOIN
response = response.format(name=f'[{member.first_name}](tg://user?id={member.id})')
await message.answer(response, parse_mode=ParseMode.MARKDOWN)
@router.message(F.content_type == ContentType.LEFT_CHAT_MEMBER)
async def user_join_handler(message: Message):
chat_id = message.chat.id
chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return
member = message.left_chat_member
if member.is_bot:
return
database.DB.delete_user(chat_id, member.id)

103
tg/handlers/admin.py Normal file
View file

@ -0,0 +1,103 @@
from aiogram import Bot, Router, F
from aiogram.types import Message
from aiogram.utils.formatting import Bold
import utils
from messages import *
import tg.tg_database as database
router = Router()
async def tg_user_is_admin(chat_id: int, user_id: int, bot: Bot):
for admin in await bot.get_chat_administrators(chat_id=chat_id):
if admin.user.id == user_id:
return True
return False
@router.message(F.text == "!старт")
async def start_handler(message: Message, bot: Bot):
chat_id = message.chat.id
database.DB.create_chat_if_not_exists(chat_id)
if not await tg_user_is_admin(chat_id, message.from_user.id, bot):
await message.answer(MESSAGE_PERMISSION_DENIED)
return
database.DB.chat_update(chat_id, active=1)
await message.answer('Готова к работе!')
@router.message(F.text == "!правила")
async def rules_handler(message: Message, bot: Bot):
chat_id = message.chat.id
chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return
if message.reply_to_message is None:
if chat['rules'] is not None:
response = Bold('Правила чата') + '\n' + chat['rules']
await message.answer(**response.as_kwargs())
else:
await message.answer(MESSAGE_DEFAULT_RULES)
else:
if not await tg_user_is_admin(chat_id, message.from_user.id, bot):
await message.answer(MESSAGE_PERMISSION_DENIED)
return
database.DB.chat_update(chat_id, rules=message.reply_to_message.text)
await message.answer('Правила чата изменены.')
@router.message(F.text == "!приветствие")
async def set_greeting_handler(message: Message, bot: Bot):
chat_id = message.chat.id
chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return
if not await tg_user_is_admin(chat_id, message.from_user.id, bot):
await message.answer(MESSAGE_PERMISSION_DENIED)
return
if message.reply_to_message is None:
await message.answer(MESSAGE_NEED_REPLY)
return
database.DB.chat_update(chat_id, greeting_join=message.reply_to_message.text)
await message.answer('Приветствие изменено.')
@router.message(F.text == "!предупреждение")
async def warning_handler(message: Message, bot: Bot):
chat_id = message.chat.id
chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return
if not await tg_user_is_admin(chat_id, message.from_user.id, bot):
await message.answer(MESSAGE_PERMISSION_DENIED)
return
if message.reply_to_message is None:
await message.answer(MESSAGE_NEED_REPLY)
return
user_id = message.reply_to_message.from_user.id
database.DB.create_user_if_not_exists(chat_id, user_id)
database.DB.user_increment_warnings(chat_id, user_id)
user = database.DB.get_user(chat_id, user_id)
user_info = message.reply_to_message.from_user
await message.answer('У {} {} {} {}.'.format(
user_info.first_name,
user_info.last_name,
user['warnings'],
utils.make_word_agree_with_number(user['warnings'], 'предупреждение'))
)

44
tg/handlers/default.py Normal file
View file

@ -0,0 +1,44 @@
from aiogram import Router, F
from aiogram.types import Message
from aiogram.enums.content_type import ContentType
import utils
import tg.tg_database as database
router = Router()
ACCEPTED_CONTENT_TYPES: list[ContentType] = [
ContentType.TEXT,
ContentType.ANIMATION,
ContentType.AUDIO,
ContentType.DOCUMENT,
ContentType.PAID_MEDIA,
ContentType.PHOTO,
ContentType.STICKER,
ContentType.STORY,
ContentType.VIDEO,
ContentType.VIDEO_NOTE,
ContentType.VOICE,
ContentType.CHECKLIST,
ContentType.CONTACT,
ContentType.POLL,
ContentType.VENUE,
ContentType.LOCATION
]
@router.message(F.content_type.in_(ACCEPTED_CONTENT_TYPES))
async def any_message_handler(message: Message):
chat_id = message.chat.id
chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0:
return
# Игнорировать ботов
if message.from_user.is_bot:
return
user_id = message.from_user.id
database.DB.create_user_if_not_exists(chat_id, user_id)
database.DB.user_set_last_message(chat_id, user_id, utils.posix_time())
database.DB.user_increment_messages(chat_id, user_id)

129
tg/handlers/user.py Normal file
View file

@ -0,0 +1,129 @@
from typing import List, Any
from aiogram import Bot, Router, F
from aiogram.types import Message
from aiogram.utils.formatting import Bold, Italic
from messages import *
import tg.tg_database as database
router = Router()
# top_users - массив sqlite3.Row с двумя столбцами: user_id и value
async def format_rating(chat_id: int, top_users: List[Any], bot: Bot) -> str:
result = ''
i = 1
for user in top_users:
info = await bot.get_chat_member(chat_id, user['user_id'])
result += '{}. {} {} - {}\n'.format(i, info.user.first_name, info.user.last_name, user['value'])
i = i + 1
return result
def calculate_total_messages(top_users: List[Any]) -> int:
total = 0
for user in top_users:
total += user['value']
return total
@router.message(F.text == '!помощь')
async def help_handler(message: Message):
chat_id = message.chat.id
chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return
response = Bold('Команды для всех') + '\n'
response += '!правила - вывести правила\n'
response += '!сегодня - статистика сообщений за сегодня\n'
response += '!месяц - статистика сообщений за месяц\n'
response += '!молчуны - список молчунов\n'
response += '!предупреждения - список участников с предупреждениями\n'
response += '\n'
response += Bold('Команды для администраторов') + '\n'
response += '!старт - начать работу в чате\n'
response += '!правила* - изменить правила\n'
response += '!приветствие* - изменить приветствие новичков\n'
response += '!предупреждение* - выдать предупреждение участнику\n'
response += '\n'
response += Italic('Команды с пометкой * нужно вызывать в ответном сообщении.')
await message.answer(**response.as_kwargs())
@router.message(F.text == "!сегодня")
async def stats_today_handler(message: Message, bot: Bot):
chat_id = message.chat.id
chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return
top_users = database.DB.get_top_messages_today(chat_id)
if len(top_users) == 0:
await message.answer('Сегодня еще никто не писал.')
return
response = Bold('Статистика за сегодня') + '\n'
response += 'Всего сообщений - {}\n'.format(calculate_total_messages(top_users))
response += await format_rating(chat_id, top_users, bot)
await message.answer(**response.as_kwargs())
@router.message(F.text == "!месяц")
async def stats_month_handler(message: Message, bot: Bot):
chat_id = message.chat.id
chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return
top_users = database.DB.get_top_messages_month(chat_id)
if len(top_users) == 0:
await message.answer('В этом месяце еще никто не писал.')
return
response = Bold('Статистика за месяц') + '\n'
response += 'Всего сообщений - {}\n'.format(calculate_total_messages(top_users))
response += await format_rating(chat_id, top_users, bot)
await message.answer(**response.as_kwargs())
@router.message(F.text == "!молчуны")
async def silent_handler(message: Message, bot: Bot):
chat_id = message.chat.id
chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return
top_users = database.DB.get_top_messages_today(chat_id)
if len(top_users) == 0:
await message.answer('Молчунов нет. Все молодцы!')
return
response = Bold('Молчуны чата') + ' (не писали более 14 дней)\n'
response += await format_rating(chat_id, top_users, bot)
await message.answer(**response.as_kwargs())
@router.message(F.text == "!предупреждения")
async def warnings_handler(message: Message, bot: Bot):
chat_id = message.chat.id
chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return
top_users = database.DB.get_top_warnings(chat_id)
if len(top_users) == 0:
await message.answer('Пока все спокойно. Продолжайте в том же духе.')
return
response = Bold('Участники с предупреждениями') + '\n'
response += await format_rating(chat_id, top_users, bot)
await message.answer(**response.as_kwargs())

67
tg/tasks.py Normal file
View file

@ -0,0 +1,67 @@
import datetime
import traceback
from asyncio import sleep
from aiogram import Bot
from aiogram.utils.formatting import Bold
from messages import *
import tg.tg_database as database
from tg.handlers.user import format_rating
async def reset_counters(reset_month: bool, bot: Bot):
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(chat['id'], top_users, bot)
await bot.send_message(chat_id=chat['id'], **message.as_kwargs())
database.DB.reset_messages_month()
print('Месячные счетчики сброшены.')
async def wait_until(target_time: datetime.datetime):
now = datetime.datetime.now(target_time.tzinfo)
if now >= target_time:
return
delay_seconds = (target_time - now).total_seconds()
await sleep(delay_seconds)
async def daily_maintenance_task(bot: Bot):
tz = datetime.timezone(datetime.timedelta(hours=3), name="MSK")
target_time = datetime.time(6, 0, 0, tzinfo=tz)
now = datetime.datetime.now(tz)
if now.hour > target_time.hour or now.hour == target_time.hour and now.minute > target_time.minute:
target_date = now.date() + datetime.timedelta(days=1)
else:
target_date = now.date()
target_datetime = datetime.datetime.combine(target_date, target_time)
while True:
await wait_until(target_datetime)
try:
await reset_counters(target_datetime.day == 1, bot)
except Exception:
print(traceback.format_exc())
target_datetime = target_datetime + datetime.timedelta(days=1)
async def startup_task(bot: Bot):
me = await bot.get_me()
print(f"Бот '{me.full_name}' (id={me.id}) запущен.")

20
tg/tg_bot.py Normal file
View file

@ -0,0 +1,20 @@
import asyncio
from aiogram import Bot, Dispatcher
import config
import handlers
import tasks
async def main() -> None:
bot = Bot(token=config.Config['api_token'])
dp = Dispatcher()
dp.include_router(handlers.router)
dp.startup.register(tasks.startup_task)
asyncio.create_task(tasks.daily_maintenance_task(bot))
await dp.start_polling(bot)
asyncio.run(main())

31
tg/tg_database.py Normal file
View file

@ -0,0 +1,31 @@
import database
class TgDatabase(database.BasicDatabase):
def __init__(self):
super().__init__()
self.cursor.execute("""
CREATE TABLE IF NOT EXISTS chats (
"id" INTEGER,
"active" INTEGER NOT NULL DEFAULT 0,
"rules" TEXT,
"greeting_join" TEXT,
PRIMARY KEY("id"))
""")
self.cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
"chat_id" INTEGER,
"user_id" INTEGER,
"last_message" INTEGER NOT NULL DEFAULT 0,
"messages_today" INTEGER NOT NULL DEFAULT 0,
"messages_month" INTEGER NOT NULL DEFAULT 0,
"warnings" INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY("chat_id","user_id"))
""")
self.conn.commit()
DB = TgDatabase()

9
vk/handlers/__init__.py Normal file
View file

@ -0,0 +1,9 @@
from vkbottle.framework.labeler import BotLabeler
from . import user, admin, action, default
labeler = BotLabeler()
labeler.load(user.labeler)
labeler.load(admin.labeler)
labeler.load(action.labeler)
labeler.load(default.labeler)

View file

@ -1,15 +1,16 @@
from vkbottle.bot import Message from vkbottle.bot import Message
from vkbottle.framework.labeler import BotLabeler
import database
from messages import * from messages import *
import vk.vk_database as database
from labeler import labeler labeler = BotLabeler()
@labeler.chat_message(action=['chat_invite_user', 'chat_invite_user_by_link']) @labeler.chat_message(action=['chat_invite_user', 'chat_invite_user_by_link'])
async def user_join_handler(message: Message): async def user_join_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
return return
@ -37,7 +38,7 @@ async def user_join_handler(message: Message):
@labeler.chat_message(action=['chat_kick_user']) @labeler.chat_message(action=['chat_kick_user'])
async def user_leave_handler(message: Message): async def user_leave_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
return return

View file

@ -1,12 +1,13 @@
from vkbottle import bold, VKAPIError from vkbottle import bold, VKAPIError
from vkbottle.bot import Message from vkbottle.bot import Message
from vkbottle.framework.labeler import BotLabeler
from vkbottle_types.codegen.objects import MessagesGetConversationMembers from vkbottle_types.codegen.objects import MessagesGetConversationMembers
import database
from messages import * from messages import *
import utils import utils
import vk.vk_database as database
from labeler import labeler labeler = BotLabeler()
def vk_user_is_admin(user_id: int, chat_members: MessagesGetConversationMembers): def vk_user_is_admin(user_id: int, chat_members: MessagesGetConversationMembers):
@ -20,7 +21,7 @@ def vk_user_is_admin(user_id: int, chat_members: MessagesGetConversationMembers)
@labeler.chat_message(text="!старт") @labeler.chat_message(text="!старт")
async def start_handler(message: Message): async def start_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
database.create_chat_if_not_exists(chat_id) database.DB.create_chat_if_not_exists(chat_id)
chat_members = await message.ctx_api.messages.get_conversation_members(peer_id=chat_id, extended=False) chat_members = await message.ctx_api.messages.get_conversation_members(peer_id=chat_id, extended=False)
@ -34,7 +35,7 @@ async def start_handler(message: Message):
# Пропустить ботов # Пропустить ботов
if member.member_id < 0: if member.member_id < 0:
continue continue
database.create_user_if_not_exists(chat_id, member.member_id) database.DB.create_user_if_not_exists(chat_id, member.member_id)
await message.answer('Готова к работе!') await message.answer('Готова к работе!')
@ -42,7 +43,7 @@ async def start_handler(message: Message):
@labeler.chat_message(text="!правила") @labeler.chat_message(text="!правила")
async def rules_handler(message: Message): async def rules_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE) await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return return
@ -65,7 +66,7 @@ async def rules_handler(message: Message):
@labeler.chat_message(text="!приветствие") @labeler.chat_message(text="!приветствие")
async def set_greeting_join_handler(message: Message): async def set_greeting_join_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE) await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return return
@ -86,7 +87,7 @@ async def set_greeting_join_handler(message: Message):
@labeler.chat_message(text="!возвращение") @labeler.chat_message(text="!возвращение")
async def set_greeting_rejoin_handler(message: Message): async def set_greeting_rejoin_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE) await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return return
@ -107,7 +108,7 @@ async def set_greeting_rejoin_handler(message: Message):
@labeler.chat_message(text="!деньрождения") @labeler.chat_message(text="!деньрождения")
async def set_birthday_handler(message: Message): async def set_birthday_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE) await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return return
@ -128,7 +129,7 @@ async def set_birthday_handler(message: Message):
@labeler.chat_message(text="!предупреждение") @labeler.chat_message(text="!предупреждение")
async def warning_handler(message: Message): async def warning_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE) await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return return
@ -144,7 +145,7 @@ async def warning_handler(message: Message):
return return
user_id = message.reply_message.from_id user_id = message.reply_message.from_id
database.create_user_if_not_exists(chat_id, user_id) database.DB.create_user_if_not_exists(chat_id, user_id)
database.DB.user_increment_warnings(chat_id, user_id) database.DB.user_increment_warnings(chat_id, user_id)
user = database.DB.get_user(chat_id, user_id) user = database.DB.get_user(chat_id, user_id)
@ -162,7 +163,7 @@ async def warning_handler(message: Message):
@labeler.chat_message(text="!исключить") @labeler.chat_message(text="!исключить")
async def ban_handler(message: Message): async def ban_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE) await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return return

View file

@ -1,15 +1,17 @@
from vkbottle.bot import Message from vkbottle.bot import Message
from vkbottle.framework.labeler import BotLabeler
import database
import utils import utils
from labeler import labeler import vk.vk_database as database
labeler = BotLabeler()
# Обычные сообщения (не команды и не действия) # Обычные сообщения (не команды и не действия)
@labeler.chat_message() @labeler.chat_message()
async def any_message_handler(message: Message): async def any_message_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
return return
@ -22,6 +24,6 @@ async def any_message_handler(message: Message):
return return
user_id = message.from_id user_id = message.from_id
database.create_user_if_not_exists(chat_id, user_id) database.DB.create_user_if_not_exists(chat_id, user_id)
database.DB.user_set_last_message(chat_id, user_id, utils.posix_time()) database.DB.user_set_last_message(chat_id, user_id, utils.posix_time())
database.DB.user_increment_messages(chat_id, user_id) database.DB.user_increment_messages(chat_id, user_id)

View file

@ -2,11 +2,12 @@ from typing import List, Any
from vkbottle import bold, italic, API from vkbottle import bold, italic, API
from vkbottle.bot import Message from vkbottle.bot import Message
from vkbottle.framework.labeler import BotLabeler
import database
from messages import * from messages import *
import vk.vk_database as database
from labeler import labeler labeler = BotLabeler()
# top_users - массив sqlite3.Row с двумя столбцами: user_id и value # top_users - массив sqlite3.Row с двумя столбцами: user_id и value
@ -37,7 +38,7 @@ def calculate_total_messages(top_users: List[Any]) -> int:
@labeler.chat_message(text="!помощь") @labeler.chat_message(text="!помощь")
async def rules_handler(message: Message): async def rules_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE) await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return return
@ -67,7 +68,7 @@ async def rules_handler(message: Message):
@labeler.chat_message(text="!сегодня") @labeler.chat_message(text="!сегодня")
async def stats_today_handler(message: Message): async def stats_today_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE) await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return return
@ -86,7 +87,7 @@ async def stats_today_handler(message: Message):
@labeler.chat_message(text="!месяц") @labeler.chat_message(text="!месяц")
async def stats_month_handler(message: Message): async def stats_month_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE) await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return return
@ -105,7 +106,7 @@ async def stats_month_handler(message: Message):
@labeler.chat_message(text="!молчуны") @labeler.chat_message(text="!молчуны")
async def silent_handler(message: Message): async def silent_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE) await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return return
@ -123,7 +124,7 @@ async def silent_handler(message: Message):
@labeler.chat_message(text="!предупреждения") @labeler.chat_message(text="!предупреждения")
async def warnings_handler(message: Message): async def warnings_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE) await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return return
@ -141,13 +142,13 @@ async def warnings_handler(message: Message):
@labeler.chat_message(text="!поздравление") @labeler.chat_message(text="!поздравление")
async def no_birthday_handler(message: Message): async def no_birthday_handler(message: Message):
chat_id = message.peer_id chat_id = message.peer_id
chat = database.create_chat_if_not_exists(chat_id) chat = database.DB.create_chat_if_not_exists(chat_id)
if chat['active'] == 0: if chat['active'] == 0:
await message.answer(MESSAGE_CHAT_NOT_ACTIVE) await message.answer(MESSAGE_CHAT_NOT_ACTIVE)
return return
user_id = message.from_id user_id = message.from_id
user = database.create_user_if_not_exists(chat_id, user_id) user = database.DB.create_user_if_not_exists(chat_id, user_id)
happy_birthday = 1 if user['happy_birthday'] == 0 else 0 happy_birthday = 1 if user['happy_birthday'] == 0 else 0
database.DB.user_toggle_happy_birthday(chat_id, user_id, happy_birthday) database.DB.user_toggle_happy_birthday(chat_id, user_id, happy_birthday)

View file

@ -4,9 +4,9 @@ import traceback
from asyncio import sleep from asyncio import sleep
from vkbottle import API, bold from vkbottle import API, bold
import database
from handlers.user import format_rating
from messages import * from messages import *
import vk.vk_database as database
from vk.handlers.user import format_rating
async def reset_counters(reset_month: bool, api: API): async def reset_counters(reset_month: bool, api: API):
@ -46,7 +46,7 @@ async def check_birthdays(api: API):
user_id = item.member_id user_id = item.member_id
if user_id < 0: if user_id < 0:
continue continue
user = database.create_user_if_not_exists(chat_id, user_id) user = database.DB.create_user_if_not_exists(chat_id, user_id)
for profile in members.profiles: for profile in members.profiles:
if profile.id == user_id: if profile.id == user_id:

View file

@ -2,13 +2,10 @@ import config
import handlers import handlers
import tasks import tasks
from labeler import labeler from vkbottle.bot import Bot as VkBot
from vkbottle.bot import Bot
assert handlers bot = VkBot(config.Config['api_token'], labeler=handlers.labeler)
bot = Bot(config.Config['api_token'], labeler=labeler)
bot.loop_wrapper.on_startup.append(tasks.startup_task(bot.api)) bot.loop_wrapper.on_startup.append(tasks.startup_task(bot.api))
bot.loop_wrapper.add_task(tasks.daily_maintenance_task(bot.api)) bot.loop_wrapper.add_task(tasks.daily_maintenance_task(bot.api))
bot.run_forever() bot.run_forever()

37
vk/vk_database.py Normal file
View file

@ -0,0 +1,37 @@
import database
class VkDatabase(database.BasicDatabase):
def __init__(self):
super().__init__()
self.cursor.execute("""
CREATE TABLE IF NOT EXISTS chats (
"id" INTEGER,
"active" INTEGER NOT NULL DEFAULT 0,
"rules" TEXT,
"greeting_join" TEXT,
"greeting_rejoin" TEXT,
"birthday_message" TEXT,
PRIMARY KEY("id"))
""")
self.cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
"chat_id" INTEGER,
"user_id" INTEGER,
"last_message" INTEGER NOT NULL DEFAULT 0,
"messages_today" INTEGER NOT NULL DEFAULT 0,
"messages_month" INTEGER NOT NULL DEFAULT 0,
"warnings" INTEGER NOT NULL DEFAULT 0,
"happy_birthday" INTEGER NOT NULL DEFAULT 1,
PRIMARY KEY("chat_id","user_id"))
""")
self.conn.commit()
def user_toggle_happy_birthday(self, chat_id: int, user_id: int, happy_birthday: int):
self.user_update(chat_id, user_id, happy_birthday=happy_birthday)
DB = VkDatabase()