diff --git a/client_classes/DiscordClient.py b/client_classes/DiscordClient.py new file mode 100644 index 0000000..61094de --- /dev/null +++ b/client_classes/DiscordClient.py @@ -0,0 +1,24 @@ +import discord +from client_classes.Message import Message + + +class DiscordClient(discord.Client): + def __init__(self, compute_message_func): + super(DiscordClient, self).__init__() + self.compute_massage = compute_message_func + + async def on_message(self, message): + if message.author != self.user: + from_id = message.channel.id + text = message.content + author_id = message.author.id + author_name = message.author.name + if type(message.channel) != discord.channel.DMChannel: + chat_name = message.author.guild.name + "/" + message.channel.name + is_owner = message.author.guild_permissions.administrator + self.compute_massage(Message((from_id, "DS"), text, author_id, author_name, chat_name=chat_name, is_owner=is_owner)) + else: + self.compute_massage(Message((from_id, "DS"), text, author_id, author_name)) + + def send_msg(self, id, text): + self.loop.create_task(self.get_channel(id).send(text)) diff --git a/client_classes/Message.py b/client_classes/Message.py new file mode 100644 index 0000000..e006b45 --- /dev/null +++ b/client_classes/Message.py @@ -0,0 +1,28 @@ +class Message: + def __init__(self, from_id, text, author_id, author_name, chat_name=None, is_owner=None): + self.from_id = from_id + self.text = text + self.author_id = author_id + self.author_name = author_name + self.chat_name = chat_name + self.is_owner = is_owner + + def is_chat_command(self): + return len(self.text) > 0 and self.text[0] == "!" + + def get_chat_id(self): + return str(self.from_id[0]) + self.from_id[1] + + def get_author_id(self): + return str(self.author_id) + self.from_id[1] + + def get_chat_command(self): + if not self.is_chat_command(): + return None + return self.text[1:].strip() + + def get_text_to_forwarding(self): + description = "" + if self.author_name is not None: + description += self.author_name + ":\n" + return description + self.text diff --git a/client_classes/TelegramClient.py b/client_classes/TelegramClient.py new file mode 100644 index 0000000..db852f3 --- /dev/null +++ b/client_classes/TelegramClient.py @@ -0,0 +1,35 @@ +import threading +import telebot +from client_classes.Message import Message + + +class TelegramClient: + def __init__(self, compute_message_func): + self.client = None + self.handler_thread = None + self.compute_massage = compute_message_func + + def __handler(self): + @self.client.message_handler(content_types=["text"]) + def on_message(message): + from_id = message.chat.id + text = message.text + author_id = message.from_user.id + author = self.client.get_chat_member(from_id, author_id) + author_name = message.from_user.last_name + " " + message.from_user.first_name + if from_id != author_id: + chat_name = message.chat.title + is_owner = author.status == "creator" + self.compute_massage(Message((from_id, "TG"), text, author_id, author_name, chat_name=chat_name, is_owner=is_owner)) + else: + self.compute_massage(Message((from_id, "TG"), text, author_id, author_name)) + + self.client.infinity_polling() + + def send_msg(self, id, text): + self.client.send_message(id, text) + + def run(self, token): + self.client = telebot.TeleBot(token) + self.handler_thread = threading.Thread(target=self.__handler) + self.handler_thread.start() diff --git a/client_classes/VkClient.py b/client_classes/VkClient.py new file mode 100644 index 0000000..ccf5cc3 --- /dev/null +++ b/client_classes/VkClient.py @@ -0,0 +1,55 @@ +import threading +import vk_api +from vk_api.bot_longpoll import VkBotLongPoll, VkBotEventType +from client_classes.Message import Message + + +class VkClient: + def __init__(self, compute_message_func): + self.client = None + self.group_id = None + self.handler_thread = None + self.compute_massage = compute_message_func + + def __get_peer_id_by_id(self, id): + return id + 2000000000 + + def __get_user(self, id): + return self.client.method("users.get", {"user_ids": id})[0] + + def __get_chat(self, id): + chat = self.client.method("messages.getConversationsById", {"peer_ids": self.__get_peer_id_by_id(id)}) + if chat["count"] == 0: + return {"chat_settings": {"title": "NULL"}} + return chat["items"][0] + + def __handler(self): + longpoll = VkBotLongPoll(self.client, self.group_id) + + for event in longpoll.listen(): + if event.type == VkBotEventType.MESSAGE_NEW: + text = event.object["message"]["text"] + author = self.__get_user(event.object["message"]["from_id"]) + author_id = event.object["message"]["from_id"] + author_name = author["last_name"] + " " + author["first_name"] + if event.from_chat: + from_id = event.chat_id + chat = self.__get_chat(event.chat_id) + chat_name = chat["chat_settings"]["title"] + is_owner = author_id == chat["chat_settings"]["owner_id"] + self.compute_massage(Message((from_id, "VK"), text, author_id, author_name, chat_name=chat_name, is_owner=is_owner)) + else: + from_id = event.object["message"]["from_id"] + self.compute_massage(Message((from_id, "VK"), text, author_id, author_name)) + + def send_msg(self, id, text, to_chat): + if to_chat: + self.client.method("messages.send", {"chat_id": id, "message": text, "random_id": 0}) + else: + self.client.method("messages.send", {"user_id": id, "message": text, "random_id": 0}) + + def run(self, token, group_id): + self.client = vk_api.VkApi(token=token) + self.group_id = group_id + self.handler_thread = threading.Thread(target=self.__handler) + self.handler_thread.start() diff --git a/config.py b/config.py index fa48ddd..49e36d8 100644 --- a/config.py +++ b/config.py @@ -5,5 +5,6 @@ TELEGRAM_TOKEN = "" -GRAPH_STORAGE_NAME = "graph.txt" -ERROR_LOG_NAME = "error_log.txt" +GRAPH_STORAGE_NAME = "data/graph.txt" +ERROR_LOG_NAME = "data/error_log.txt" +USERS_INFORMATION_DB_NAME = "data/users_inf.db" diff --git a/error_log.txt b/data/error_log.txt similarity index 100% rename from error_log.txt rename to data/error_log.txt diff --git a/graph.txt b/data/graph.txt similarity index 100% rename from graph.txt rename to data/graph.txt diff --git a/main.py b/main.py index ee2b743..c71efa4 100644 --- a/main.py +++ b/main.py @@ -1,289 +1,10 @@ -import threading -import queue -import vk_api -from vk_api.bot_longpoll import VkBotLongPoll, VkBotEventType -import discord -import telebot import config - - -class Graph: - def __init__(self, graph_storage_name): - graph_storage = open(graph_storage_name, "r") - self.graph_storage_name = graph_storage_name - self.adjacency_list = dict() - self.graph_storage_size = 0 - for line in graph_storage.readlines(): - type_operation, vertex1, vertex2 = self.__convert_text_to_operation(line) - - if type_operation == "+": - self.add_edge(vertex1, vertex2, save_operation=False) - else: - self.erase_edge(vertex1, vertex2, save_operation=False) - self.graph_storage_size += 1 - - def __convert_text_to_operation(self, text): - text = text.split() - return text[0], (int(text[1]), text[2]), (int(text[3]), text[4]) - - def __convert_operation_to_text(self, type_operation, vertex1, vertex2): - return type_operation + " " + str(vertex1[0]) + " " + vertex1[1] + " " + str(vertex2[0]) + " " + vertex2[ - 1] + "\n" - - def __reset_graph_storage(self): - graph_storage = open(self.graph_storage_name, "w") - used = set() - self.graph_storage_size = 0 - for vertex1 in self.adjacency_list: - for vertex2 in self.adjacency_list[vertex1]: - if (vertex1, vertex2) in used or (vertex2, vertex1) in used: - continue - - used.add((vertex1, vertex2)) - graph_storage.write(self.__convert_operation_to_text("+", vertex1, vertex2)) - self.graph_storage_size += 1 - graph_storage.close() - - def __add_operation_to_storage(self, type_operation, vertex1, vertex2): - graph_storage = open(self.graph_storage_name, "a") - graph_storage.write(self.__convert_operation_to_text(type_operation, vertex1, vertex2)) - graph_storage.close() - - self.graph_storage_size += 1 - if self.graph_storage_size >= len(self.adjacency_list) ** 2: - self.__reset_graph_storage() - - def get_reachable_vertices(self, vertex_start): - used = set() - used.add(vertex_start) - q = queue.Queue() - q.put(vertex_start) - while not q.empty(): - v = q.get() - for to in self.adjacency_list[v]: - if to in used: - continue - - used.add(to) - q.put(to) - - used.discard(vertex_start) - return list(used) - - def add_vertex(self, vertex): - if not (vertex in self.adjacency_list): - self.adjacency_list[vertex] = set() - - def add_edge(self, vertex1, vertex2, save_operation=True): - self.add_vertex(vertex1) - self.add_vertex(vertex2) - self.adjacency_list[vertex1].add(vertex2) - self.adjacency_list[vertex2].add(vertex1) - if save_operation: - self.__add_operation_to_storage("+", vertex1, vertex2) - - def erase_edge(self, vertex1, vertex2, save_operation=True): - if vertex1 in self.adjacency_list: - self.adjacency_list[vertex1].discard(vertex2) - if vertex2 in self.adjacency_list: - self.adjacency_list[vertex2].discard(vertex1) - if save_operation: - self.__add_operation_to_storage("-", vertex1, vertex2) - - -class Message: - def __init__(self, from_id, text, author_name, chat_name): - self.from_id = from_id - self.text = text - self.author_name = author_name - self.chat_name = chat_name - - def is_command(self): - return len(self.text) > 0 and self.text[0] == "!" - - def get_command(self): - if not self.is_command(): - return None - return self.text[1:].strip().lower() - - def get_text_to_forwarding(self): - description = "" - if self.chat_name != None: - description += " [" + self.chat_name + "]" - if self.author_name != None: - description += ", " + self.author_name - if self.chat_name != None or self.author_name != None: - description = self.from_id[1] + description + ":\n" - return description + self.text - - -class VkClient: - def __init__(self): - self.vk_client = None - self.group_id = None - self.handler_thread = None - - def __get_user(self, id): - return self.vk_client.method("users.get", {"user_ids": id})[0] - - def __get_chat(self, id): - chat = self.vk_client.method("messages.getConversationsById", {"peer_ids": id + 2000000000}) - if chat["count"] == 0: - return {"chat_settings": {"title": None}} - return chat["items"][0] - - def __handler(self): - longpoll = VkBotLongPoll(self.vk_client, self.group_id) - - for event in longpoll.listen(): - if event.type == VkBotEventType.MESSAGE_NEW and event.from_chat: - author = self.__get_user(event.object["message"]["from_id"]) - author_name = author["last_name"] + " " + author["first_name"] - chat = self.__get_chat(event.chat_id) - chat_name = chat["chat_settings"]["title"] - compute_message(Message((event.chat_id, "VK"), event.object["message"]["text"], author_name, chat_name)) - - def send_msg(self, id, text): - self.vk_client.method("messages.send", {"chat_id": id, "message": text, "random_id": 0}) - - def run(self, token, group_id): - self.vk_client = vk_api.VkApi(token=token) - self.group_id = group_id - self.handler_thread = threading.Thread(target=self.__handler) - self.handler_thread.start() - - -class TelegramClient: - def __init__(self): - self.telegram_client = None - self.handler_thread = None - - def __handler(self): - @self.telegram_client.message_handler(content_types=["text"]) - def on_message(message): - author_name = message.from_user.last_name + " " + message.from_user.first_name - chat_name = message.chat.title - compute_message(Message((message.chat.id, "TG"), message.text, author_name, chat_name)) - - self.telegram_client.infinity_polling() - - def send_msg(self, id, text): - self.telegram_client.send_message(id, text) - - def run(self, token): - self.telegram_client = telebot.TeleBot(token) - self.handler_thread = threading.Thread(target=self.__handler) - self.handler_thread.start() - - -class DiscordClient(discord.Client): - async def on_message(self, message): - if message.author != self.user: - author_name = message.author.name - chat_name = message.author.guild.name + "/" + message.channel.name - compute_message(Message((message.channel.id, "DS"), message.content, author_name, chat_name)) - - def send_msg(self, id, text): - self.loop.create_task(discord_client.get_channel(id).send(text)) - - -def add_error_to_log(text): - error_log = open(config.ERROR_LOG_NAME, "a") - error_log.write(text + "\n\n") - error_log.close() - - -def send(id, text): - try: - if id[1] == "VK": - vk_client.send_msg(id[0], text) - elif id[1] == "DS": - discord_client.send_msg(id[0], text) - elif id[1] == "TG": - telegram_client.send_msg(id[0], text) - else: - add_error_to_log("Error: Unknown system to send message.") - except Exception as error: - add_error_to_log("Error: Unknown error while sending the message.\nDescription:\n" + str(error)) - - -def compute_command_select(msg): - global select_chat - - select_chat["chat_id"] = msg.from_id - select_chat["chat_name"] = msg.chat_name - send(msg.from_id, "Chat is selected.") - - -def compute_command_connect(msg): - global graph, select_chat - - select_id = select_chat["chat_id"] - if select_id == (None, None): - send(msg.from_id, "Error: No selected chat.") - elif select_id == msg.from_id: - send(msg.from_id, "Error: Attempting to connect a chat with itself.") - elif select_id in graph.adjacency_list[msg.from_id]: - send(msg.from_id, "Error: Chats already connected.") - else: - graph.add_edge(msg.from_id, select_id) - send(msg.from_id, select_id[1] + " chat with name " + select_chat["chat_name"] + " is connected.") - send(select_id, msg.from_id[1] + " chat with name " + msg.chat_name + " is connected.") - - -def compute_command_disconnect(msg): - global graph, select_chat - - select_id = select_chat["chat_id"] - if select_id == (None, None): - send(msg.from_id, "Error: No selected chat.") - elif not (select_id in graph.adjacency_list[msg.from_id]): - send(msg.from_id, "Error: Chats are not connected.") - else: - graph.erase_edge(msg.from_id, select_id) - send(msg.from_id, select_id[1] + " chat with name " + select_chat["chat_name"] + " is disconnected.") - send(select_id, msg.from_id[1] + " chat with name " + msg.chat_name + " is disconnected.") - - -def compute_command(msg): - command = msg.get_command() - if command == "select": - compute_command_select(msg) - elif command == "connect": - compute_command_connect(msg) - elif command == "disconnect": - compute_command_disconnect(msg) - else: - send(msg.from_id, "Error: Unknown instruction.") - - -def compute_message(msg): - global graph - - if msg.text == "": - return None - - graph.add_vertex(msg.from_id) - if msg.is_command(): - return compute_command(msg) - - for send_id in graph.get_reachable_vertices(msg.from_id): - send(send_id, msg.get_text_to_forwarding()) +from main_classes.UsersHandler import UsersHandler def main(): - global graph, select_chat, vk_client, discord_client, telegram_client - - graph = Graph(config.GRAPH_STORAGE_NAME) - select_chat = {"chat_name": None, "chat_id": (None, None)} - - vk_client = VkClient() - discord_client = DiscordClient() - telegram_client = TelegramClient() - - vk_client.run(config.VK_TOKEN, config.VK_GROUP_ID) - telegram_client.run(config.TELEGRAM_TOKEN) - discord_client.run(config.DISCORD_TOKEN) + bot = UsersHandler(config.GRAPH_STORAGE_NAME, config.USERS_INFORMATION_DB_NAME, error_log_name=config.ERROR_LOG_NAME) + bot.run(vk_token=config.VK_TOKEN, vk_group_id=config.VK_GROUP_ID, telegram_token=config.TELEGRAM_TOKEN, discord_token=config.DISCORD_TOKEN) if __name__ == "__main__": diff --git a/main_classes/Graph.py b/main_classes/Graph.py new file mode 100644 index 0000000..733e0fb --- /dev/null +++ b/main_classes/Graph.py @@ -0,0 +1,98 @@ +import queue + + +class Graph: + def __init__(self, graph_storage_name): + graph_storage = open(graph_storage_name, "r") + self.graph_storage_name = graph_storage_name + self.adjacency_list = dict() + self.rules = dict() + self.graph_storage_size = 0 + for line in graph_storage.readlines(): + type_operation, vertex1, vertex2 = self.__convert_text_to_operation(line) + + if type_operation == "+": + self.add_edge(vertex1, vertex2, save_operation=False) + else: + self.erase_edge(vertex1, vertex2, save_operation=False) + self.graph_storage_size += 1 + + def __check_rule(self, vertex, text): + rule = self.rules[vertex] + return len(text) >= len(rule) and text[:len(rule)] == rule + + def __convert_text_to_operation(self, text): + text = text.split() + return text[0], (int(text[1]), text[2]), (int(text[3]), text[4]) + + def __convert_operation_to_text(self, type_operation, vertex1, vertex2): + return type_operation + " " + str(vertex1[0]) + " " + vertex1[1] + " " + str(vertex2[0]) + " " + vertex2[1] + "\n" + + def __reset_graph_storage(self): + graph_storage = open(self.graph_storage_name, "w") + used = set() + self.graph_storage_size = 0 + for vertex1 in self.adjacency_list: + for vertex2 in self.adjacency_list[vertex1]: + if (vertex1, vertex2) in used or (vertex2, vertex1) in used: + continue + + used.add((vertex1, vertex2)) + graph_storage.write(self.__convert_operation_to_text("+", vertex1, vertex2)) + self.graph_storage_size += 1 + graph_storage.close() + + def __add_operation_to_storage(self, type_operation, vertex1, vertex2): + graph_storage = open(self.graph_storage_name, "a") + graph_storage.write(self.__convert_operation_to_text(type_operation, vertex1, vertex2)) + graph_storage.close() + + self.graph_storage_size += 1 + if self.graph_storage_size >= len(self.adjacency_list) ** 2: + self.__reset_graph_storage() + + def get_reachable_vertices(self, vertex_start, text): + used = set() + used.add(vertex_start) + q = queue.Queue() + q.put(vertex_start) + while not q.empty(): + v = q.get() + if not self.__check_rule(v, text): + continue + + for to in self.adjacency_list[v]: + if to in used: + continue + + used.add(to) + q.put(to) + + used.discard(vertex_start) + return list(used) + + def add_vertex(self, vertex): + if not (vertex in self.adjacency_list): + self.rules[vertex] = "" + self.adjacency_list[vertex] = set() + + def set_rule(self, id, rule): + vertex = (int(id[:-2]), id[-2:]) + self.add_vertex(vertex) + self.rules[vertex] = rule + + def add_edge(self, vertex1, vertex2, save_operation=True): + self.add_vertex(vertex1) + self.add_vertex(vertex2) + self.adjacency_list[vertex1].add(vertex2) + self.adjacency_list[vertex2].add(vertex1) + if save_operation: + self.__add_operation_to_storage("+", vertex1, vertex2) + + def erase_edge(self, vertex1, vertex2, save_operation=True): + if vertex1 in self.adjacency_list: + self.adjacency_list[vertex1].discard(vertex2) + if vertex2 in self.adjacency_list: + self.adjacency_list[vertex2].discard(vertex1) + if save_operation: + self.__add_operation_to_storage("-", vertex1, vertex2) diff --git a/main_classes/UsersHandler.py b/main_classes/UsersHandler.py new file mode 100644 index 0000000..0ad8103 --- /dev/null +++ b/main_classes/UsersHandler.py @@ -0,0 +1,234 @@ +import sqlite3 +from main_classes.Graph import Graph +from client_classes.VkClient import VkClient +from client_classes.TelegramClient import TelegramClient +from client_classes.DiscordClient import DiscordClient + + +class UsersHandler: + def __init__(self, graph_storage_name, users_information_db_name, error_log_name=None): + self.error_log_name = error_log_name + self.graph = Graph(graph_storage_name) + self.select_chat = {"chat_name": None, "chat_id": (None, None)} + + self.vk_client = VkClient(self.compute_message) + self.discord_client = DiscordClient(self.compute_message) + self.telegram_client = TelegramClient(self.compute_message) + + self.users_information_db_name = users_information_db_name + conn = sqlite3.connect(users_information_db_name) + cursor = conn.cursor() + cursor.execute("CREATE TABLE IF NOT EXISTS users(id TEXT PRIMARY KEY, name TEXT, is_admin INT);") + cursor.execute("CREATE TABLE IF NOT EXISTS chat_rules(id TEXT PRIMARY KEY, rule TEXT);") + conn.commit() + + cursor.execute("SELECT * FROM chat_rules;") + for rule in cursor.fetchall(): + self.graph.set_rule(rule[0], rule[1]) + + def __add_user(self, id): + conn = sqlite3.connect(self.users_information_db_name) + cursor = conn.cursor() + cursor.execute("SELECT * FROM users WHERE id='" + id + "';") + if cursor.fetchone() is None: + entry = (id, "None", 0) + cursor.execute("INSERT INTO users VALUES(?, ?, ?);", entry) + conn.commit() + + def __get_user_name(self, msg): + conn = sqlite3.connect(self.users_information_db_name) + cursor = conn.cursor() + cursor.execute("SELECT * FROM users WHERE id='" + msg.get_author_id() + str(msg.from_id[0]) + "';") + return cursor.fetchone()[1] + + def __is_admin(self, msg): + if msg.is_owner: + return True + + conn = sqlite3.connect(self.users_information_db_name) + cursor = conn.cursor() + cursor.execute("SELECT * FROM users WHERE id='" + msg.get_author_id() + str(msg.from_id[0]) + "';") + return cursor.fetchone()[2] + + def __add_error_to_log(self, text): + if self.error_log_name is not None: + error_log = open(self.error_log_name, "a") + error_log.write(text + "\n\n") + error_log.close() + + def __send(self, id, text, to_chat=True): + try: + if id[1] == "VK": + self.vk_client.send_msg(id[0], text, to_chat) + elif id[1] == "DS": + self.discord_client.send_msg(id[0], text) + elif id[1] == "TG": + self.telegram_client.send_msg(id[0], text) + else: + self.__add_error_to_log("Error: Unknown system to send message.") + except Exception as error: + self.__add_error_to_log("Error: Unknown error while sending the message.\nDescription:\n" + str(error)) + + def __compute_command_select(self, msg): + self.select_chat["chat_id"] = msg.from_id + self.select_chat["chat_name"] = msg.chat_name + self.__send(msg.from_id, "Chat is selected.") + + def __compute_command_connect(self, msg): + select_id = self.select_chat["chat_id"] + if select_id == (None, None): + self.__send(msg.from_id, "Error: No selected chat.") + elif select_id == msg.from_id: + self.__send(msg.from_id, "Error: Attempting to connect a chat with itself.") + elif select_id in self.graph.adjacency_list[msg.from_id]: + self.__send(msg.from_id, "Error: Chats already connected.") + else: + self.graph.add_edge(msg.from_id, select_id) + self.__send(msg.from_id, select_id[1] + " chat with name " + self.select_chat["chat_name"] + " is connected.") + self.__send(select_id, msg.from_id[1] + " chat with name " + msg.chat_name + " is connected.") + + def __compute_command_disconnect(self, msg): + select_id = self.select_chat["chat_id"] + if select_id == (None, None): + self.__send(msg.from_id, "Error: No selected chat.") + elif not (select_id in self.graph.adjacency_list[msg.from_id]): + self.__send(msg.from_id, "Error: Chats are not connected.") + else: + self.graph.erase_edge(msg.from_id, select_id) + self.__send(msg.from_id, select_id[1] + " chat with name " + self.select_chat["chat_name"] + " is disconnected.") + self.__send(select_id, msg.from_id[1] + " chat with name " + msg.chat_name + " is disconnected.") + + def __compute_command_get_id(self, msg): + self.__send(msg.from_id, "User id: " + msg.get_author_id(), to_chat=msg.chat_name is not None) + + def __compute_command_set_admin(self, msg): + if not self.__is_admin(msg): + return self.__send(msg.from_id, "Error: You must be an administrator to use this command.") + + command = msg.get_chat_command().split() + if len(command) == 2: + return self.__send(msg.from_id, "Error: An user id is required.") + user_id = " ".join(command[2:]) + self.__add_user(user_id + str(msg.from_id[0])) + + conn = sqlite3.connect(self.users_information_db_name) + cursor = conn.cursor() + cursor.execute("SELECT * FROM users WHERE id='" + user_id + str(msg.from_id[0]) + "';") + if cursor.fetchone()[2]: + return self.__send(msg.from_id, "Error: The account with id '" + user_id + "' already has administrator rights.") + + cursor.execute("UPDATE users SET is_admin=1 WHERE id='" + user_id + str(msg.from_id[0]) + "';") + conn.commit() + self.__send(msg.from_id, "The account with id '" + user_id + "' has been granted administrative rights.") + + def __compute_command_delete_admin(self, msg): + if not msg.is_owner: + return self.__send(msg.from_id, "Error: You must be an owner to use this command.") + + command = msg.get_chat_command().split() + if len(command) == 2: + return self.__send(msg.from_id, "Error: An user id is required.") + user_id = " ".join(command[2:]) + self.__add_user(user_id + str(msg.from_id[0])) + + conn = sqlite3.connect(self.users_information_db_name) + cursor = conn.cursor() + cursor.execute("SELECT * FROM users WHERE id='" + user_id + str(msg.from_id[0]) + "';") + if not cursor.fetchone()[2]: + return self.__send(msg.from_id, "Error: The account with id '" + user_id + "' does not have administrative rights.") + + cursor.execute("UPDATE users SET is_admin=0 WHERE id='" + user_id + str(msg.from_id[0]) + "';") + conn.commit() + self.__send(msg.from_id, "The account with id '" + user_id + "' no longer has administrative rights.") + + def __compute_command_rename(self, msg): + if not self.__is_admin(msg): + return self.__send(msg.from_id, "Error: You must be an administrator to use this command.") + + command = msg.get_chat_command().split() + if len(command) == 1: + return self.__send(msg.from_id, "Error: An user id is required.") + if len(command) == 2: + return self.__send(msg.from_id, "Error: A new name is required.") + user_id = command[1] + if user_id == "self": + user_id = msg.get_author_id() + name = " ".join(command[2:]) + self.__add_user(user_id + str(msg.from_id[0])) + + conn = sqlite3.connect(self.users_information_db_name) + cursor = conn.cursor() + cursor.execute("SELECT * FROM users WHERE id='" + user_id + str(msg.from_id[0]) + "';") + if user_id != msg.get_author_id() and cursor.fetchone()[2]: + return self.__send(msg.from_id, "Error: Forbidden to rename administrators.") + + cursor.execute("UPDATE users SET name='" + name + "' WHERE id='" + user_id + str(msg.from_id[0]) + "';") + conn.commit() + self.__send(msg.from_id, "The account name has been changed to '" + name + "'.") + + def __compute_command_set_rule(self, msg): + if not self.__is_admin(msg): + return self.__send(msg.from_id, "Error: You must be an administrator to use this command.") + + command = msg.get_chat_command() + if len(command.split()) == 2 or command.count("\"") < 2: + return self.__send(msg.from_id, "Error: A new rule is required.") + rule = command[command.find("\"") + 1:command.rfind("\"")] + + conn = sqlite3.connect(self.users_information_db_name) + cursor = conn.cursor() + cursor.execute("UPDATE chat_rules SET rule='" + rule + "' WHERE id='" + msg.get_chat_id() + "';") + conn.commit() + self.graph.set_rule(msg.get_chat_id(), rule) + self.__send(msg.from_id, "The chat rule has been changed to '" + rule + "'.") + + def __compute_chat_command(self, msg): + command = msg.get_chat_command().split() + if len(command) >= 1 and command[0].lower() == "select": + self.__compute_command_select(msg) + elif len(command) >= 1 and command[0].lower() == "connect": + self.__compute_command_connect(msg) + elif len(command) >= 1 and command[0].lower() == "disconnect": + self.__compute_command_disconnect(msg) + elif len(command) >= 2 and command[0].lower() == "set" and command[1].lower() == "admin": + self.__compute_command_set_admin(msg) + elif len(command) >= 2 and command[0].lower() == "delete" and command[1].lower() == "admin": + self.__compute_command_delete_admin(msg) + elif len(command) >= 2 and command[0].lower() == "get" and command[1].lower() == "id": + self.__compute_command_get_id(msg) + elif len(command) >= 1 and command[0].lower() == "rename": + self.__compute_command_rename(msg) + elif len(command) >= 2 and command[0].lower() == "set" and command[1].lower() == "rule": + self.__compute_command_set_rule(msg) + else: + self.__send(msg.from_id, "Error: Unknown instruction.") + + def __compute_user_command(self, msg): + command = msg.text.split() + if len(command) >= 2 and command[0].lower() == "get" and command[1].lower() == "id": + self.__compute_command_get_id(msg) + else: + self.__send(msg.from_id, "Error: Unknown instruction.", to_chat=False) + + def run(self, vk_token=None, vk_group_id=None, telegram_token=None, discord_token=None): + if vk_token is not None and vk_group_id is not None: + self.vk_client.run(vk_token, vk_group_id) + if telegram_token is not None: + self.telegram_client.run(telegram_token) + if discord_token is not None: + self.discord_client.run(discord_token) + + def compute_message(self, msg): + if msg.chat_name is None: + return self.__compute_user_command(msg) + + self.__add_user(msg.get_author_id() + str(msg.from_id[0])) + self.graph.add_vertex(msg.from_id) + if msg.is_chat_command(): + return self.__compute_chat_command(msg) + + name = self.__get_user_name(msg) + if name != "None": + msg.author_name = name + for send_id in self.graph.get_reachable_vertices(msg.from_id, msg.text): + self.__send(send_id, msg.get_text_to_forwarding())