Compare commits
	
		
			9 Commits
		
	
	
		
			1.1.2
			...
			09771ac2a3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 09771ac2a3 | |||
| 6f27ce7bbc | |||
| 806144d9d3 | |||
| 877af6b945 | |||
| 979e0a0e6f | |||
| fdf10f2728 | |||
| f7ffd78dcc | |||
| 8ddb9f087a | |||
| 0ca3be478b | 
@@ -10,6 +10,7 @@ from cpl_translation import TranslatePipe, TranslationServiceABC, TranslationSet
 | 
				
			|||||||
from bot_api.api_thread import ApiThread
 | 
					from bot_api.api_thread import ApiThread
 | 
				
			||||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
					from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
				
			||||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
					from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
 | 
				
			||||||
 | 
					from bot_core.service.data_integrity_service import DataIntegrityService
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Application(DiscordBotApplicationABC):
 | 
					class Application(DiscordBotApplicationABC):
 | 
				
			||||||
@@ -21,6 +22,7 @@ class Application(DiscordBotApplicationABC):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        # cpl-core
 | 
					        # cpl-core
 | 
				
			||||||
        self._logger: LoggerABC = services.get_service(LoggerABC)
 | 
					        self._logger: LoggerABC = services.get_service(LoggerABC)
 | 
				
			||||||
 | 
					        self._data_integrity: DataIntegrityService = services.get_service(DataIntegrityService)
 | 
				
			||||||
        # cpl-discord
 | 
					        # cpl-discord
 | 
				
			||||||
        self._bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC)
 | 
					        self._bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC)
 | 
				
			||||||
        self._bot_settings: DiscordBotSettings = config.get_configuration(DiscordBotSettings)
 | 
					        self._bot_settings: DiscordBotSettings = config.get_configuration(DiscordBotSettings)
 | 
				
			||||||
@@ -69,6 +71,7 @@ class Application(DiscordBotApplicationABC):
 | 
				
			|||||||
                self._api.stop()
 | 
					                self._api.stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await self._bot.close()
 | 
					            await self._bot.close()
 | 
				
			||||||
 | 
					            self._data_integrity.check_data_integrity(is_for_shutdown=True)
 | 
				
			||||||
            self._logger.info(__name__, f"Stopped {DiscordBotService.__name__}")
 | 
					            self._logger.info(__name__, f"Stopped {DiscordBotService.__name__}")
 | 
				
			||||||
        except Exception as e:
 | 
					        except Exception as e:
 | 
				
			||||||
            self._logger.error(__name__, "stop failed", e)
 | 
					            self._logger.error(__name__, "stop failed", e)
 | 
				
			||||||
@@ -76,4 +79,4 @@ class Application(DiscordBotApplicationABC):
 | 
				
			|||||||
        Console.write_line()
 | 
					        Console.write_line()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def is_restart(self):
 | 
					    def is_restart(self):
 | 
				
			||||||
        return True if self._configuration.get_configuration("IS_RESTART") == "true" else False  #
 | 
					        return True if self._configuration.get_configuration("IS_RESTART") == "true" else False
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,23 +16,23 @@
 | 
				
			|||||||
    "LicenseName": "MIT",
 | 
					    "LicenseName": "MIT",
 | 
				
			||||||
    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
					    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core==2022.12.1.post3",
 | 
					      "cpl-core==2023.4.0.post2",
 | 
				
			||||||
      "cpl-translation==2022.12.1",
 | 
					      "cpl-translation==2023.4.0.post1",
 | 
				
			||||||
      "cpl-query==2022.12.2.post2",
 | 
					      "cpl-query==2023.4.0.post1",
 | 
				
			||||||
      "cpl-discord==2022.12.2.post1",
 | 
					      "cpl-discord==2023.4.0.post3",
 | 
				
			||||||
      "Flask==2.2.2",
 | 
					      "Flask==2.3.2",
 | 
				
			||||||
      "Flask-Classful==0.14.2",
 | 
					      "Flask-Classful==0.14.2",
 | 
				
			||||||
      "Flask-Cors==3.0.10",
 | 
					      "Flask-Cors==3.0.10",
 | 
				
			||||||
      "PyJWT==2.6.0",
 | 
					      "PyJWT==2.7.0",
 | 
				
			||||||
      "waitress==2.1.2",
 | 
					      "waitress==2.1.2",
 | 
				
			||||||
      "Flask-SocketIO==5.3.2",
 | 
					      "Flask-SocketIO==5.3.4",
 | 
				
			||||||
      "eventlet==0.33.3",
 | 
					      "eventlet==0.33.3",
 | 
				
			||||||
      "requests-oauthlib==1.3.1",
 | 
					      "requests-oauthlib==1.3.1",
 | 
				
			||||||
      "icmplib==3.0.3",
 | 
					      "icmplib==3.0.3",
 | 
				
			||||||
      "ariadne==0.17.1"
 | 
					      "ariadne==0.19.1"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli==2022.12.1.post3",
 | 
					      "cpl-cli==2023.4.0.post3",
 | 
				
			||||||
      "pygount==1.5.1"
 | 
					      "pygount==1.5.1"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
 
 | 
				
			|||||||
 Submodule kdb-bot/src/bot/config updated: 0c94637537...e1c1efac98
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
from ariadne import graphql_sync
 | 
					from ariadne import graphql_sync
 | 
				
			||||||
from ariadne.constants import PLAYGROUND_HTML
 | 
					from ariadne.explorer import ExplorerGraphiQL
 | 
				
			||||||
from cpl_core.configuration import ConfigurationABC
 | 
					from cpl_core.configuration import ConfigurationABC
 | 
				
			||||||
from cpl_core.environment import ApplicationEnvironmentABC
 | 
					from cpl_core.environment import ApplicationEnvironmentABC
 | 
				
			||||||
from flask import request, jsonify
 | 
					from flask import request, jsonify
 | 
				
			||||||
@@ -30,7 +30,7 @@ class GraphQLController:
 | 
				
			|||||||
        if self._env.environment_name != "development":
 | 
					        if self._env.environment_name != "development":
 | 
				
			||||||
            return "", 403
 | 
					            return "", 403
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return PLAYGROUND_HTML, 200
 | 
					        return ExplorerGraphiQL().html(None), 200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Route.post(f"{BasePath}")
 | 
					    @Route.post(f"{BasePath}")
 | 
				
			||||||
    @Route.authorize(by_api_key=True)
 | 
					    @Route.authorize(by_api_key=True)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,32 +1,26 @@
 | 
				
			|||||||
import traceback
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
 | 
					from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
 | 
				
			||||||
from cpl_core.console import Console, ForegroundColorEnum
 | 
					from cpl_core.utils.json_processor import JSONProcessor
 | 
				
			||||||
from cpl_query.extension import List
 | 
					from cpl_query.extension import List
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from bot_core.configuration.file_logging_settings import FileLoggingSettings
 | 
					from bot_core.configuration.file_logging_settings import FileLoggingSettings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BotLoggingSettings(ConfigurationModelABC):
 | 
					class BotLoggingSettings(ConfigurationModelABC):
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self, custom_logs: dict = None):
 | 
				
			||||||
        ConfigurationModelABC.__init__(self)
 | 
					        ConfigurationModelABC.__init__(self)
 | 
				
			||||||
        self._files: List[FileLoggingSettings] = List(FileLoggingSettings)
 | 
					        self._files: List[FileLoggingSettings] = List(FileLoggingSettings)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if custom_logs is not None:
 | 
				
			||||||
 | 
					            self._files_from_dict(custom_logs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def files(self) -> List[FileLoggingSettings]:
 | 
					    def files(self) -> List[FileLoggingSettings]:
 | 
				
			||||||
        return self._files
 | 
					        return self._files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def from_dict(self, settings: dict):
 | 
					    def _files_from_dict(self, settings: dict):
 | 
				
			||||||
        try:
 | 
					        files = List(FileLoggingSettings)
 | 
				
			||||||
            files = List(FileLoggingSettings)
 | 
					        for s in settings:
 | 
				
			||||||
            for s in settings:
 | 
					            settings[s]["Key"] = s
 | 
				
			||||||
                st = FileLoggingSettings()
 | 
					            st = JSONProcessor.process(FileLoggingSettings, settings[s])
 | 
				
			||||||
                settings[s]["Key"] = s
 | 
					            files.append(st)
 | 
				
			||||||
                st.from_dict(settings[s])
 | 
					        self._files = files
 | 
				
			||||||
                files.append(st)
 | 
					 | 
				
			||||||
            self._files = files
 | 
					 | 
				
			||||||
        except Exception as e:
 | 
					 | 
				
			||||||
            Console.set_foreground_color(ForegroundColorEnum.red)
 | 
					 | 
				
			||||||
            Console.write_line(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
 | 
					 | 
				
			||||||
            Console.write_line(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
 | 
					 | 
				
			||||||
            Console.set_foreground_color(ForegroundColorEnum.default)
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,23 +1,27 @@
 | 
				
			|||||||
import traceback
 | 
					from cpl_core.logging import LoggingSettings, LoggingLevelEnum
 | 
				
			||||||
 | 
					 | 
				
			||||||
from cpl_core.console import Console
 | 
					 | 
				
			||||||
from cpl_core.logging import LoggingSettings
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FileLoggingSettings(LoggingSettings):
 | 
					class FileLoggingSettings(LoggingSettings):
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(
 | 
				
			||||||
        LoggingSettings.__init__(self)
 | 
					        self,
 | 
				
			||||||
 | 
					        key: str,
 | 
				
			||||||
 | 
					        path: str = None,
 | 
				
			||||||
 | 
					        filename: str = None,
 | 
				
			||||||
 | 
					        console_log_level: LoggingLevelEnum = None,
 | 
				
			||||||
 | 
					        file_log_level: LoggingLevelEnum = None,
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
 | 
					        LoggingSettings.__init__(self, path, filename, console_log_level, file_log_level)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self._key = ""
 | 
					        self._key = key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def key(self) -> str:
 | 
					    def key(self) -> str:
 | 
				
			||||||
        return self._key
 | 
					        return self._key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def from_dict(self, settings: dict):
 | 
					    # def from_dict(self, settings: dict):
 | 
				
			||||||
        try:
 | 
					    #     try:
 | 
				
			||||||
            self._key = settings["Key"]
 | 
					    #         self._key = settings["Key"]
 | 
				
			||||||
            super().from_dict(settings)
 | 
					    #         super().from_dict(settings)
 | 
				
			||||||
        except Exception as e:
 | 
					    #     except Exception as e:
 | 
				
			||||||
            Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
 | 
					    #         Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
 | 
				
			||||||
            Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
 | 
					    #         Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
 | 
				
			|||||||
from bot_core.events.core_on_ready_event import CoreOnReadyEvent
 | 
					from bot_core.events.core_on_ready_event import CoreOnReadyEvent
 | 
				
			||||||
from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
 | 
					from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
 | 
				
			||||||
from bot_core.service.client_utils_service import ClientUtilsService
 | 
					from bot_core.service.client_utils_service import ClientUtilsService
 | 
				
			||||||
 | 
					from bot_core.service.data_integrity_service import DataIntegrityService
 | 
				
			||||||
from bot_core.service.message_service import MessageService
 | 
					from bot_core.service.message_service import MessageService
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,6 +25,7 @@ class CoreModule(ModuleABC):
 | 
				
			|||||||
    def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
 | 
					    def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
 | 
				
			||||||
        services.add_transient(MessageServiceABC, MessageService)
 | 
					        services.add_transient(MessageServiceABC, MessageService)
 | 
				
			||||||
        services.add_transient(ClientUtilsABC, ClientUtilsService)
 | 
					        services.add_transient(ClientUtilsABC, ClientUtilsService)
 | 
				
			||||||
 | 
					        services.add_transient(DataIntegrityService)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # pipes
 | 
					        # pipes
 | 
				
			||||||
        services.add_transient(DateTimeOffsetPipe)
 | 
					        services.add_transient(DateTimeOffsetPipe)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										373
									
								
								kdb-bot/src/bot_core/service/data_integrity_service.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								kdb-bot/src/bot_core/service/data_integrity_service.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,373 @@
 | 
				
			|||||||
 | 
					from datetime import datetime, timedelta
 | 
				
			||||||
 | 
					from typing import Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import discord
 | 
				
			||||||
 | 
					from cpl_core.configuration import ConfigurationABC
 | 
				
			||||||
 | 
					from cpl_core.database.context import DatabaseContextABC
 | 
				
			||||||
 | 
					from cpl_discord.service import DiscordBotServiceABC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from bot_core.logging.database_logger import DatabaseLogger
 | 
				
			||||||
 | 
					from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
 | 
				
			||||||
 | 
					from bot_data.abc.client_repository_abc import ClientRepositoryABC
 | 
				
			||||||
 | 
					from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
 | 
				
			||||||
 | 
					from bot_data.abc.user_joined_game_server_repository_abc import UserJoinedGameServerRepositoryABC
 | 
				
			||||||
 | 
					from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
 | 
				
			||||||
 | 
					from bot_data.abc.user_joined_voice_channel_repository_abc import (
 | 
				
			||||||
 | 
					    UserJoinedVoiceChannelRepositoryABC,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					from bot_data.abc.user_repository_abc import UserRepositoryABC
 | 
				
			||||||
 | 
					from bot_data.model.client import Client
 | 
				
			||||||
 | 
					from bot_data.model.known_user import KnownUser
 | 
				
			||||||
 | 
					from bot_data.model.server import Server
 | 
				
			||||||
 | 
					from bot_data.model.user import User
 | 
				
			||||||
 | 
					from bot_data.model.user_joined_server import UserJoinedServer
 | 
				
			||||||
 | 
					from bot_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
 | 
				
			||||||
 | 
					from bot_data.service.seeder_service import SeederService
 | 
				
			||||||
 | 
					from bot_data.service.user_repository_service import ServerRepositoryABC
 | 
				
			||||||
 | 
					from modules.base.configuration.base_server_settings import BaseServerSettings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DataIntegrityService:
 | 
				
			||||||
 | 
					    def __init__(
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        config: ConfigurationABC,
 | 
				
			||||||
 | 
					        logger: DatabaseLogger,
 | 
				
			||||||
 | 
					        seeder: SeederService,
 | 
				
			||||||
 | 
					        bot: DiscordBotServiceABC,
 | 
				
			||||||
 | 
					        db_context: DatabaseContextABC,
 | 
				
			||||||
 | 
					        server_repo: ServerRepositoryABC,
 | 
				
			||||||
 | 
					        user_repo: UserRepositoryABC,
 | 
				
			||||||
 | 
					        client_repo: ClientRepositoryABC,
 | 
				
			||||||
 | 
					        known_users: KnownUserRepositoryABC,
 | 
				
			||||||
 | 
					        user_joins: UserJoinedServerRepositoryABC,
 | 
				
			||||||
 | 
					        user_joins_vc: UserJoinedVoiceChannelRepositoryABC,
 | 
				
			||||||
 | 
					        user_joined_gs: UserJoinedGameServerRepositoryABC,
 | 
				
			||||||
 | 
					        dtp: DateTimeOffsetPipe,
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
 | 
					        self._config = config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._logger = logger
 | 
				
			||||||
 | 
					        self._seeder = seeder
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					        self._user_joined_gs = user_joined_gs
 | 
				
			||||||
 | 
					        self._dtp = dtp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._is_for_shutdown = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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.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.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.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.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.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, self._dtp.transform(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_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
 | 
				
			||||||
 | 
					            settings: BaseServerSettings = self._config.get_configuration(f"BaseServerSettings_{guild.id}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            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:
 | 
				
			||||||
 | 
					                # close open voice states
 | 
				
			||||||
 | 
					                for member in guild.members:
 | 
				
			||||||
 | 
					                    if member.bot:
 | 
				
			||||||
 | 
					                        self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
 | 
				
			||||||
 | 
					                        continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
 | 
				
			||||||
 | 
					                    if user is None:
 | 
				
			||||||
 | 
					                        self._logger.fatal(__name__, f"User not found in database: {member.id}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    joins = self._user_joins_vc.find_active_user_joined_voice_channels_by_user_id(user.id)
 | 
				
			||||||
 | 
					                    if joins is None or len(joins) == 0:
 | 
				
			||||||
 | 
					                        continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for join in joins:
 | 
				
			||||||
 | 
					                        self._logger.warn(
 | 
				
			||||||
 | 
					                            __name__,
 | 
				
			||||||
 | 
					                            f"Active UserJoinedVoiceChannel found in database: {guild.id}:{member.id}@{join.joined_on}",
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                        join.leaved_on = datetime.now()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (
 | 
				
			||||||
 | 
					                            (join.leaved_on - join.joined_on).total_seconds() / 60 / 60
 | 
				
			||||||
 | 
					                        ) > settings.max_voice_state_hours:
 | 
				
			||||||
 | 
					                            join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        self._user_joins_vc.update_user_joined_voice_channel(join)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if self._is_for_shutdown:
 | 
				
			||||||
 | 
					                            user.xp = round(join.time * settings.xp_per_ontime_hour)
 | 
				
			||||||
 | 
					                            self._users.update_user(user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        self._db_context.save_changes()
 | 
				
			||||||
 | 
					                        if self._is_for_shutdown:
 | 
				
			||||||
 | 
					                            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # add open voice states
 | 
				
			||||||
 | 
					                for member in guild.members:
 | 
				
			||||||
 | 
					                    if member.bot:
 | 
				
			||||||
 | 
					                        self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
 | 
				
			||||||
 | 
					                        continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if member.voice is None or member.voice.channel.id in settings.afk_channel_ids:
 | 
				
			||||||
 | 
					                        continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
 | 
				
			||||||
 | 
					                    if user is None:
 | 
				
			||||||
 | 
					                        self._logger.fatal(__name__, f"User not found in database: {member.id}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    join = UserJoinedVoiceChannel(user, member.voice.channel.id, datetime.now())
 | 
				
			||||||
 | 
					                    self._user_joins_vc.add_user_joined_voice_channel(join)
 | 
				
			||||||
 | 
					                    self._db_context.save_changes()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            except Exception as e:
 | 
				
			||||||
 | 
					                self._logger.error(__name__, f"Cannot get UserJoinedVoiceChannel", e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _check_user_joined_gs(self):
 | 
				
			||||||
 | 
					        self._logger.debug(__name__, f"Start checking UserJoinedGameServer 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 member in guild.members:
 | 
				
			||||||
 | 
					                    if member.bot:
 | 
				
			||||||
 | 
					                        self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
 | 
				
			||||||
 | 
					                        continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
 | 
				
			||||||
 | 
					                    if user is None:
 | 
				
			||||||
 | 
					                        self._logger.fatal(__name__, f"User not found in database: {member.id}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    joins = self._user_joined_gs.find_active_user_joined_game_servers_by_user_id(user.id)
 | 
				
			||||||
 | 
					                    if joins is None or len(joins) == 0:
 | 
				
			||||||
 | 
					                        continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for join in joins:
 | 
				
			||||||
 | 
					                        self._logger.warn(
 | 
				
			||||||
 | 
					                            __name__,
 | 
				
			||||||
 | 
					                            f"Active UserJoinedGameServer found in database: {guild.id}:{member.id}@{join.joined_on}",
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                        join.leaved_on = datetime.now()
 | 
				
			||||||
 | 
					                        settings: BaseServerSettings = self._config.get_configuration(f"BaseServerSettings_{guild.id}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (
 | 
				
			||||||
 | 
					                            (join.leaved_on - join.joined_on).total_seconds() / 60 / 60
 | 
				
			||||||
 | 
					                        ) > settings.max_voice_state_hours:
 | 
				
			||||||
 | 
					                            join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        self._user_joined_gs.update_user_joined_game_server(join)
 | 
				
			||||||
 | 
					                        if self._is_for_shutdown:
 | 
				
			||||||
 | 
					                            user.xp = round(join.time * settings.xp_per_ontime_hour)
 | 
				
			||||||
 | 
					                            self._users.update_user(user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        self._db_context.save_changes()
 | 
				
			||||||
 | 
					            except Exception as e:
 | 
				
			||||||
 | 
					                self._logger.error(__name__, f"Cannot get UserJoinedGameServer", e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def check_data_integrity(self, is_for_shutdown=False):
 | 
				
			||||||
 | 
					        if is_for_shutdown != self._is_for_shutdown:
 | 
				
			||||||
 | 
					            self._is_for_shutdown = is_for_shutdown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._check_known_users()
 | 
				
			||||||
 | 
					        self._check_servers()
 | 
				
			||||||
 | 
					        self._check_clients()
 | 
				
			||||||
 | 
					        self._check_users()
 | 
				
			||||||
 | 
					        self._check_user_joins()
 | 
				
			||||||
 | 
					        self._check_user_joins_vc()
 | 
				
			||||||
 | 
					        self._check_user_joined_gs()
 | 
				
			||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "MIT",
 | 
					    "LicenseName": "MIT",
 | 
				
			||||||
    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
					    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core>=1.0.7"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli>=1.0.7"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,31 +1,11 @@
 | 
				
			|||||||
from ctypes import Union
 | 
					from datetime import datetime
 | 
				
			||||||
from datetime import datetime, timedelta
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import discord
 | 
					 | 
				
			||||||
from cpl_core.configuration import ConfigurationABC
 | 
					from cpl_core.configuration import ConfigurationABC
 | 
				
			||||||
from cpl_core.database.context import DatabaseContextABC
 | 
					 | 
				
			||||||
from cpl_discord.events import OnReadyABC
 | 
					from cpl_discord.events import OnReadyABC
 | 
				
			||||||
from cpl_discord.service import DiscordBotServiceABC
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from bot_core.logging.database_logger import DatabaseLogger
 | 
					from bot_core.logging.database_logger import DatabaseLogger
 | 
				
			||||||
from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
 | 
					from bot_core.service.data_integrity_service import DataIntegrityService
 | 
				
			||||||
from bot_data.abc.client_repository_abc import ClientRepositoryABC
 | 
					 | 
				
			||||||
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
 | 
					 | 
				
			||||||
from bot_data.abc.user_joined_game_server_repository_abc import UserJoinedGameServerRepositoryABC
 | 
					 | 
				
			||||||
from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
 | 
					 | 
				
			||||||
from bot_data.abc.user_joined_voice_channel_repository_abc import (
 | 
					 | 
				
			||||||
    UserJoinedVoiceChannelRepositoryABC,
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
 | 
					 | 
				
			||||||
from bot_data.model.client import Client
 | 
					 | 
				
			||||||
from bot_data.model.known_user import KnownUser
 | 
					 | 
				
			||||||
from bot_data.model.server import Server
 | 
					 | 
				
			||||||
from bot_data.model.user import User
 | 
					 | 
				
			||||||
from bot_data.model.user_joined_server import UserJoinedServer
 | 
					 | 
				
			||||||
from bot_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
 | 
					 | 
				
			||||||
from bot_data.service.seeder_service import SeederService
 | 
					from bot_data.service.seeder_service import SeederService
 | 
				
			||||||
from bot_data.service.user_repository_service import ServerRepositoryABC
 | 
					 | 
				
			||||||
from modules.base.configuration.base_server_settings import BaseServerSettings
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DatabaseOnReadyEvent(OnReadyABC):
 | 
					class DatabaseOnReadyEvent(OnReadyABC):
 | 
				
			||||||
@@ -34,31 +14,13 @@ class DatabaseOnReadyEvent(OnReadyABC):
 | 
				
			|||||||
        config: ConfigurationABC,
 | 
					        config: ConfigurationABC,
 | 
				
			||||||
        logger: DatabaseLogger,
 | 
					        logger: DatabaseLogger,
 | 
				
			||||||
        seeder: SeederService,
 | 
					        seeder: SeederService,
 | 
				
			||||||
        bot: DiscordBotServiceABC,
 | 
					        data_integrity: DataIntegrityService,
 | 
				
			||||||
        db_context: DatabaseContextABC,
 | 
					 | 
				
			||||||
        server_repo: ServerRepositoryABC,
 | 
					 | 
				
			||||||
        user_repo: UserRepositoryABC,
 | 
					 | 
				
			||||||
        client_repo: ClientRepositoryABC,
 | 
					 | 
				
			||||||
        known_users: KnownUserRepositoryABC,
 | 
					 | 
				
			||||||
        user_joins: UserJoinedServerRepositoryABC,
 | 
					 | 
				
			||||||
        user_joins_vc: UserJoinedVoiceChannelRepositoryABC,
 | 
					 | 
				
			||||||
        user_joined_gs: UserJoinedGameServerRepositoryABC,
 | 
					 | 
				
			||||||
        dtp: DateTimeOffsetPipe,
 | 
					 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        self._config = config
 | 
					        self._config = config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self._logger = logger
 | 
					        self._logger = logger
 | 
				
			||||||
        self._seeder = seeder
 | 
					        self._seeder = seeder
 | 
				
			||||||
        self._bot = bot
 | 
					        self._data_integrity = data_integrity
 | 
				
			||||||
        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
 | 
					 | 
				
			||||||
        self._user_joined_gs = user_joined_gs
 | 
					 | 
				
			||||||
        self._dtp = dtp
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        OnReadyABC.__init__(self)
 | 
					        OnReadyABC.__init__(self)
 | 
				
			||||||
        self._logger.info(__name__, f"Module {type(self)} loaded")
 | 
					        self._logger.info(__name__, f"Module {type(self)} loaded")
 | 
				
			||||||
@@ -83,306 +45,10 @@ class DatabaseOnReadyEvent(OnReadyABC):
 | 
				
			|||||||
            self._logger.error(__name__, "Database init time calculation failed", e)
 | 
					            self._logger.error(__name__, "Database init time calculation failed", e)
 | 
				
			||||||
            return
 | 
					            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.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.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.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.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.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, self._dtp.transform(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_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
 | 
					 | 
				
			||||||
            settings: BaseServerSettings = self._config.get_configuration(f"BaseServerSettings_{guild.id}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            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 member in guild.members:
 | 
					 | 
				
			||||||
                    if member.bot:
 | 
					 | 
				
			||||||
                        self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
 | 
					 | 
				
			||||||
                        continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
 | 
					 | 
				
			||||||
                    if user is None:
 | 
					 | 
				
			||||||
                        self._logger.fatal(__name__, f"User not found in database: {member.id}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    joins = self._user_joins_vc.find_active_user_joined_voice_channels_by_user_id(user.id)
 | 
					 | 
				
			||||||
                    if joins is None or len(joins) == 0:
 | 
					 | 
				
			||||||
                        continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    for join in joins:
 | 
					 | 
				
			||||||
                        self._logger.warn(
 | 
					 | 
				
			||||||
                            __name__,
 | 
					 | 
				
			||||||
                            f"Active UserJoinedVoiceChannel found in database: {guild.id}:{member.id}@{join.joined_on}",
 | 
					 | 
				
			||||||
                        )
 | 
					 | 
				
			||||||
                        join.leaved_on = datetime.now()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        if (
 | 
					 | 
				
			||||||
                            (join.leaved_on - join.joined_on).total_seconds() / 60 / 60
 | 
					 | 
				
			||||||
                        ) > settings.max_voice_state_hours:
 | 
					 | 
				
			||||||
                            join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        self._user_joins_vc.update_user_joined_voice_channel(join)
 | 
					 | 
				
			||||||
                        # todo: maybe add XP
 | 
					 | 
				
			||||||
                        self._db_context.save_changes()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                for member in guild.members:
 | 
					 | 
				
			||||||
                    if member.bot:
 | 
					 | 
				
			||||||
                        self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
 | 
					 | 
				
			||||||
                        continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if member.voice is None or member.voice.channel.id in settings.afk_channel_ids:
 | 
					 | 
				
			||||||
                        continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
 | 
					 | 
				
			||||||
                    if user is None:
 | 
					 | 
				
			||||||
                        self._logger.fatal(__name__, f"User not found in database: {member.id}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    join = UserJoinedVoiceChannel(user, member.voice.channel.id, datetime.now())
 | 
					 | 
				
			||||||
                    self._user_joins_vc.add_user_joined_voice_channel(join)
 | 
					 | 
				
			||||||
                    self._db_context.save_changes()
 | 
					 | 
				
			||||||
                    self._logger.warn(__name__, f"VS {member.voice}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            except Exception as e:
 | 
					 | 
				
			||||||
                self._logger.error(__name__, f"Cannot get UserJoinedVoiceChannel", e)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _check_user_joined_gs(self):
 | 
					 | 
				
			||||||
        self._logger.debug(__name__, f"Start checking UserJoinedGameServer 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 member in guild.members:
 | 
					 | 
				
			||||||
                    if member.bot:
 | 
					 | 
				
			||||||
                        self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
 | 
					 | 
				
			||||||
                        continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
 | 
					 | 
				
			||||||
                    if user is None:
 | 
					 | 
				
			||||||
                        self._logger.fatal(__name__, f"User not found in database: {member.id}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    joins = self._user_joined_gs.find_active_user_joined_game_servers_by_user_id(user.id)
 | 
					 | 
				
			||||||
                    if joins is None or len(joins) == 0:
 | 
					 | 
				
			||||||
                        continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    for join in joins:
 | 
					 | 
				
			||||||
                        self._logger.warn(
 | 
					 | 
				
			||||||
                            __name__,
 | 
					 | 
				
			||||||
                            f"Active UserJoinedGameServer found in database: {guild.id}:{member.id}@{join.joined_on}",
 | 
					 | 
				
			||||||
                        )
 | 
					 | 
				
			||||||
                        join.leaved_on = datetime.now()
 | 
					 | 
				
			||||||
                        settings: BaseServerSettings = self._config.get_configuration(f"BaseServerSettings_{guild.id}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        if (
 | 
					 | 
				
			||||||
                            (join.leaved_on - join.joined_on).total_seconds() / 60 / 60
 | 
					 | 
				
			||||||
                        ) > settings.max_voice_state_hours:
 | 
					 | 
				
			||||||
                            join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        self._user_joined_gs.update_user_joined_game_server(join)
 | 
					 | 
				
			||||||
                        # todo: maybe add XP
 | 
					 | 
				
			||||||
                        self._db_context.save_changes()
 | 
					 | 
				
			||||||
            except Exception as e:
 | 
					 | 
				
			||||||
                self._logger.error(__name__, f"Cannot get UserJoinedGameServer", e)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    async def on_ready(self):
 | 
					    async def on_ready(self):
 | 
				
			||||||
        self._logger.debug(__name__, f"Module {type(self)} started")
 | 
					        self._logger.debug(__name__, f"Module {type(self)} started")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self._check_known_users()
 | 
					        self._data_integrity.check_data_integrity()
 | 
				
			||||||
        self._check_servers()
 | 
					 | 
				
			||||||
        self._check_clients()
 | 
					 | 
				
			||||||
        self._check_users()
 | 
					 | 
				
			||||||
        self._check_user_joins()
 | 
					 | 
				
			||||||
        self._check_user_joins_vc()
 | 
					 | 
				
			||||||
        self._check_user_joined_gs()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await self._seeder.seed()
 | 
					        await self._seeder.seed()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self._validate_init_time()
 | 
					        self._validate_init_time()
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user