Moved folders #405
This commit is contained in:
26
bot/src/modules/technician/__init__.py
Normal file
26
bot/src/modules/technician/__init__.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
bot sh-edraft.de Discord bot
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Discord bot for customers of sh-edraft.de
|
||||
|
||||
:copyright: (c) 2022 - 2023 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = "modules.technician"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "1.2.0"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="1", minor="2", micro="0")
|
46
bot/src/modules/technician/api_key_seeder.py
Normal file
46
bot/src/modules/technician/api_key_seeder.py
Normal file
@@ -0,0 +1,46 @@
|
||||
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_data.abc.api_key_repository_abc import ApiKeyRepositoryABC
|
||||
from bot_data.abc.data_seeder_abc import DataSeederABC
|
||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||
from bot_data.model.api_key import ApiKey
|
||||
|
||||
|
||||
class ApiKeySeeder(DataSeederABC):
|
||||
def __init__(
|
||||
self,
|
||||
logger: DatabaseLogger,
|
||||
config: ConfigurationABC,
|
||||
bot: DiscordBotServiceABC,
|
||||
db: DatabaseContextABC,
|
||||
users: UserRepositoryABC,
|
||||
api_keys: ApiKeyRepositoryABC,
|
||||
):
|
||||
DataSeederABC.__init__(self)
|
||||
|
||||
self._logger = logger
|
||||
self._config = config
|
||||
self._bot = bot
|
||||
self._db = db
|
||||
self._users = users
|
||||
self._api_keys = api_keys
|
||||
|
||||
async def seed(self):
|
||||
self._logger.debug(__name__, f"API-Key seeder started")
|
||||
|
||||
if self._api_keys.get_api_keys().count() > 0:
|
||||
self._logger.debug(__name__, f"Skip API-Key seeder")
|
||||
return
|
||||
|
||||
try:
|
||||
frontend_key = ApiKey(
|
||||
"frontend", "87f529fd-a32e-40b3-a1d1-7a1583cf3ff5", None
|
||||
)
|
||||
self._api_keys.add_api_key(frontend_key)
|
||||
self._db.save_changes()
|
||||
self._logger.info(__name__, f"Created frontend API-Key")
|
||||
except Exception as e:
|
||||
self._logger.fatal(__name__, "Cannot create frontend API-Key", e)
|
26
bot/src/modules/technician/command/__init__.py
Normal file
26
bot/src/modules/technician/command/__init__.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
bot sh-edraft.de Discord bot
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Discord bot for customers of sh-edraft.de
|
||||
|
||||
:copyright: (c) 2022 - 2023 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = "modules.technician.command"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "1.2.0"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="1", minor="2", micro="0")
|
157
bot/src/modules/technician/command/api_key_group.py
Normal file
157
bot/src/modules/technician/command/api_key_group.py
Normal file
@@ -0,0 +1,157 @@
|
||||
import hashlib
|
||||
import uuid
|
||||
from typing import List as TList
|
||||
|
||||
import discord
|
||||
from cpl_core.database.context import DatabaseContextABC
|
||||
from cpl_discord.command import DiscordCommandABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
from cpl_translation import TranslatePipe
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
from discord.ext.commands import Context
|
||||
|
||||
from bot_api.configuration.authentication_settings import AuthenticationSettings
|
||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||
from bot_core.helper.command_checks import CommandChecks
|
||||
from bot_core.logging.command_logger import CommandLogger
|
||||
from bot_data.abc.api_key_repository_abc import ApiKeyRepositoryABC
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||
from bot_data.model.api_key import ApiKey
|
||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
||||
|
||||
|
||||
class ApiKeyGroup(DiscordCommandABC):
|
||||
def __init__(
|
||||
self,
|
||||
logger: CommandLogger,
|
||||
auth_settings: AuthenticationSettings,
|
||||
message_service: MessageServiceABC,
|
||||
bot: DiscordBotServiceABC,
|
||||
client_utils: ClientUtilsABC,
|
||||
permission_service: PermissionServiceABC,
|
||||
translate: TranslatePipe,
|
||||
db: DatabaseContextABC,
|
||||
servers: ServerRepositoryABC,
|
||||
users: UserRepositoryABC,
|
||||
api_keys: ApiKeyRepositoryABC,
|
||||
):
|
||||
DiscordCommandABC.__init__(self)
|
||||
|
||||
self._logger = logger
|
||||
self._auth_settings = auth_settings
|
||||
self._message_service = message_service
|
||||
self._bot = bot
|
||||
self._client_utils = client_utils
|
||||
self._permissions = permission_service
|
||||
self._t = translate
|
||||
self._db = db
|
||||
self._servers = servers
|
||||
self._users = users
|
||||
self._api_keys = api_keys
|
||||
|
||||
def _get_api_key_str(self, api_key: ApiKey) -> str:
|
||||
return hashlib.sha256(
|
||||
f"{api_key.identifier}:{api_key.key}+{self._auth_settings.secret_key}".encode(
|
||||
"utf-8"
|
||||
)
|
||||
).hexdigest()
|
||||
|
||||
@commands.hybrid_group(name="api-key")
|
||||
@commands.guild_only()
|
||||
async def api_key(self, ctx: Context):
|
||||
pass
|
||||
|
||||
@api_key.command()
|
||||
@commands.guild_only()
|
||||
@CommandChecks.check_is_ready()
|
||||
@CommandChecks.check_is_member_technician()
|
||||
async def get(self, ctx: Context, key: str, wait: int = None):
|
||||
self._logger.debug(
|
||||
__name__, f"Received command api-key get {ctx}: {key},{wait}"
|
||||
)
|
||||
|
||||
api_key = self._api_keys.get_api_key_by_key(key)
|
||||
await self._message_service.send_ctx_msg(
|
||||
ctx,
|
||||
self._t.transform("modules.technician.api_key.get").format(
|
||||
api_key.identifier, self._get_api_key_str(api_key)
|
||||
),
|
||||
)
|
||||
self._logger.trace(__name__, f"Finished command api-key get")
|
||||
|
||||
@get.autocomplete("key")
|
||||
async def get_autocomplete(
|
||||
self, interaction: discord.Interaction, current: str
|
||||
) -> TList[app_commands.Choice[str]]:
|
||||
keys = self._api_keys.get_api_keys()
|
||||
|
||||
return [
|
||||
app_commands.Choice(name=f"{key.identifier}: {key.key}", value=key.key)
|
||||
for key in self._client_utils.get_auto_complete_list(
|
||||
keys, current, lambda x: x.key
|
||||
)
|
||||
]
|
||||
|
||||
@api_key.command()
|
||||
@commands.guild_only()
|
||||
@CommandChecks.check_is_ready()
|
||||
@CommandChecks.check_is_member_moderator()
|
||||
async def add(self, ctx: Context, identifier: str):
|
||||
self._logger.debug(
|
||||
__name__, f"Received command api-key add {ctx}: {identifier}"
|
||||
)
|
||||
|
||||
server = self._servers.get_server_by_discord_id(ctx.guild.id)
|
||||
user = self._users.get_user_by_discord_id_and_server_id(
|
||||
ctx.author.id, server.id
|
||||
)
|
||||
api_key = ApiKey(identifier, str(uuid.uuid4()), user)
|
||||
self._api_keys.add_api_key(api_key)
|
||||
self._db.save_changes()
|
||||
await self._message_service.send_ctx_msg(
|
||||
ctx,
|
||||
self._t.transform("modules.technician.api_key.add.success").format(
|
||||
identifier, self._get_api_key_str(api_key)
|
||||
),
|
||||
)
|
||||
|
||||
self._logger.trace(__name__, f"Finished command api-key add")
|
||||
|
||||
@api_key.command()
|
||||
@commands.guild_only()
|
||||
@CommandChecks.check_is_ready()
|
||||
@CommandChecks.check_is_member_moderator()
|
||||
async def remove(self, ctx: Context, key: str):
|
||||
self._logger.debug(__name__, f"Received command api-key remove {ctx}: {key}")
|
||||
|
||||
keys = self._api_keys.get_api_keys().where(lambda x: x.key == key)
|
||||
if keys.count() < 1:
|
||||
await self._message_service.send_ctx_msg(
|
||||
ctx,
|
||||
self._t.transform("modules.technician.api_key.remove.not_found"),
|
||||
)
|
||||
|
||||
api_key = keys.single()
|
||||
self._api_keys.delete_api_key(api_key)
|
||||
self._db.save_changes()
|
||||
await self._message_service.send_ctx_msg(
|
||||
ctx, self._t.transform("modules.technician.api_key.remove.success")
|
||||
)
|
||||
|
||||
self._logger.trace(__name__, f"Finished command api-key remove")
|
||||
|
||||
@remove.autocomplete("key")
|
||||
async def set_autocomplete(
|
||||
self, interaction: discord.Interaction, current: str
|
||||
) -> TList[app_commands.Choice[str]]:
|
||||
keys = self._api_keys.get_api_keys()
|
||||
|
||||
return [
|
||||
app_commands.Choice(name=f"{key.identifier}: {key.key}", value=key.key)
|
||||
for key in self._client_utils.get_auto_complete_list(
|
||||
keys, current, lambda x: x.key
|
||||
)
|
||||
]
|
122
bot/src/modules/technician/command/log_command.py
Normal file
122
bot/src/modules/technician/command/log_command.py
Normal file
@@ -0,0 +1,122 @@
|
||||
import os
|
||||
from string import Template
|
||||
from zipfile import ZipFile
|
||||
|
||||
import discord
|
||||
from cpl_core.dependency_injection import ServiceProviderABC
|
||||
from cpl_core.environment import ApplicationEnvironmentABC
|
||||
from cpl_core.logging import LoggingSettings
|
||||
from cpl_core.time import TimeFormatSettings
|
||||
from cpl_discord.command import DiscordCommandABC
|
||||
from cpl_query.extension import List
|
||||
from cpl_translation import TranslatePipe
|
||||
from discord.ext import commands
|
||||
from discord.ext.commands import Context
|
||||
|
||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
||||
from bot_core.abc.custom_file_logger_abc import CustomFileLoggerABC
|
||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||
from bot_core.helper.command_checks import CommandChecks
|
||||
from bot_core.logging.command_logger import CommandLogger
|
||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
||||
|
||||
|
||||
class LogCommand(DiscordCommandABC):
|
||||
def __init__(
|
||||
self,
|
||||
logger: CommandLogger,
|
||||
logging_settings: LoggingSettings,
|
||||
services: ServiceProviderABC,
|
||||
message_service: MessageServiceABC,
|
||||
client_utils: ClientUtilsABC,
|
||||
translate: TranslatePipe,
|
||||
permissions: PermissionServiceABC,
|
||||
time_format: TimeFormatSettings,
|
||||
env: ApplicationEnvironmentABC,
|
||||
):
|
||||
DiscordCommandABC.__init__(self)
|
||||
|
||||
self._logger = logger
|
||||
self._logging_settings = logging_settings
|
||||
self._services = services
|
||||
self._message_service = message_service
|
||||
self._client_utils = client_utils
|
||||
self._t = translate
|
||||
self._permissions = permissions
|
||||
|
||||
self._env = env
|
||||
self._log_settings: LoggingSettings = logging_settings
|
||||
self._time_format_settings: TimeFormatSettings = time_format
|
||||
|
||||
self._logger.trace(__name__, f"Loaded command service: {type(self).__name__}")
|
||||
|
||||
def _reduce_path(self, p: str) -> str:
|
||||
if len(p.split("/")) == 1 or p == "":
|
||||
return p
|
||||
|
||||
return self._reduce_path(os.path.dirname(p))
|
||||
|
||||
@commands.hybrid_command()
|
||||
@commands.guild_only()
|
||||
@CommandChecks.check_is_ready()
|
||||
@CommandChecks.check_is_member_technician()
|
||||
async def log(self, ctx: Context):
|
||||
self._logger.debug(__name__, f"Received command log {ctx}")
|
||||
|
||||
possible_log_paths = List(str)
|
||||
possible_log_paths.append(self._reduce_path(self._logging_settings.path))
|
||||
|
||||
file_extensions = List(str)
|
||||
if "." in self._logging_settings.filename:
|
||||
split_filename = self._logging_settings.filename.split(".")
|
||||
file_extensions.append(f".{split_filename[len(split_filename) - 1]}")
|
||||
|
||||
for subclass in CustomFileLoggerABC.__subclasses__():
|
||||
logger: CustomFileLoggerABC = self._services.get_service(subclass)
|
||||
if logger is None:
|
||||
continue
|
||||
|
||||
path = self._reduce_path(logger.settings.path)
|
||||
if "." in logger.settings.filename:
|
||||
split_filename = logger.settings.filename.split(".")
|
||||
file_extension = f".{split_filename[len(split_filename) - 1]}"
|
||||
if file_extension not in file_extensions:
|
||||
file_extensions.append(file_extension)
|
||||
|
||||
if path in possible_log_paths:
|
||||
continue
|
||||
possible_log_paths.append(path)
|
||||
|
||||
files_str = "\n\t".join(possible_log_paths.to_list())
|
||||
self._logger.debug(__name__, f"Possible log files: \n\t{files_str}")
|
||||
|
||||
files = List(str)
|
||||
for possible_path in possible_log_paths:
|
||||
for r, d, f in os.walk(possible_path):
|
||||
for file in f:
|
||||
if "." not in file:
|
||||
continue
|
||||
|
||||
split_filename = file.split(".")
|
||||
if (
|
||||
f".{split_filename[len(split_filename) - 1]}"
|
||||
not in file_extensions
|
||||
):
|
||||
continue
|
||||
|
||||
files.append(os.path.join(r, file))
|
||||
|
||||
files_str = "\n\t".join(files.to_list())
|
||||
self._logger.debug(__name__, f"Log files: \n\t{files_str}")
|
||||
|
||||
zip_file = ZipFile("logs.zip", "w")
|
||||
files.for_each(lambda x: zip_file.write(x))
|
||||
zip_file.close()
|
||||
await self._message_service.send_interaction_msg(
|
||||
ctx.interaction,
|
||||
self._t.transform("modules.technician.log_message"),
|
||||
file=discord.File(zip_file.filename, "logs.zip"),
|
||||
)
|
||||
os.remove(zip_file.filename)
|
||||
|
||||
self._logger.trace(__name__, f"Finished log command")
|
62
bot/src/modules/technician/command/restart_command.py
Normal file
62
bot/src/modules/technician/command/restart_command.py
Normal file
@@ -0,0 +1,62 @@
|
||||
import asyncio
|
||||
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_discord.command import DiscordCommandABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
from cpl_translation import TranslatePipe
|
||||
from discord.ext import commands
|
||||
from discord.ext.commands import Context
|
||||
|
||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||
from bot_core.helper.command_checks import CommandChecks
|
||||
from bot_core.logging.command_logger import CommandLogger
|
||||
from bot_core.service.data_integrity_service import DataIntegrityService
|
||||
from bot_data.model.technician_config import TechnicianConfig
|
||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
||||
|
||||
|
||||
class RestartCommand(DiscordCommandABC):
|
||||
def __init__(
|
||||
self,
|
||||
logger: CommandLogger,
|
||||
config: ConfigurationABC,
|
||||
message_service: MessageServiceABC,
|
||||
bot: DiscordBotServiceABC,
|
||||
client_utils: ClientUtilsABC,
|
||||
translate: TranslatePipe,
|
||||
permissions: PermissionServiceABC,
|
||||
settings: TechnicianConfig,
|
||||
data_integrity: DataIntegrityService,
|
||||
):
|
||||
DiscordCommandABC.__init__(self)
|
||||
|
||||
self._logger = logger
|
||||
self._config = config
|
||||
self._message_service = message_service
|
||||
self._bot = bot
|
||||
self._client_utils = client_utils
|
||||
self._t = translate
|
||||
self._permissions = permissions
|
||||
self._settings = settings
|
||||
self._data_integrity = data_integrity
|
||||
|
||||
self._logger.trace(__name__, f"Loaded command service: {type(self).__name__}")
|
||||
|
||||
@commands.hybrid_command()
|
||||
@commands.guild_only()
|
||||
@CommandChecks.check_is_ready()
|
||||
@CommandChecks.check_is_member_technician()
|
||||
async def restart(self, ctx: Context):
|
||||
self._logger.debug(__name__, f"Received command restart {ctx}")
|
||||
|
||||
self._config.add_configuration("IS_RESTART", "true")
|
||||
await self._client_utils.presence_game("common.presence.restart")
|
||||
await self._message_service.send_ctx_msg(
|
||||
ctx, self._t.transform("modules.technician.restart_message")
|
||||
)
|
||||
await asyncio.sleep(self._settings.wait_for_restart)
|
||||
await self._data_integrity.check_data_integrity(is_for_shutdown=True)
|
||||
await self._bot.stop_async()
|
||||
|
||||
self._logger.trace(__name__, f"Finished restart command")
|
61
bot/src/modules/technician/command/shutdown_command.py
Normal file
61
bot/src/modules/technician/command/shutdown_command.py
Normal file
@@ -0,0 +1,61 @@
|
||||
import asyncio
|
||||
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_discord.command import DiscordCommandABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
from cpl_translation import TranslatePipe
|
||||
from discord.ext import commands
|
||||
from discord.ext.commands import Context
|
||||
|
||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||
from bot_core.helper.command_checks import CommandChecks
|
||||
from bot_core.logging.command_logger import CommandLogger
|
||||
from bot_core.service.data_integrity_service import DataIntegrityService
|
||||
from bot_data.model.technician_config import TechnicianConfig
|
||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
||||
|
||||
|
||||
class ShutdownCommand(DiscordCommandABC):
|
||||
def __init__(
|
||||
self,
|
||||
logger: CommandLogger,
|
||||
config: ConfigurationABC,
|
||||
message_service: MessageServiceABC,
|
||||
bot: DiscordBotServiceABC,
|
||||
client_utils: ClientUtilsABC,
|
||||
translate: TranslatePipe,
|
||||
permissions: PermissionServiceABC,
|
||||
settings: TechnicianConfig,
|
||||
data_integrity: DataIntegrityService,
|
||||
):
|
||||
DiscordCommandABC.__init__(self)
|
||||
|
||||
self._logger = logger
|
||||
self._config = config
|
||||
self._message_service = message_service
|
||||
self._bot = bot
|
||||
self._client_utils = client_utils
|
||||
self._t = translate
|
||||
self._permissions = permissions
|
||||
self._settings = settings
|
||||
self._data_integrity = data_integrity
|
||||
|
||||
self._logger.trace(__name__, f"Loaded command service: {type(self).__name__}")
|
||||
|
||||
@commands.hybrid_command()
|
||||
@commands.guild_only()
|
||||
@CommandChecks.check_is_ready()
|
||||
@CommandChecks.check_is_member_technician()
|
||||
async def shutdown(self, ctx: Context):
|
||||
self._logger.debug(__name__, f"Received command shutdown {ctx}")
|
||||
|
||||
await self._client_utils.presence_game("common.presence.shutdown")
|
||||
await self._message_service.send_ctx_msg(
|
||||
ctx, self._t.transform("modules.technician.shutdown_message")
|
||||
)
|
||||
await asyncio.sleep(self._settings.wait_for_shutdown)
|
||||
await self._data_integrity.check_data_integrity(is_for_shutdown=True)
|
||||
await self._bot.stop_async()
|
||||
|
||||
self._logger.trace(__name__, f"Finished shutdown command")
|
187
bot/src/modules/technician/command/sync_xp_command.py
Normal file
187
bot/src/modules/technician/command/sync_xp_command.py
Normal file
@@ -0,0 +1,187 @@
|
||||
import discord
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.database.context import DatabaseContextABC
|
||||
from cpl_discord.command import DiscordCommandABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
from cpl_translation import TranslatePipe
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
from discord.ext.commands import Context
|
||||
|
||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||
from bot_core.helper.command_checks import CommandChecks
|
||||
from bot_core.logging.command_logger import CommandLogger
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from bot_data.model.technician_config import TechnicianConfig
|
||||
from bot_data.model.user import User
|
||||
from modules.level.service.level_service import LevelService
|
||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
||||
|
||||
|
||||
class SyncXpGroup(DiscordCommandABC):
|
||||
def __init__(
|
||||
self,
|
||||
logger: CommandLogger,
|
||||
config: ConfigurationABC,
|
||||
message_service: MessageServiceABC,
|
||||
bot: DiscordBotServiceABC,
|
||||
client_utils: ClientUtilsABC,
|
||||
translate: TranslatePipe,
|
||||
servers: ServerRepositoryABC,
|
||||
users: UserRepositoryABC,
|
||||
permissions: PermissionServiceABC,
|
||||
settings: TechnicianConfig,
|
||||
db: DatabaseContextABC,
|
||||
level_service: LevelService,
|
||||
):
|
||||
DiscordCommandABC.__init__(self)
|
||||
|
||||
self._logger = logger
|
||||
self._config = config
|
||||
self._message_service = message_service
|
||||
self._bot = bot
|
||||
self._client_utils = client_utils
|
||||
self._t = translate
|
||||
self._servers = servers
|
||||
self._users = users
|
||||
self._permissions = permissions
|
||||
self._settings = settings
|
||||
self._db = db
|
||||
self._level_service = level_service
|
||||
|
||||
self._logger.trace(__name__, f"Loaded command service: {type(self).__name__}")
|
||||
|
||||
@commands.hybrid_group(name="sync-xp")
|
||||
@commands.guild_only()
|
||||
async def sync_xp(self, ctx: Context):
|
||||
pass
|
||||
|
||||
@sync_xp.command(name="all-members")
|
||||
@commands.guild_only()
|
||||
@CommandChecks.check_is_ready()
|
||||
@CommandChecks.check_is_member_technician()
|
||||
async def all_members(self, ctx: Context, server_id: int):
|
||||
self._logger.debug(__name__, f"Received command sync xp {ctx}")
|
||||
|
||||
if ctx.guild is None:
|
||||
return
|
||||
|
||||
settings: ServerConfig = self._config.get_configuration(
|
||||
f"ServerConfig_{ctx.guild.id}"
|
||||
)
|
||||
if not FeatureFlagsSettings.get_flag_from_dict(
|
||||
settings.feature_flags, FeatureFlagsEnum.sync_xp
|
||||
):
|
||||
await self._message_service.send_ctx_msg(
|
||||
ctx, self._t.transform("common.feature_not_activated")
|
||||
)
|
||||
return
|
||||
|
||||
other_server = self._servers.get_server_by_id(server_id)
|
||||
users_on_other_server = self._users.get_users_by_server_id(
|
||||
other_server.id
|
||||
).where(lambda x: not x.left_server)
|
||||
discord_ids_on_other_server = users_on_other_server.select(
|
||||
lambda x: x.discord_id
|
||||
)
|
||||
|
||||
for user in self._users.get_users_by_server_id(
|
||||
self._servers.get_server_by_discord_id(ctx.guild.id).id
|
||||
).where(lambda x: not x.left_server):
|
||||
try:
|
||||
if user.discord_id not in discord_ids_on_other_server:
|
||||
continue
|
||||
|
||||
user_on_other_server: User = users_on_other_server.where(
|
||||
lambda x: x.discord_id == user.discord_id
|
||||
).first_or_default()
|
||||
if user_on_other_server is None or user_on_other_server.xp <= user.xp:
|
||||
continue
|
||||
|
||||
user.xp = user_on_other_server.xp
|
||||
self._users.update_user(user)
|
||||
self._db.save_changes()
|
||||
await self._level_service.check_level(
|
||||
ctx.guild.get_member(user.discord_id)
|
||||
)
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"Cannot sync user {user.name}", e)
|
||||
|
||||
await self._message_service.send_ctx_msg(
|
||||
ctx, self._t.transform("modules.technician.synced_message")
|
||||
)
|
||||
self._logger.trace(__name__, f"Finished sync xp command")
|
||||
|
||||
@all_members.autocomplete("server_id")
|
||||
async def list_autocomplete(
|
||||
self, interaction: discord.Interaction, current: str
|
||||
) -> list[app_commands.Choice]:
|
||||
return [
|
||||
app_commands.Choice(name=server.name, value=server.id)
|
||||
for server in self._client_utils.get_auto_complete_list(
|
||||
self._servers.get_servers(), current, lambda x: x.name
|
||||
)
|
||||
]
|
||||
|
||||
@sync_xp.command(name="by_member")
|
||||
@commands.guild_only()
|
||||
@CommandChecks.check_is_ready()
|
||||
@CommandChecks.check_is_member_technician()
|
||||
async def by_member(self, ctx: Context, server_id: int, member: discord.Member):
|
||||
self._logger.debug(__name__, f"Received command sync xp {ctx}")
|
||||
|
||||
if ctx.guild is None:
|
||||
return
|
||||
|
||||
settings: ServerConfig = self._config.get_configuration(
|
||||
f"ServerConfig_{ctx.guild.id}"
|
||||
)
|
||||
if not FeatureFlagsSettings.get_flag_from_dict(
|
||||
settings.feature_flags, FeatureFlagsEnum.sync_xp
|
||||
):
|
||||
await self._message_service.send_ctx_msg(
|
||||
ctx, self._t.transform("common.feature_not_activated")
|
||||
)
|
||||
return
|
||||
|
||||
other_server = self._servers.get_server_by_id(server_id)
|
||||
user = self._users.get_user_by_discord_id_and_server_id(
|
||||
self._servers.get_server_by_discord_id(ctx.guild.id).id, member.id
|
||||
)
|
||||
|
||||
try:
|
||||
user_on_other_server = (
|
||||
self._users.get_users_by_server_id(other_server.id)
|
||||
.where(lambda x: x.discord_id == member.id)
|
||||
.first_or_default()
|
||||
)
|
||||
if user_on_other_server is None or user_on_other_server.xp <= user.xp:
|
||||
return
|
||||
|
||||
user.xp = user_on_other_server.xp
|
||||
self._users.update_user(user)
|
||||
self._db.save_changes()
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"Cannot sync user {user.name}", e)
|
||||
|
||||
await self._message_service.send_ctx_msg(
|
||||
ctx, self._t.transform("modules.technician.synced_message")
|
||||
)
|
||||
await self._level_service.check_level(member)
|
||||
self._logger.trace(__name__, f"Finished sync xp command")
|
||||
|
||||
@by_member.autocomplete("server_id")
|
||||
async def list_autocomplete(
|
||||
self, interaction: discord.Interaction, current: str
|
||||
) -> list[app_commands.Choice]:
|
||||
return [
|
||||
app_commands.Choice(name=server.name, value=server.id)
|
||||
for server in self._client_utils.get_auto_complete_list(
|
||||
self._servers.get_servers(), current, lambda x: x.name
|
||||
)
|
||||
]
|
44
bot/src/modules/technician/technician.json
Normal file
44
bot/src/modules/technician/technician.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"ProjectSettings": {
|
||||
"Name": "technician",
|
||||
"Version": {
|
||||
"Major": "1",
|
||||
"Minor": "2",
|
||||
"Micro": "0"
|
||||
},
|
||||
"Author": "",
|
||||
"AuthorEmail": "",
|
||||
"Description": "",
|
||||
"LongDescription": "",
|
||||
"URL": "",
|
||||
"CopyrightDate": "",
|
||||
"CopyrightName": "",
|
||||
"LicenseName": "",
|
||||
"LicenseDescription": "",
|
||||
"Dependencies": [
|
||||
"cpl-core==2022.12.0"
|
||||
],
|
||||
"DevDependencies": [
|
||||
"cpl-cli==2022.12.0"
|
||||
],
|
||||
"PythonVersion": ">=3.10.6",
|
||||
"PythonPath": {},
|
||||
"Classifiers": []
|
||||
},
|
||||
"BuildSettings": {
|
||||
"ProjectType": "library",
|
||||
"SourcePath": "",
|
||||
"OutputPath": "../../dist",
|
||||
"Main": "technician.main",
|
||||
"EntryPoint": "technician",
|
||||
"IncludePackageData": false,
|
||||
"Included": [],
|
||||
"Excluded": [
|
||||
"*/__pycache__",
|
||||
"*/logs",
|
||||
"*/tests"
|
||||
],
|
||||
"PackageData": {},
|
||||
"ProjectReferences": []
|
||||
}
|
||||
}
|
36
bot/src/modules/technician/technician_module.py
Normal file
36
bot/src/modules/technician/technician_module.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.dependency_injection import ServiceCollectionABC
|
||||
from cpl_core.environment import ApplicationEnvironmentABC
|
||||
from cpl_discord.service.discord_collection_abc import DiscordCollectionABC
|
||||
|
||||
from bot_core.abc.module_abc import ModuleABC
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_data.abc.data_seeder_abc import DataSeederABC
|
||||
from modules.technician.api_key_seeder import ApiKeySeeder
|
||||
from modules.technician.command.api_key_group import ApiKeyGroup
|
||||
from modules.technician.command.log_command import LogCommand
|
||||
from modules.technician.command.restart_command import RestartCommand
|
||||
from modules.technician.command.shutdown_command import ShutdownCommand
|
||||
from modules.technician.command.sync_xp_command import SyncXpGroup
|
||||
|
||||
|
||||
class TechnicianModule(ModuleABC):
|
||||
def __init__(self, dc: DiscordCollectionABC):
|
||||
ModuleABC.__init__(self, dc, FeatureFlagsEnum.base_module)
|
||||
|
||||
def configure_configuration(
|
||||
self, config: ConfigurationABC, env: ApplicationEnvironmentABC
|
||||
):
|
||||
pass
|
||||
|
||||
def configure_services(
|
||||
self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC
|
||||
):
|
||||
services.add_transient(DataSeederABC, ApiKeySeeder)
|
||||
# commands
|
||||
services.add_transient(RestartCommand)
|
||||
services.add_transient(ShutdownCommand)
|
||||
services.add_transient(LogCommand)
|
||||
services.add_transient(ApiKeyGroup)
|
||||
services.add_transient(SyncXpGroup)
|
||||
# events
|
Reference in New Issue
Block a user