from ctypes import Union from datetime import datetime import discord from cpl_core.configuration import ConfigurationABC from cpl_core.database.context import DatabaseContextABC from cpl_core.logging import LoggerABC from gismo_core.abc.bot_service_abc import BotServiceABC from gismo_core.configuration.server_settings import ServerSettings from gismo_data.abc.client_repository_abc import ClientRepositoryABC from gismo_data.abc.known_user_repository_abc import KnownUserRepositoryABC from gismo_data.abc.user_joined_server_repository_abc import \ UserJoinedServerRepositoryABC from gismo_data.abc.user_joined_voice_channel_abc import UserJoinedVoiceChannelRepositoryABC from gismo_data.abc.user_repository_abc import UserRepositoryABC from gismo_data.model.client import Client from gismo_data.model.known_user import KnownUser from gismo_data.model.server import Server from gismo_data.model.user import User from gismo_data.model.user_joined_server import UserJoinedServer from gismo_data.service.user_repository_service import ServerRepositoryABC from modules_core.abc.events.on_ready_abc import OnReadyABC from modules_core.abc.module_abc import ModuleABC class Database(ModuleABC, OnReadyABC): def __init__( self, config: ConfigurationABC, logger: LoggerABC, bot: BotServiceABC, db_context: DatabaseContextABC, server_repo: ServerRepositoryABC, user_repo: UserRepositoryABC, client_repo: ClientRepositoryABC, known_users: KnownUserRepositoryABC, user_joins: UserJoinedServerRepositoryABC, user_joins_vc: UserJoinedVoiceChannelRepositoryABC ): self._config = config self._logger = logger self._bot = bot self._db_context = db_context self._servers = server_repo self._users = user_repo self._clients = client_repo self._known_users = known_users self._user_joins = user_joins self._user_joins_vc = user_joins_vc ModuleABC.__init__(self) self._priorities[OnReadyABC] = 0 self._logger.trace(__name__, f'Module {type(self)} loaded') def _validate_init_time(self): try: start_time = self._config.get_configuration('Database_StartTime') init_time = round((datetime.now() - start_time).total_seconds(), 2) self._config.add_configuration('Database_InitTime', init_time) self._logger.debug(__name__, f'Database Init time: {init_time}s') # print warning if initialisation took too long if init_time >= 30: self._logger.warn( __name__, 'It takes long time to start the bot!') # print error if initialisation took way too long elif init_time >= 90: self._logger.error( __name__, 'It takes very long time to start the bot!!!') except Exception as e:# self._logger.error(__name__, 'Database init time calculation failed', e) return def _check_known_users(self): self._logger.debug(__name__, f'Start checking KnownUsers table, {len(self._bot.users)}') for u in self._bot.users: u: discord.User = u try: if u.bot: self._logger.trace(__name__, f'User {u.id} is ignored, because its a bot') continue user = self._known_users.find_user_by_discord_id(u.id) if user is not None: continue self._logger.warn(__name__, f'Unknown user: {u.id}') self._logger.debug(__name__, f'Add user: {u.id}') self._known_users.add_user(KnownUser(u.id)) self._db_context.save_changes() user = self._known_users.find_user_by_discord_id(u.id) if user is None: self._logger.fatal(__name__, f'Cannot add user: {u.id}') self._logger.debug(__name__, f'Added user: {u.id}') except Exception as e: self._logger.error(__name__, f'Cannot get user', e) def _check_servers(self): self._logger.debug(__name__, f'Start checking Servers table') for g in self._bot.guilds: g: discord.Guild = g try: server = self._servers.find_server_by_discord_id(g.id) if server is not None: continue self._logger.warn(__name__, f'Server not found in database: {g.id}') self._logger.debug(__name__, f'Add server: {g.id}') self._servers.add_server(Server(g.id)) self._db_context.save_changes() server = self._servers.find_server_by_discord_id(g.id) if server is None: self._logger.fatal(__name__, f'Cannot add server: {g.id}') self._logger.debug(__name__, f'Added server: {g.id}') except Exception as e: self._logger.error(__name__, f'Cannot get server', e) results = self._servers.get_servers() if results is None or len(results) == 0: self._logger.error(__name__, f'Table Servers is empty!') def _check_clients(self): self._logger.debug(__name__, f'Start checking Clients table') for g in self._bot.guilds: g: discord.Guild = g try: server: Server = self._servers.find_server_by_discord_id(g.id) if server is None: self._logger.fatal(__name__, f'Server not found in database: {g.id}') client = self._clients.find_client_by_server_id(server.server_id) if client is not None: continue self._logger.warn(__name__, f'Client for server {g.id} not found in database: {self._bot.user.id}') self._logger.debug(__name__, f'Add client: {self._bot.user.id}') self._clients.add_client(Client(self._bot.user.id, 0, 0, 0, 0, 0, server)) self._db_context.save_changes() client = self._clients.find_client_by_server_id(server.server_id) if client is None: self._logger.fatal(__name__, f'Cannot add client {self._bot.user.id} for server {g.id}') self._logger.debug(__name__, f'Added client: {g.id}') except Exception as e: self._logger.error(__name__, f'Cannot get client', e) results = self._servers.get_servers() if results is None or len(results) == 0: self._logger.error(__name__, f'Table Servers is empty!') def _check_users(self): self._logger.debug(__name__, f'Start checking Users table') for g in self._bot.guilds: g: discord.Guild = g try: server = self._servers.find_server_by_discord_id(g.id) if server is None: self._logger.fatal(__name__, f'Server not found in database: {g.id}') for u in g.members: u: Union[discord.Member, discord.User] = u if u.bot: self._logger.trace(__name__, f'User {u.id} is ignored, because its a bot') continue user = self._users.find_user_by_discord_id_and_server_id(u.id, server.server_id) if user is not None: continue self._logger.warn(__name__, f'User not found in database: {u.id}') self._logger.debug(__name__, f'Add user: {u.id}') self._users.add_user(User(u.id, 0, server)) self._db_context.save_changes() self._logger.debug(__name__, f'Added User: {u.id}') except Exception as e: self._logger.error(__name__, f'Cannot get User', e) results = self._users.get_users() if results is None or len(results) == 0: self._logger.error(__name__, f'Table Users is empty!') def _check_user_joins(self): self._logger.debug(__name__, f'Start checking UserJoinedServers table') for guild in self._bot.guilds: guild: discord.Guild = guild server = self._servers.find_server_by_discord_id(guild.id) if server is None: self._logger.fatal(__name__, f'Server not found in database: {guild.id}') try: for u in guild.members: u: discord.User = u if u.bot: self._logger.trace(__name__, f'User {u.id} is ignored, because its a bot') continue user = self._users.find_user_by_discord_id_and_server_id(u.id, server.server_id) if user is None: self._logger.fatal(__name__, f'User not found in database: {u.id}') join = self._user_joins.find_active_user_joined_server_by_user_id(user.user_id) if join is not None: continue m: discord.Member = u self._logger.warn(__name__, f'Active UserJoinedServer not found in database: {guild.id}:{u.id}@{m.joined_at}') self._logger.debug(__name__, f'Add UserJoinedServer: {guild.id}:{u.id}@{m.joined_at}') self._user_joins.add_user_joined_server(UserJoinedServer(user, m.joined_at, None)) self._db_context.save_changes() self._logger.debug(__name__, f'Added UserJoinedServer: {u.id}') except Exception as e: self._logger.error(__name__, f'Cannot get UserJoinedServer', e) results = self._users.get_users() if results is None or len(results) == 0: self._logger.error(__name__, f'Table Users is empty!') joins = self._user_joins.get_user_joined_servers() for join in joins: join: UserJoinedServer = join if join.user.server.discord_server_id != guild.id: continue if join.leaved_on is not None: continue dc_user = guild.get_member(join.user.discord_id) if dc_user is None: self._logger.warn(__name__, f'User {join.user.discord_id} already left the server.') join.leaved_on = datetime.now() self._user_joins.update_user_joined_server(join) self._db_context.save_changes() def _check_user_joins_vc(self): self._logger.debug(__name__, f'Start checking UserJoinedVoiceChannel table') for guild in self._bot.guilds: guild: discord.Guild = guild server = self._servers.find_server_by_discord_id(guild.id) if server is None: self._logger.fatal(__name__, f'Server not found in database: {guild.id}') try: for u in guild.members: u: discord.User = u if u.bot: self._logger.trace(__name__, f'User {u.id} is ignored, because its a bot') continue user = self._users.find_user_by_discord_id_and_server_id(u.id, server.server_id) if user is None: self._logger.fatal(__name__, f'User not found in database: {u.id}') join = self._user_joins_vc.find_active_user_joined_voice_channel_by_user_id(user.user_id) if join is None: continue m: discord.Member = u self._logger.warn(__name__, f'Active UserJoinedVoiceChannel found in database: {guild.id}:{u.id}@{m.joined_at}') join.leaved_on = datetime.now() server_st: ServerSettings = self._config.get_configuration(f'DSERVER_{guild.id}') if ((join.leaved_on - join.joined_on).total_seconds()/60/60) > server_st.max_voice_state_hours: join.leaved_on = join.joined_on + datetime.timedelta(hours=server_st.max_voice_state_hours) self._user_joins_vc.update_user_joined_voice_channel(join) # todo: maybe add XP self._db_context.save_changes() except Exception as e: self._logger.error(__name__, f'Cannot get UserJoinedVoiceChannel', e) async def on_ready(self): self._logger.debug(__name__, f'Module {type(self)} started') self._check_known_users() self._check_servers() self._check_clients() self._check_users() self._check_user_joins() self._check_user_joins_vc() self._validate_init_time() self._logger.trace(__name__, f'Module {type(self)} stopped')