MySQL no longer supported, antispam thing remaded

This commit is contained in:
dan63047 2022-04-10 19:13:38 +03:00
parent cc109af0cf
commit 3cac828cae
3 changed files with 65 additions and 180 deletions

View File

@ -43,7 +43,7 @@
Теперь заходим в директорию бота (`cd dan63047pythonbot/`) и устанавливаем необходимые библиотеки: Теперь заходим в директорию бота (`cd dan63047pythonbot/`) и устанавливаем необходимые библиотеки:
`pip3 install vk-api pyowm Wikipedia-API PyMySQL --user` `pip3 install vk-api pyowm Wikipedia-API --user`
Эта команда установит все необходимые библиотеки для работы бота. Эта команда установит все необходимые библиотеки для работы бота.
@ -58,18 +58,11 @@ admins = [276193568, 629085267] # Список ид аккаунтов адми
vk_service_token = "vk_service_token" # Сервисный ключ доступа для команды !image. Оставьте None, если хотите выключить эту команду vk_service_token = "vk_service_token" # Сервисный ключ доступа для команды !image. Оставьте None, если хотите выключить эту команду
album_for_command = 269199619 # Цифровой ид альбома для команды !image. Оставьте None, если хотите выключить эту команду album_for_command = 269199619 # Цифровой ид альбома для команды !image. Оставьте None, если хотите выключить эту команду
openweathermap_api_key = 'openweathermap_api_key' # Ключ OpenWeather API. Оставьте None, если хотите выключить команду !weather openweathermap_api_key = 'openweathermap_api_key' # Ключ OpenWeather API. Оставьте None, если хотите выключить команду !weather
use_database = True # False, если вы не планируете использовать MySQL базу данных, иначе следующие 4 строки обязательны
mysql_host = 'pythonanywhere_nickname.mysql.pythonanywhere-services.com' # ссылка на хост БД. Вместо pythonanywhere_nickname должен быть ваш никнейм на pythonanywhere
mysql_user = 'pythonanywhere_nickname' # Ваш никнейм на pythonanywhere
mysql_pass = 'qwerty123' # Пароль, созданный вами для БД
mysql_db = 'pythonanywhere_nickname$default' # Название вашей БД. Вместо pythonanywhere_nickname должен быть ваш никнейм на pythonanywhere. Так же вместо default может быть ваше название БД
``` ```
## Если вы будете использовать команду !image ## Если вы будете использовать команду !image
Разберёмся с костылём для метода `photos.get`: Идем на `vk.com/dev`, нажимаем на *Мои приложения* и кликаем по *Создать приложение*. Новое приложение может называться как угодно, от него нам необходимо всего лишь сервисный ключ доступа, который можно найти, если нажать на *Настройки* Разберёмся с костылём для метода `photos.get`: Идем на `vk.com/dev`, нажимаем на *Мои приложения* и кликаем по *Создать приложение*. Новое приложение может называться как угодно, от него нам необходимо всего лишь сервисный ключ доступа, который можно найти, если нажать на *Настройки*
## Если вы будете использовать команду !weather ## Если вы будете использовать команду !weather
Перейдите по `openweathermap.org`, пройдите там регистрацию и создайте API ключ Перейдите по `openweathermap.org`, пройдите там регистрацию и создайте API ключ
## Если вы решите использовать MySQL БД (давно не тестировалось, может не работать)
Вам необходимо будет купить тариф на pythonanywhere, где есть поддержка MySQL базы данных, с которой бот будет работать. Тыкаем на *Databases* в шапке сайта. Создаём пароль для вашей базы данных. По умолчанию будет создана база данных с названием `your_nickname$default`, но вы можете создать БД со своим названием.
## Запуск бота ## Запуск бота
Если аккаунт платный: в pythonanywhere тыкаем на *Tasks*, создаём и запускаем в *Always-on tasks* задачу `python3.8 /home/pythonanywhere_nickname/dan63047pythonbot/longpulling.py`, где вместо pythonanywhere_nickname должен быть ваш никнейм на pythonanywhere. После небольшого тупления pythonanywhere запустит вашего бота. Если аккаунт платный: в pythonanywhere тыкаем на *Tasks*, создаём и запускаем в *Always-on tasks* задачу `python3.8 /home/pythonanywhere_nickname/dan63047pythonbot/longpulling.py`, где вместо pythonanywhere_nickname должен быть ваш никнейм на pythonanywhere. После небольшого тупления pythonanywhere запустит вашего бота.
@ -94,9 +87,7 @@ mysql_db = 'pythonanywhere_nickname$default' # Название вашей БД.
* [vk_api](https://github.com/python273/vk_api) — модуль для создания скриптов для социальной сети Вконтакте * [vk_api](https://github.com/python273/vk_api) — модуль для создания скриптов для социальной сети Вконтакте
* [pyowm](https://github.com/csparpa/pyowm) — модуль для получения погоды через OpenWeather API * [pyowm](https://github.com/csparpa/pyowm) — модуль для получения погоды через OpenWeather API
* [Wikipedia-API](https://github.com/martin-majlis/Wikipedia-API) — модуль для получения статей из Wikipedia * [Wikipedia-API](https://github.com/martin-majlis/Wikipedia-API) — модуль для получения статей из Wikipedia
* [PyMySQL](https://github.com/PyMySQL/PyMySQL/) — Pure Python MySQL Client
# Дополнительно # Дополнительно
Автор бота: [Даниил Михайлов](https://vk.com/dan63047) Автор бота: [Даниил Михайлов](https://vk.com/dan63047)
Буду рад помощи и поддержке Буду рад помощи и поддержке

View File

@ -43,6 +43,7 @@ def log(warning, text):
print(msg) print(msg)
bot = {} bot = {}
SPAMMER_LIST = {}
errors_array = {"access": "Отказано в доступе", errors_array = {"access": "Отказано в доступе",
"miss_argument": "Отсуствует аргумент", "miss_argument": "Отсуствует аргумент",
"command_off": "Команда отключена", "command_off": "Команда отключена",
@ -94,156 +95,61 @@ except Exception:
class Database_worker(): class Database_worker():
def __init__(self): def __init__(self):
if config.use_database: try:
log(False, "Trying to connect to database") with open("data.json", "r") as data:
try: self._DATA_DIST = json.load(data)
self._CON = pymysql.connect( data.close()
host=config.mysql_host, except Exception:
user=config.mysql_user, log(True, "data.json is not exist, it will be created")
password=config.mysql_pass, self._DATA_DIST = {"users": {}, "spammers": []}
db=config.mysql_db, open("data.json", "w").write(json.dumps(self._DATA_DIST))
charset='utf8mb4',
cursorclass=DictCursor
)
cur = self._CON.cursor()
except Exception as e:
debug_array['db_warnings'] += 1
log(True, f"Unable to connect to database: {str(e)}")
try:
cur.execute("SELECT * FROM bot_users")
except:
cur.execute("CREATE TABLE bot_users ( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, chat_id INT UNSIGNED, awaiting VARCHAR(128), access TINYINT, midnight BOOL, new_post BOOL, admin_mode BOOL, game_wins INT UNSIGNED, game_defeats INT UNSIGNED, game_draws INT UNSIGNED, banned BOOL)")
cur.close()
log(False, "Database connection established")
else:
log(False, "Bot will use JSON file as database")
try:
with open("data.json", "r") as data:
self._DATA_DIST = json.load(data)
data.close()
except Exception:
log(True, "data.json is not exist, it will be created soon")
self._DATA_DIST = {"users": {}}
def set_new_user(self, peer_id, midnight=False, awaiting=None, access=1, new_post=False, admin_mode=False, game_wins=0, game_defeats=0, game_draws=0, banned=False): def set_new_user(self, peer_id, midnight=False, awaiting=None, access=1, new_post=False, admin_mode=False, game_wins=0, game_defeats=0, game_draws=0, banned=False):
if(config.use_database): self._DATA_DIST['users'][peer_id] = {"awaiting": awaiting, "access": access, "midnight": midnight, "new_post": new_post, "admin_mode": admin_mode, "game_wins": game_wins, "game_defeats": game_defeats, "game_draws": game_draws, "banned": banned}
try: open("data.json", "w").write(json.dumps(self._DATA_DIST))
cur = self._CON.cursor()
cur.execute("INSERT INTO bot_users (chat_id, awaiting, access, midnight, new_post, admin_mode, game_wins, game_defeats, game_draws, banned) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
(peer_id, awaiting, access, midnight, new_post, admin_mode, game_wins, game_defeats, game_draws, banned))
self._CON.commit()
cur.close()
except Exception as e:
debug_array['db_warnings'] += 1
log(True, f"Unable to add new user in database: {str(e)}")
else:
self._DATA_DIST['users'][peer_id] = {"awaiting": awaiting, "access": access, "midnight": midnight, "new_post": new_post,
"admin_mode": admin_mode, "game_wins": game_wins, "game_defeats": game_defeats, "game_draws": game_draws, "banned": banned}
open("data.json", "w").write(json.dumps(self._DATA_DIST))
def get_all_users(self): def get_all_users(self):
if not config.use_database: with open("data.json", "r") as data:
with open("data.json", "r") as data: self._DATA_DIST = json.load(data)
self._DATA_DIST = json.load(data) data.close()
data.close() return self._DATA_DIST['users']
return self._DATA_DIST['users']
try:
cur = self._CON.cursor()
cur.execute("SELECT * FROM bot_users")
result = cur.fetchall()
cur.close()
return result
except Exception as e:
debug_array['db_warnings'] += 1
log(True, f"Unable to load user from database: {str(e)}")
def get_from_users(self, from_id): def get_from_users(self, from_id):
if not config.use_database: with open("data.json", "r") as data:
with open("data.json", "r") as data: self._DATA_DIST = json.load(data)
self._DATA_DIST = json.load(data) data.close()
data.close() if not self._DATA_DIST['users'].get(str(from_id)):
if not self._DATA_DIST['users'].get(str(from_id)): self.set_new_user(str(from_id))
self.set_new_user(str(from_id)) return self._DATA_DIST['users'][str(from_id)]
return self._DATA_DIST['users'][str(from_id)]
try:
cur = self._CON.cursor()
cur.execute(
"SELECT * FROM bot_users WHERE chat_id = %s", (from_id))
result = cur.fetchall()
cur.close()
return result
except Exception as e:
debug_array['db_warnings'] += 1
log(True, f"Unable to load user from database: {str(e)}")
def get_game_stat(self): def get_game_stat(self):
if not config.use_database: return self._DATA_DIST['users']
return self._DATA_DIST['users']
try:
cur = self._CON.cursor()
cur.execute(
"SELECT chat_id, game_wins, game_draws, game_defeats FROM bot_users WHERE game_wins > 0 OR game_draws > 0 OR game_defeats > 0")
result = cur.fetchall()
cur.close()
return result
except Exception as e:
debug_array['db_warnings'] += 1
log(True, f"Unable to load stats from database: {str(e)}")
# Info: dist cannot return only the necessary keys
def update_user(self, chat_id, thing, new_value): def update_user(self, chat_id, thing, new_value):
if(config.use_database): self._DATA_DIST['users'][str(chat_id)][thing] = new_value
try: open("data.json", "w").write(json.dumps(self._DATA_DIST))
cur = self._CON.cursor()
cur.execute(f"UPDATE bot_users SET {thing} = %s WHERE bot_users.chat_id = %s;", (new_value, chat_id))
self._CON.commit()
cur.close()
except Exception as e:
debug_array['db_warnings'] += 1
log(True, f"Unable to update info about user in database: {str(e)}")
else:
if not self._DATA_DIST['users'][str(chat_id)].get(thing):
if thing == "spam_list":
self._DATA_DIST['users'][str(chat_id)][thing] = []
self._DATA_DIST['users'][str(chat_id)][thing] = new_value
open("data.json", "w").write(json.dumps(self._DATA_DIST))
def delete_user(self, chat_id): def delete_user(self, chat_id):
if(config.use_database): self._DATA_DIST['users'].pop(str(chat_id))
try: open("data.json", "w").write(json.dumps(self._DATA_DIST))
cur = self._CON.cursor()
cur.execute( def add_spammer(self, user_id):
"DELETE FROM bot_users, game_defeats WHERE chat_id = %s", (chat_id)) SPAMMER_LIST.append(int(user_id))
self._CON.commit() self._DATA_DIST["spammers"].append(int(user_id))
cur.close() open("data.json", "w").write(json.dumps(self._DATA_DIST))
return True
except Exception as e: def remove_spammer(self, user_id):
debug_array['db_warnings'] += 1 SPAMMER_LIST.pop(int(user_id))
log(True, f"Unable to delete user from database: {str(e)}") self._DATA_DIST["spammers"].pop(int(user_id))
return False open("data.json", "w").write(json.dumps(self._DATA_DIST))
else:
self._DATA_DIST['users'].pop(str(chat_id)) def read_spammers(self):
open("data.json", "w").write(json.dumps(self._DATA_DIST)) return self._DATA_DIST["spammers"]
db = Database_worker() db = Database_worker()
def load_users():
try:
log(False, "Reading database")
get_info = db.get_all_users()
for i in get_info:
if config.use_database:
bot[int(i['chat_id'])] = VkBot(int(i['chat_id']), bool(i['midnight']), i['awaiting'], int(
i['access']), bool(i['new_post']), bool(i['admin_mode']), bool(i['banned']))
else:
bot[int(i)] = VkBot(int(i), bool(get_info[i]['midnight']), get_info[i]['awaiting'], int(
get_info[i]['access']), bool(get_info[i]['new_post']), bool(get_info[i]['admin_mode']), bool(get_info[i]['banned']))
except Exception as lol:
debug_array['bot_warnings'] += 1
log(True, f"Problem with creating objects: {str(lol)}")
def toFixed(numObj, digits=0): def toFixed(numObj, digits=0):
return f"{numObj:.{digits}f}" return f"{numObj:.{digits}f}"
@ -306,7 +212,6 @@ class VkBot:
""" """
log(False, f"[BOT_{peer_id}] Created new bot-object") log(False, f"[BOT_{peer_id}] Created new bot-object")
self._CHAT_ID = peer_id self._CHAT_ID = peer_id
self._SPAMMER_LIST = {}
self._AWAITING_INPUT_MODE = awaiting self._AWAITING_INPUT_MODE = awaiting
self._ACCESS_TO_ALL = access self._ACCESS_TO_ALL = access
self._MIDNIGHT_EVENT = midnight self._MIDNIGHT_EVENT = midnight
@ -375,17 +280,19 @@ class VkBot:
action = event.message.action action = event.message.action
if action['type'] == 'chat_invite_user' or action['type'] == 'chat_invite_user_by_link': if action['type'] == 'chat_invite_user' or action['type'] == 'chat_invite_user_by_link':
user_info = vk.method('users.get', {'user_ids': action["member_id"], 'fields': 'verified,last_seen,sex'}) user_info = vk.method('users.get', {'user_ids': action["member_id"], 'fields': 'verified,last_seen,sex'})
chat_info = db.get_from_users(int(self._CHAT_ID)) if int(action["member_id"]) in SPAMMER_LIST:
if chat_info.get("spam_list"): self.send(f'[id{action["member_id"]}|Данный пользователь] находится в антиспам базе. Исключаю...')
if int(action["member_id"]) in chat_info["spam_list"]: vk.method("messages.removeChatUser", {"chat_id": int(self._CHAT_ID)-2000000000, "member_id": action["member_id"]})
self.send(f'Привет, {user_info[0]["first_name"]}. К сожалению, администраторы этой беседы признали тебя спамером, поэтому мне придётся выгнать тебя отсюда') return
vk.method("messages.removeChatUser", {"chat_id": int(self._CHAT_ID)-2000000000, "member_id": action["member_id"]})
return
self.send(f'Добро пожаловать в беседу, {user_info[0]["first_name"]} {user_info[0]["last_name"]}') self.send(f'Добро пожаловать в беседу, {user_info[0]["first_name"]} {user_info[0]["last_name"]}')
elif action['type'] == 'chat_kick_user': elif action['type'] == 'chat_kick_user':
pass pass
# user_info = vk.method('users.get', {'user_ids': action["member_id"], 'fields': 'verified,last_seen,sex'}) # user_info = vk.method('users.get', {'user_ids': action["member_id"], 'fields': 'verified,last_seen,sex'})
# self.send(f'{user_info[0]["first_name"]} {user_info[0]["last_name"]} покинул беседу') # self.send(f'{user_info[0]["first_name"]} {user_info[0]["last_name"]} покинул беседу')
if event.message.peer_id > 2000000000 and int(user_id) in SPAMMER_LIST:
self.send(f'[id{user_id}|Данный пользователь] находится в антиспам базе. Исключаю...')
vk.method("messages.removeChatUser", {"chat_id": int(self._CHAT_ID)-2000000000, "member_id": user_id})
return
if self._AWAITING_INPUT_MODE: if self._AWAITING_INPUT_MODE:
if message == "Назад": if message == "Назад":
self.change_await() self.change_await()
@ -645,14 +552,10 @@ class VkBot:
message = message[1].split(' ', 1) message = message[1].split(' ', 1)
victum = re.search(r'id\d+', message[1]) victum = re.search(r'id\d+', message[1])
victum = victum[0][2:] victum = victum[0][2:]
if db.get_from_users(int(self._CHAT_ID)).get("spam_list"): if message[0] == "add" or message[0] == "добавить":
chat_spammers_list = db.get_from_users(int(self._CHAT_ID))["spam_list"]
else:
chat_spammers_list = []
if message[0] == "add" or message [0] == "добавить":
if int(victum) != int(config.owner_id): if int(victum) != int(config.owner_id):
if int(victum) not in chat_spammers_list: if int(victum) not in SPAMMER_LIST:
chat_spammers_list.append(int(victum)) db.add_spammer(int(victum))
respond["text"] = "Теперь он считается спамером" respond["text"] = "Теперь он считается спамером"
log(False, f"[BOT_{self._CHAT_ID}] user {victum} added to spammer list") log(False, f"[BOT_{self._CHAT_ID}] user {victum} added to spammer list")
else: else:
@ -661,15 +564,14 @@ class VkBot:
log(False, f"[BOT_{self._CHAT_ID}] can't add to spammer list owner") log(False, f"[BOT_{self._CHAT_ID}] can't add to spammer list owner")
elif message[0] == "remove" or message[0] == "удалить": elif message[0] == "remove" or message[0] == "удалить":
if int(victum) != int(config.owner_id): if int(victum) != int(config.owner_id):
if int(victum) in chat_spammers_list: if int(victum) in SPAMMER_LIST:
chat_spammers_list.pop(int(victum)) db.remove_spammer(int(victum))
respond["text"] = "Теперь он не считается спамером" respond["text"] = "Теперь он не считается спамером"
log(False, f"[BOT_{self._CHAT_ID}] user {victum} removed to spammer list") log(False, f"[BOT_{self._CHAT_ID}] user {victum} removed to spammer list")
else: else:
respond["text"] = "Его нет в этой базе" respond["text"] = "Его нет в этой базе"
else: else:
log(False, f"[BOT_{self._CHAT_ID}] can't restore owner") log(False, f"[BOT_{self._CHAT_ID}] can't restore owner")
db.update_user(int(self._CHAT_ID), "spam_list", chat_spammers_list)
except IndexError: except IndexError:
respond['text'] = errors_array["miss_argument"] respond['text'] = errors_array["miss_argument"]
except Exception as e: except Exception as e:
@ -758,14 +660,7 @@ class VkBot:
return answer return answer
def game(self, thing, user_id): def game(self, thing, user_id):
data = db.get_from_users(user_id) d = db.get_from_users(user_id)
if (config.use_database):
if len(data) == 0:
create_new_bot_object(user_id)
data = db.get_from_users(user_id)
d = data[0]
else:
d = data
if thing == "статистика": if thing == "статистика":
try: try:
winrate = (d['game_wins']/(d['game_wins'] + winrate = (d['game_wins']/(d['game_wins'] +

View File

@ -41,18 +41,20 @@ def bots():
log_msg += atch log_msg += atch
dan63047VKbot.log(False, log_msg) dan63047VKbot.log(False, log_msg)
dan63047VKbot.debug_array['messages_get'] += 1 dan63047VKbot.debug_array['messages_get'] += 1
if int(event.message.peer_id) not in dan63047VKbot.bot: if event.message.peer_id not in dan63047VKbot.bot:
dan63047VKbot.create_new_bot_object(event.message.peer_id) u = dan63047VKbot.db.get_all_users()
if str(event.message.peer_id) not in u:
dan63047VKbot.create_new_bot_object(event.message.peer_id)
else:
i = dan63047VKbot.db.get_from_users(event.message.peer_id)
dan63047VKbot.bot[event.message.peer_id] = dan63047VKbot.VkBot(event.message.peer_id, bool(i['midnight']), i['awaiting'], int(i['access']), bool(i['new_post']), bool(i['admin_mode']), bool(i['banned']))
dan63047VKbot.bot[event.message.peer_id].get_message(event) dan63047VKbot.bot[event.message.peer_id].get_message(event)
elif event.type == dan63047VKbot.VkBotEventType.WALL_POST_NEW: elif event.type == dan63047VKbot.VkBotEventType.WALL_POST_NEW:
if event.object.post_type == "post": if event.object.post_type == "post":
dan63047VKbot.log(False, f"[NEW_POST] id{event.object.id}") dan63047VKbot.log(False, f"[NEW_POST] id{event.object.id}")
users = dan63047VKbot.db.get_all_users() users = dan63047VKbot.db.get_all_users()
for i in users: for i in users:
if (config.use_database): dan63047VKbot.bot[int(i)].event("post", event.object)
dan63047VKbot.bot[int(i['chat_id'])].event("post", event.object)
else:
dan63047VKbot.bot[int(i)].event("post", event.object)
else: else:
dan63047VKbot.log(False, f"[NEW_OFFER] id{event.object.id}") dan63047VKbot.log(False, f"[NEW_OFFER] id{event.object.id}")
elif event.type == dan63047VKbot.VkBotEventType.MESSAGE_DENY: elif event.type == dan63047VKbot.VkBotEventType.MESSAGE_DENY:
@ -75,17 +77,14 @@ def midnight():
dan63047VKbot.log(False, "[EVENT_STARTED] \"Midnight\"") dan63047VKbot.log(False, "[EVENT_STARTED] \"Midnight\"")
users = dan63047VKbot.db.get_all_users() users = dan63047VKbot.db.get_all_users()
for i in users: for i in users:
if (config.use_database): dan63047VKbot.bot[int(i)].event("midnight")
dan63047VKbot.bot[int(i['chat_id'])].event("midnight")
else:
dan63047VKbot.bot[int(i)].event("midnight")
dan63047VKbot.log(False, "[EVENT_ENDED] \"Midnight\"") dan63047VKbot.log(False, "[EVENT_ENDED] \"Midnight\"")
time.sleep(1) time.sleep(1)
else: else:
time.sleep(0.50) time.sleep(0.50)
dan63047VKbot.load_users() dan63047VKbot.SPAMMER_LIST = dan63047VKbot.db.read_spammers()
tread_bots = threading.Thread(target=bots) tread_bots = threading.Thread(target=bots)
tread_midnight = threading.Thread(target=midnight, daemon=True) tread_midnight = threading.Thread(target=midnight, daemon=True)
tread_bots.start() tread_bots.start()