Merge pull request '#268_achievements' (#325) from #268_achievements into 1.1.0
Reviewed-on: sh-edraft.de/kd_discord_bot#325 Reviewed-by: edraft-dev <dev.sven.heidemann@sh-edraft.de>
This commit is contained in:
commit
5c820214a1
@ -7,6 +7,7 @@
|
|||||||
"bot-core": "src/bot_core/bot-core.json",
|
"bot-core": "src/bot_core/bot-core.json",
|
||||||
"bot-data": "src/bot_data/bot-data.json",
|
"bot-data": "src/bot_data/bot-data.json",
|
||||||
"bot-graphql": "src/bot_graphql/bot-graphql.json",
|
"bot-graphql": "src/bot_graphql/bot-graphql.json",
|
||||||
|
"achievements": "src/modules/achievements/achievements.json",
|
||||||
"auto-role": "src/modules/auto_role/auto-role.json",
|
"auto-role": "src/modules/auto_role/auto-role.json",
|
||||||
"base": "src/modules/base/base.json",
|
"base": "src/modules/base/base.json",
|
||||||
"boot-log": "src/modules/boot_log/boot-log.json",
|
"boot-log": "src/modules/boot_log/boot-log.json",
|
||||||
@ -21,25 +22,18 @@
|
|||||||
},
|
},
|
||||||
"Scripts": {
|
"Scripts": {
|
||||||
"format": "black ./",
|
"format": "black ./",
|
||||||
|
|
||||||
"sv": "cpl set-version $ARGS",
|
"sv": "cpl set-version $ARGS",
|
||||||
"set-version": "cpl run set-version $ARGS --dev; echo '';",
|
"set-version": "cpl run set-version $ARGS --dev; echo '';",
|
||||||
|
|
||||||
"gv": "cpl get-version",
|
"gv": "cpl get-version",
|
||||||
"get-version": "export VERSION=$(cpl run get-version --dev); echo $VERSION;",
|
"get-version": "export VERSION=$(cpl run get-version --dev); echo $VERSION;",
|
||||||
|
|
||||||
"pre-build": "cpl set-version $ARGS; black ./;",
|
"pre-build": "cpl set-version $ARGS; black ./;",
|
||||||
"post-build": "cpl run post-build --dev; black ./;",
|
"post-build": "cpl run post-build --dev; black ./;",
|
||||||
|
|
||||||
"pre-prod": "cpl build",
|
"pre-prod": "cpl build",
|
||||||
"prod": "export KDB_ENVIRONMENT=production; export KDB_NAME=KDB-Prod; cpl start;",
|
"prod": "export KDB_ENVIRONMENT=production; export KDB_NAME=KDB-Prod; cpl start;",
|
||||||
|
|
||||||
"pre-stage": "cpl build",
|
"pre-stage": "cpl build",
|
||||||
"stage": "export KDB_ENVIRONMENT=staging; export KDB_NAME=KDB-Stage; cpl start;",
|
"stage": "export KDB_ENVIRONMENT=staging; export KDB_NAME=KDB-Stage; cpl start;",
|
||||||
|
|
||||||
"pre-dev": "cpl build",
|
"pre-dev": "cpl build",
|
||||||
"dev": "export KDB_ENVIRONMENT=development; export KDB_NAME=KDB-Dev; cpl start;",
|
"dev": "export KDB_ENVIRONMENT=development; export KDB_NAME=KDB-Dev; cpl start;",
|
||||||
|
|
||||||
"docker-build": "cpl build $ARGS; docker build -t kdb-bot/kdb-bot:$(cpl gv) .;",
|
"docker-build": "cpl build $ARGS; docker build -t kdb-bot/kdb-bot:$(cpl gv) .;",
|
||||||
"dc-up": "docker-compose up -d",
|
"dc-up": "docker-compose up -d",
|
||||||
"dc-down": "docker-compose down",
|
"dc-down": "docker-compose down",
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit e1c1efac984a04826c0c2713a26129b9d34b21d6
|
Subproject commit 440fb3bd353dce31a2408c977a3168e3cfc32f9a
|
@ -5,6 +5,7 @@ from bot_core.core_extension.core_extension_module import CoreExtensionModule
|
|||||||
from bot_core.core_module import CoreModule
|
from bot_core.core_module import CoreModule
|
||||||
from bot_data.data_module import DataModule
|
from bot_data.data_module import DataModule
|
||||||
from bot_graphql.graphql_module import GraphQLModule
|
from bot_graphql.graphql_module import GraphQLModule
|
||||||
|
from modules.achievements.achievements_module import AchievementsModule
|
||||||
from modules.auto_role.auto_role_module import AutoRoleModule
|
from modules.auto_role.auto_role_module import AutoRoleModule
|
||||||
from modules.base.base_module import BaseModule
|
from modules.base.base_module import BaseModule
|
||||||
from modules.boot_log.boot_log_module import BootLogModule
|
from modules.boot_log.boot_log_module import BootLogModule
|
||||||
@ -31,6 +32,7 @@ class ModuleList:
|
|||||||
LevelModule,
|
LevelModule,
|
||||||
ApiModule,
|
ApiModule,
|
||||||
TechnicianModule,
|
TechnicianModule,
|
||||||
|
AchievementsModule,
|
||||||
# has to be last!
|
# has to be last!
|
||||||
BootLogModule,
|
BootLogModule,
|
||||||
CoreExtensionModule,
|
CoreExtensionModule,
|
||||||
|
@ -4,6 +4,7 @@ from cpl_core.dependency_injection import ServiceCollectionABC
|
|||||||
from cpl_core.environment import ApplicationEnvironmentABC
|
from cpl_core.environment import ApplicationEnvironmentABC
|
||||||
|
|
||||||
from bot_data.abc.migration_abc import MigrationABC
|
from bot_data.abc.migration_abc import MigrationABC
|
||||||
|
from bot_data.migration.achievements_migration import AchievementsMigration
|
||||||
from bot_data.migration.api_key_migration import ApiKeyMigration
|
from bot_data.migration.api_key_migration import ApiKeyMigration
|
||||||
from bot_data.migration.api_migration import ApiMigration
|
from bot_data.migration.api_migration import ApiMigration
|
||||||
from bot_data.migration.auto_role_fix1_migration import AutoRoleFix1Migration
|
from bot_data.migration.auto_role_fix1_migration import AutoRoleFix1Migration
|
||||||
@ -42,3 +43,4 @@ class StartupMigrationExtension(StartupExtensionABC):
|
|||||||
services.add_transient(MigrationABC, RemoveStatsMigration) # 19.02.2023 #190 - 1.0.0
|
services.add_transient(MigrationABC, RemoveStatsMigration) # 19.02.2023 #190 - 1.0.0
|
||||||
services.add_transient(MigrationABC, UserWarningMigration) # 21.02.2023 #35 - 1.0.0
|
services.add_transient(MigrationABC, UserWarningMigration) # 21.02.2023 #35 - 1.0.0
|
||||||
services.add_transient(MigrationABC, DBHistoryMigration) # 06.03.2023 #246 - 1.0.0
|
services.add_transient(MigrationABC, DBHistoryMigration) # 06.03.2023 #246 - 1.0.0
|
||||||
|
services.add_transient(MigrationABC, AchievementsMigration) # 14.06.2023 #268 - 1.1.0
|
||||||
|
@ -11,7 +11,6 @@ from bot_core.configuration.bot_logging_settings import BotLoggingSettings
|
|||||||
from bot_core.configuration.bot_settings import BotSettings
|
from bot_core.configuration.bot_settings import BotSettings
|
||||||
from modules.base.configuration.base_settings import BaseSettings
|
from modules.base.configuration.base_settings import BaseSettings
|
||||||
from modules.boot_log.configuration.boot_log_settings import BootLogSettings
|
from modules.boot_log.configuration.boot_log_settings import BootLogSettings
|
||||||
from modules.level.configuration.level_settings import LevelSettings
|
|
||||||
from modules.permission.configuration.permission_settings import PermissionSettings
|
from modules.permission.configuration.permission_settings import PermissionSettings
|
||||||
|
|
||||||
|
|
||||||
@ -37,7 +36,6 @@ class StartupSettingsExtension(StartupExtensionABC):
|
|||||||
self._configure_settings_with_sub_settings(configuration, BotSettings, lambda x: x.servers, lambda x: x.id)
|
self._configure_settings_with_sub_settings(configuration, BotSettings, lambda x: x.servers, lambda x: x.id)
|
||||||
self._configure_settings_with_sub_settings(configuration, BaseSettings, lambda x: x.servers, lambda x: x.id)
|
self._configure_settings_with_sub_settings(configuration, BaseSettings, lambda x: x.servers, lambda x: x.id)
|
||||||
self._configure_settings_with_sub_settings(configuration, BootLogSettings, lambda x: x.servers, lambda x: x.id)
|
self._configure_settings_with_sub_settings(configuration, BootLogSettings, lambda x: x.servers, lambda x: x.id)
|
||||||
self._configure_settings_with_sub_settings(configuration, LevelSettings, lambda x: x.servers, lambda x: x.id)
|
|
||||||
self._configure_settings_with_sub_settings(
|
self._configure_settings_with_sub_settings(
|
||||||
configuration, PermissionSettings, lambda x: x.servers, lambda x: x.id
|
configuration, PermissionSettings, lambda x: x.servers, lambda x: x.id
|
||||||
)
|
)
|
||||||
@ -50,9 +48,9 @@ class StartupSettingsExtension(StartupExtensionABC):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _configure_settings_with_sub_settings(
|
def _configure_settings_with_sub_settings(
|
||||||
config: ConfigurationABC, settings: Type, list_atr: Callable, atr: Callable
|
config: ConfigurationABC, settings_type: Type, list_atr: Callable, atr: Callable
|
||||||
):
|
):
|
||||||
settings: Optional[settings] = config.get_configuration(settings)
|
settings: Optional[settings_type] = config.get_configuration(settings_type)
|
||||||
if settings is None:
|
if settings is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -93,6 +93,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
|
"achievements": {
|
||||||
|
"got_new_achievement": "{} hat die Errungenschaft {} freigeschaltet :D",
|
||||||
|
"commands": {
|
||||||
|
"check": "Alles klar, ich schaue eben nach... nom nom"
|
||||||
|
}
|
||||||
|
},
|
||||||
"auto_role": {
|
"auto_role": {
|
||||||
"add": {
|
"add": {
|
||||||
"error": {
|
"error": {
|
||||||
|
@ -1,21 +1,30 @@
|
|||||||
import traceback
|
|
||||||
|
|
||||||
from cpl_core.configuration import ConfigurationModelABC
|
from cpl_core.configuration import ConfigurationModelABC
|
||||||
from cpl_core.console import Console
|
|
||||||
from cpl_query.extension import List
|
from cpl_query.extension import List
|
||||||
|
|
||||||
|
from bot_api.json_processor import JSONProcessor
|
||||||
from bot_core.configuration.server_settings import ServerSettings
|
from bot_core.configuration.server_settings import ServerSettings
|
||||||
|
|
||||||
|
|
||||||
class BotSettings(ConfigurationModelABC):
|
class BotSettings(ConfigurationModelABC):
|
||||||
def __init__(self):
|
def __init__(
|
||||||
|
self,
|
||||||
|
technicians: list = None,
|
||||||
|
wait_for_restart: int = 2,
|
||||||
|
wait_for_shutdown: int = 2,
|
||||||
|
cache_max_messages: int = 1000,
|
||||||
|
server_settings: dict = None,
|
||||||
|
):
|
||||||
ConfigurationModelABC.__init__(self)
|
ConfigurationModelABC.__init__(self)
|
||||||
|
|
||||||
|
self._technicians: List[int] = List(int) if technicians is None else technicians
|
||||||
|
self._wait_for_restart = wait_for_restart
|
||||||
|
self._wait_for_shutdown = wait_for_shutdown
|
||||||
|
self._cache_max_messages = cache_max_messages
|
||||||
|
|
||||||
self._servers: List[ServerSettings] = List(ServerSettings)
|
self._servers: List[ServerSettings] = List(ServerSettings)
|
||||||
self._technicians: List[int] = List(int)
|
|
||||||
self._wait_for_restart = 2
|
if server_settings is not None:
|
||||||
self._wait_for_shutdown = 2
|
self._servers_from_dict(server_settings)
|
||||||
self._cache_max_messages = 1000
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def servers(self) -> List[ServerSettings]:
|
def servers(self) -> List[ServerSettings]:
|
||||||
@ -37,26 +46,34 @@ class BotSettings(ConfigurationModelABC):
|
|||||||
def cache_max_messages(self) -> int:
|
def cache_max_messages(self) -> int:
|
||||||
return self._cache_max_messages
|
return self._cache_max_messages
|
||||||
|
|
||||||
def from_dict(self, settings: dict):
|
def _servers_from_dict(self, settings: dict):
|
||||||
try:
|
|
||||||
self._technicians = settings["Technicians"]
|
|
||||||
self._wait_for_restart = settings["WaitForRestart"]
|
|
||||||
self._wait_for_shutdown = settings["WaitForShutdown"]
|
|
||||||
settings.pop("Technicians")
|
|
||||||
settings.pop("WaitForRestart")
|
|
||||||
settings.pop("WaitForShutdown")
|
|
||||||
|
|
||||||
if "CacheMaxMessages" in settings:
|
|
||||||
self._cache_max_messages = settings["CacheMaxMessages"]
|
|
||||||
settings.pop("CacheMaxMessages")
|
|
||||||
|
|
||||||
servers = List(ServerSettings)
|
servers = List(ServerSettings)
|
||||||
for s in settings:
|
for s in settings:
|
||||||
st = ServerSettings()
|
settings[s]["id"] = int(s)
|
||||||
settings[s]["Id"] = s
|
st = JSONProcessor.process(ServerSettings, settings[s])
|
||||||
st.from_dict(settings[s])
|
|
||||||
servers.append(st)
|
servers.append(st)
|
||||||
self._servers = servers
|
self._servers = servers
|
||||||
except Exception as e:
|
|
||||||
Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
|
# def from_dict(self, settings: dict):
|
||||||
Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
|
# try:
|
||||||
|
# self._technicians = settings["Technicians"]
|
||||||
|
# self._wait_for_restart = settings["WaitForRestart"]
|
||||||
|
# self._wait_for_shutdown = settings["WaitForShutdown"]
|
||||||
|
# settings.pop("Technicians")
|
||||||
|
# settings.pop("WaitForRestart")
|
||||||
|
# settings.pop("WaitForShutdown")
|
||||||
|
#
|
||||||
|
# if "CacheMaxMessages" in settings:
|
||||||
|
# self._cache_max_messages = settings["CacheMaxMessages"]
|
||||||
|
# settings.pop("CacheMaxMessages")
|
||||||
|
#
|
||||||
|
# servers = List(ServerSettings)
|
||||||
|
# for s in settings:
|
||||||
|
# st = ServerSettings()
|
||||||
|
# settings[s]["Id"] = s
|
||||||
|
# st.from_dict(settings[s])
|
||||||
|
# servers.append(st)
|
||||||
|
# self._servers = servers
|
||||||
|
# except Exception as e:
|
||||||
|
# Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
|
||||||
|
# Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
|
||||||
|
@ -3,6 +3,7 @@ from enum import Enum
|
|||||||
|
|
||||||
class FeatureFlagsEnum(Enum):
|
class FeatureFlagsEnum(Enum):
|
||||||
# modules
|
# modules
|
||||||
|
achievements_module = "AchievementsModule"
|
||||||
api_module = "ApiModule"
|
api_module = "ApiModule"
|
||||||
admin_module = "AdminModule"
|
admin_module = "AdminModule"
|
||||||
auto_role_module = "AutoRoleModule"
|
auto_role_module = "AutoRoleModule"
|
||||||
|
@ -12,6 +12,7 @@ class FeatureFlagsSettings(ConfigurationModelABC):
|
|||||||
|
|
||||||
self._flags = {
|
self._flags = {
|
||||||
# modules
|
# modules
|
||||||
|
FeatureFlagsEnum.achievements_module.value: False, # 14.06.2023 #268
|
||||||
FeatureFlagsEnum.api_module.value: False, # 13.10.2022 #70
|
FeatureFlagsEnum.api_module.value: False, # 13.10.2022 #70
|
||||||
FeatureFlagsEnum.admin_module.value: False, # 02.10.2022 #48
|
FeatureFlagsEnum.admin_module.value: False, # 02.10.2022 #48
|
||||||
FeatureFlagsEnum.auto_role_module.value: True, # 03.10.2022 #54
|
FeatureFlagsEnum.auto_role_module.value: True, # 03.10.2022 #54
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
class ServerSettings(ConfigurationModelABC):
|
class ServerSettings(ConfigurationModelABC):
|
||||||
def __init__(self):
|
def __init__(
|
||||||
|
self,
|
||||||
|
id: int = None,
|
||||||
|
message_delete_timer: int = None,
|
||||||
|
notification_chat_id: int = None,
|
||||||
|
):
|
||||||
ConfigurationModelABC.__init__(self)
|
ConfigurationModelABC.__init__(self)
|
||||||
|
|
||||||
self._id: int = 0
|
self._id: int = id
|
||||||
self._message_delete_timer: int = 0
|
self._message_delete_timer: int = message_delete_timer
|
||||||
|
self._notification_chat_id: int = notification_chat_id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self) -> int:
|
def id(self) -> int:
|
||||||
@ -19,10 +22,15 @@ class ServerSettings(ConfigurationModelABC):
|
|||||||
def message_delete_timer(self) -> int:
|
def message_delete_timer(self) -> int:
|
||||||
return self._message_delete_timer
|
return self._message_delete_timer
|
||||||
|
|
||||||
def from_dict(self, settings: dict):
|
@property
|
||||||
try:
|
def notification_chat_id(self) -> int:
|
||||||
self._id = int(settings["Id"])
|
return self._notification_chat_id
|
||||||
self._message_delete_timer = int(settings["MessageDeleteTimer"])
|
|
||||||
except Exception as e:
|
# def from_dict(self, settings: dict):
|
||||||
Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in settings")
|
# try:
|
||||||
Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
|
# self._id = int(settings["Id"])
|
||||||
|
# self._message_delete_timer = int(settings["MessageDeleteTimer"])
|
||||||
|
# self._notification_chat_id = int(settings["NotificationChatId"])
|
||||||
|
# except Exception as e:
|
||||||
|
# Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in settings")
|
||||||
|
# Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
|
||||||
|
@ -24,6 +24,7 @@ from bot_data.model.user_joined_server import UserJoinedServer
|
|||||||
from bot_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
|
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 bot_data.service.user_repository_service import ServerRepositoryABC
|
||||||
|
from modules.achievements.achievement_service import AchievementService
|
||||||
from modules.base.configuration.base_server_settings import BaseServerSettings
|
from modules.base.configuration.base_server_settings import BaseServerSettings
|
||||||
|
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ class DataIntegrityService:
|
|||||||
user_joins: UserJoinedServerRepositoryABC,
|
user_joins: UserJoinedServerRepositoryABC,
|
||||||
user_joins_vc: UserJoinedVoiceChannelRepositoryABC,
|
user_joins_vc: UserJoinedVoiceChannelRepositoryABC,
|
||||||
user_joined_gs: UserJoinedGameServerRepositoryABC,
|
user_joined_gs: UserJoinedGameServerRepositoryABC,
|
||||||
|
achievement_service: AchievementService,
|
||||||
dtp: DateTimeOffsetPipe,
|
dtp: DateTimeOffsetPipe,
|
||||||
):
|
):
|
||||||
self._config = config
|
self._config = config
|
||||||
@ -57,6 +59,7 @@ class DataIntegrityService:
|
|||||||
self._user_joins = user_joins
|
self._user_joins = user_joins
|
||||||
self._user_joins_vc = user_joins_vc
|
self._user_joins_vc = user_joins_vc
|
||||||
self._user_joined_gs = user_joined_gs
|
self._user_joined_gs = user_joined_gs
|
||||||
|
self._achievements = achievement_service
|
||||||
self._dtp = dtp
|
self._dtp = dtp
|
||||||
|
|
||||||
self._is_for_shutdown = False
|
self._is_for_shutdown = False
|
||||||
@ -360,6 +363,25 @@ class DataIntegrityService:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._logger.error(__name__, f"Cannot get UserJoinedGameServer", e)
|
self._logger.error(__name__, f"Cannot get UserJoinedGameServer", e)
|
||||||
|
|
||||||
|
def _check_for_user_achievements(self):
|
||||||
|
self._logger.debug(__name__, f"Start checking UserGotAchievement table")
|
||||||
|
|
||||||
|
for guild in self._bot.guilds:
|
||||||
|
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}")
|
||||||
|
|
||||||
|
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}")
|
||||||
|
|
||||||
|
self._bot.loop.create_task(self._achievements.validate_achievements_for_user(user))
|
||||||
|
|
||||||
def check_data_integrity(self, is_for_shutdown=False):
|
def check_data_integrity(self, is_for_shutdown=False):
|
||||||
if is_for_shutdown != self._is_for_shutdown:
|
if is_for_shutdown != self._is_for_shutdown:
|
||||||
self._is_for_shutdown = is_for_shutdown
|
self._is_for_shutdown = is_for_shutdown
|
||||||
@ -371,3 +393,4 @@ class DataIntegrityService:
|
|||||||
self._check_user_joins()
|
self._check_user_joins()
|
||||||
self._check_user_joins_vc()
|
self._check_user_joins_vc()
|
||||||
self._check_user_joined_gs()
|
self._check_user_joined_gs()
|
||||||
|
self._check_for_user_achievements()
|
||||||
|
52
kdb-bot/src/bot_data/abc/achievement_repository_abc.py
Normal file
52
kdb-bot/src/bot_data/abc/achievement_repository_abc.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
from cpl_query.extension import List
|
||||||
|
|
||||||
|
from bot_data.model.achievement import Achievement
|
||||||
|
from bot_data.model.user_got_achievement import UserGotAchievement
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementRepositoryABC(ABC):
|
||||||
|
@abstractmethod
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_achievements(self) -> List[Achievement]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_achievement_by_id(self, id: int) -> Achievement:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_achievements_by_server_id(self, server_id: int) -> List[Achievement]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_achievements_by_user_id(self, user_id: int) -> List[Achievement]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_user_got_achievements_by_achievement_id(self, achievement_id: int) -> List[Achievement]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def add_achievement(self, achievement: Achievement):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def update_achievement(self, achievement: Achievement):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def delete_achievement(self, achievement: Achievement):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def add_user_got_achievement(self, join: UserGotAchievement):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def delete_user_got_achievement(self, join: UserGotAchievement):
|
||||||
|
pass
|
@ -5,6 +5,7 @@ from cpl_discord.service.discord_collection_abc import DiscordCollectionABC
|
|||||||
|
|
||||||
from bot_core.abc.module_abc import ModuleABC
|
from bot_core.abc.module_abc import ModuleABC
|
||||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||||
|
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
|
||||||
from bot_data.abc.api_key_repository_abc import ApiKeyRepositoryABC
|
from bot_data.abc.api_key_repository_abc import ApiKeyRepositoryABC
|
||||||
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
|
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
|
||||||
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
|
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
|
||||||
@ -24,6 +25,7 @@ from bot_data.abc.user_message_count_per_hour_repository_abc import (
|
|||||||
)
|
)
|
||||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||||
from bot_data.abc.user_warnings_repository_abc import UserWarningsRepositoryABC
|
from bot_data.abc.user_warnings_repository_abc import UserWarningsRepositoryABC
|
||||||
|
from bot_data.service.achievements_repository_service import AchievementRepositoryService
|
||||||
from bot_data.service.api_key_repository_service import ApiKeyRepositoryService
|
from bot_data.service.api_key_repository_service import ApiKeyRepositoryService
|
||||||
from bot_data.service.auth_user_repository_service import AuthUserRepositoryService
|
from bot_data.service.auth_user_repository_service import AuthUserRepositoryService
|
||||||
from bot_data.service.auto_role_repository_service import AutoRoleRepositoryService
|
from bot_data.service.auto_role_repository_service import AutoRoleRepositoryService
|
||||||
@ -77,5 +79,6 @@ class DataModule(ModuleABC):
|
|||||||
)
|
)
|
||||||
services.add_transient(GameServerRepositoryABC, GameServerRepositoryService)
|
services.add_transient(GameServerRepositoryABC, GameServerRepositoryService)
|
||||||
services.add_transient(UserGameIdentRepositoryABC, UserGameIdentRepositoryService)
|
services.add_transient(UserGameIdentRepositoryABC, UserGameIdentRepositoryService)
|
||||||
|
services.add_transient(AchievementRepositoryABC, AchievementRepositoryService)
|
||||||
|
|
||||||
services.add_transient(SeederService)
|
services.add_transient(SeederService)
|
||||||
|
@ -11,6 +11,7 @@ class DBContext(DatabaseContext):
|
|||||||
self._logger = logger
|
self._logger = logger
|
||||||
|
|
||||||
DatabaseContext.__init__(self)
|
DatabaseContext.__init__(self)
|
||||||
|
self._fails = 0
|
||||||
|
|
||||||
def connect(self, database_settings: DatabaseSettings):
|
def connect(self, database_settings: DatabaseSettings):
|
||||||
try:
|
try:
|
||||||
@ -32,7 +33,11 @@ class DBContext(DatabaseContext):
|
|||||||
try:
|
try:
|
||||||
return super(DBContext, self).select(statement)
|
return super(DBContext, self).select(statement)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
if self._fails >= 3:
|
||||||
|
self._logger.fatal(__name__, f"Database error caused by {statement}", e)
|
||||||
|
|
||||||
self._logger.error(__name__, f"Database error caused by {statement}", e)
|
self._logger.error(__name__, f"Database error caused by {statement}", e)
|
||||||
|
self._fails += 1
|
||||||
try:
|
try:
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
return self.select(statement)
|
return self.select(statement)
|
||||||
|
127
kdb-bot/src/bot_data/migration/achievements_migration.py
Normal file
127
kdb-bot/src/bot_data/migration/achievements_migration.py
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
from bot_core.logging.database_logger import DatabaseLogger
|
||||||
|
from bot_data.abc.migration_abc import MigrationABC
|
||||||
|
from bot_data.db_context import DBContext
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementsMigration(MigrationABC):
|
||||||
|
name = "1.1.0_AchievementsMigration"
|
||||||
|
|
||||||
|
def __init__(self, logger: DatabaseLogger, db: DBContext):
|
||||||
|
MigrationABC.__init__(self)
|
||||||
|
self._logger = logger
|
||||||
|
self._db = db
|
||||||
|
self._cursor = db.cursor
|
||||||
|
|
||||||
|
def upgrade(self):
|
||||||
|
self._logger.debug(__name__, "Running upgrade")
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Achievements` (
|
||||||
|
`Id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`Name` VARCHAR(255) NOT NULL,
|
||||||
|
`Description` VARCHAR(255) NOT NULL,
|
||||||
|
`Attribute` VARCHAR(255) NOT NULL,
|
||||||
|
`Operator` VARCHAR(255) NOT NULL,
|
||||||
|
`Value` VARCHAR(255) NOT NULL,
|
||||||
|
`ServerId` BIGINT,
|
||||||
|
`CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||||
|
`LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||||
|
PRIMARY KEY(`Id`),
|
||||||
|
FOREIGN KEY (`ServerId`) REFERENCES `Servers`(`ServerId`)
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `AchievementsHistory`
|
||||||
|
(
|
||||||
|
`Id` BIGINT(20) NOT NULL,
|
||||||
|
`Name` VARCHAR(255) NOT NULL,
|
||||||
|
`Description` VARCHAR(255) NOT NULL,
|
||||||
|
`Attribute` VARCHAR(255) NOT NULL,
|
||||||
|
`Operator` VARCHAR(255) NOT NULL,
|
||||||
|
`Value` VARCHAR(255) NOT NULL,
|
||||||
|
`ServerId` BIGINT,
|
||||||
|
`Deleted` BOOL DEFAULT FALSE,
|
||||||
|
`DateFrom` DATETIME(6) NOT NULL,
|
||||||
|
`DateTo` DATETIME(6) NOT NULL
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `UserGotAchievements` (
|
||||||
|
`Id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`UserId` BIGINT,
|
||||||
|
`AchievementId` BIGINT,
|
||||||
|
`CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||||
|
`LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||||
|
PRIMARY KEY(`Id`),
|
||||||
|
FOREIGN KEY (`UserId`) REFERENCES `Users`(`UserId`),
|
||||||
|
FOREIGN KEY (`AchievementId`) REFERENCES `Achievements`(`Id`)
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# A join table history between users and achievements is not necessary.
|
||||||
|
|
||||||
|
self._cursor.execute(str(f"""ALTER TABLE Users ADD MessageCount BIGINT NOT NULL DEFAULT 0 AFTER XP;"""))
|
||||||
|
self._cursor.execute(str(f"""ALTER TABLE Users ADD ReactionCount BIGINT NOT NULL DEFAULT 0 AFTER XP;"""))
|
||||||
|
self._cursor.execute(str(f"""ALTER TABLE UsersHistory ADD MessageCount BIGINT NOT NULL DEFAULT 0 AFTER XP;"""))
|
||||||
|
self._cursor.execute(str(f"""ALTER TABLE UsersHistory ADD ReactionCount BIGINT NOT NULL DEFAULT 0 AFTER XP;"""))
|
||||||
|
|
||||||
|
self._cursor.execute(str(f"""DROP TRIGGER IF EXISTS `TR_AchievementsUpdate`;"""))
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
CREATE TRIGGER `TR_AchievementsUpdate`
|
||||||
|
AFTER UPDATE
|
||||||
|
ON `Achievements`
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO `AchievementsHistory` (
|
||||||
|
`Id`, `Name`, `Description`, `Attribute`, `Operator`, `Value`, `ServerId`, `DateFrom`, `DateTo`
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
OLD.Id, OLD.Name, OLD.Description, OLD.Attribute, OLD.Operator, OLD.Value, OLD.ServerId, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)
|
||||||
|
);
|
||||||
|
END;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self._cursor.execute(str(f"""DROP TRIGGER IF EXISTS `TR_AchievementsDelete`;"""))
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
CREATE TRIGGER `TR_AchievementsDelete`
|
||||||
|
AFTER DELETE
|
||||||
|
ON `Achievements`
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO `AchievementsHistory` (
|
||||||
|
`Id`, `Name`, `Description`, `Attribute`, `Operator`, `Value`, `ServerId`, `Deleted`, `DateFrom`, `DateTo`
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
OLD.Id, OLD.Name, OLD.Description, OLD.Attribute, OLD.Operator, OLD.Value, OLD.ServerId, TRUE, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)
|
||||||
|
);
|
||||||
|
END;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def downgrade(self):
|
||||||
|
self._cursor.execute("DROP TABLE `Achievements`;")
|
||||||
|
|
||||||
|
self._cursor.execute(str(f"""ALTER TABLE Users DROP COLUMN MessageCount;"""))
|
||||||
|
self._cursor.execute(str(f"""ALTER TABLE Users DROP COLUMN ReactionCount;"""))
|
149
kdb-bot/src/bot_data/model/achievement.py
Normal file
149
kdb-bot/src/bot_data/model/achievement.py
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from cpl_core.database import TableABC
|
||||||
|
from cpl_core.dependency_injection import ServiceProviderABC
|
||||||
|
|
||||||
|
from bot_data.model.server import Server
|
||||||
|
|
||||||
|
|
||||||
|
class Achievement(TableABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
description: str,
|
||||||
|
attribute: str,
|
||||||
|
operator: str,
|
||||||
|
value: str,
|
||||||
|
server: Optional[Server],
|
||||||
|
created_at: datetime = None,
|
||||||
|
modified_at: datetime = None,
|
||||||
|
id=0,
|
||||||
|
):
|
||||||
|
self._id = id
|
||||||
|
self._name = name
|
||||||
|
self._description = description
|
||||||
|
self._attribute = attribute
|
||||||
|
|
||||||
|
if self._is_operator_valid(operator):
|
||||||
|
raise ValueError("Operator invalid")
|
||||||
|
|
||||||
|
self._operator = operator
|
||||||
|
self._value = value
|
||||||
|
self._server = server
|
||||||
|
|
||||||
|
TableABC.__init__(self)
|
||||||
|
self._created_at = created_at if created_at is not None else self._created_at
|
||||||
|
self._modified_at = modified_at if modified_at is not None else self._modified_at
|
||||||
|
|
||||||
|
@ServiceProviderABC.inject
|
||||||
|
def _is_operator_valid(self, operator, service: ServiceProviderABC) -> bool:
|
||||||
|
from modules.achievements.achievement_service import AchievementService
|
||||||
|
|
||||||
|
achievements: AchievementService = service.get_service(AchievementService)
|
||||||
|
return operator not in achievements.get_operators()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self) -> int:
|
||||||
|
return self._id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> str:
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, value: str):
|
||||||
|
self._name = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self) -> str:
|
||||||
|
return self._description
|
||||||
|
|
||||||
|
@description.setter
|
||||||
|
def description(self, value: str):
|
||||||
|
self._description = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def attribute(self) -> str:
|
||||||
|
return self._attribute
|
||||||
|
|
||||||
|
@attribute.setter
|
||||||
|
def attribute(self, value: str):
|
||||||
|
self._attribute = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def operator(self) -> str:
|
||||||
|
return self._operator
|
||||||
|
|
||||||
|
@operator.setter
|
||||||
|
def operator(self, value: str):
|
||||||
|
self._operator = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value(self) -> str:
|
||||||
|
return self._value
|
||||||
|
|
||||||
|
@value.setter
|
||||||
|
def value(self, value: str):
|
||||||
|
self._value = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def server(self) -> Server:
|
||||||
|
return self._server
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_select_all_string() -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
SELECT * FROM `Achievements`;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_select_by_id_string(id: int) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
SELECT * FROM `Achievements`
|
||||||
|
WHERE `Id` = {id};
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def insert_string(self) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
INSERT INTO `Achievements` (
|
||||||
|
`Name`, `Description`, `Attribute`, `Operator`, `Value`, `ServerId`
|
||||||
|
) VALUES (
|
||||||
|
'{self._name}',
|
||||||
|
'{self._description}',
|
||||||
|
'{self._attribute}',
|
||||||
|
'{self._operator}',
|
||||||
|
'{self._value}',
|
||||||
|
{self._server.id}
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def udpate_string(self) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
UPDATE `Achievements`
|
||||||
|
SET `Name` = '{self._name}',
|
||||||
|
`Description` = '{self._description}',
|
||||||
|
`Attribute` = '{self._attribute}',
|
||||||
|
`Operator` = '{self._operator}',
|
||||||
|
`Value` = '{self._value}'
|
||||||
|
WHERE `Id` = {self._id};
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def delete_string(self) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
DELETE FROM `Achievements`
|
||||||
|
WHERE `Id` = {self._id};
|
||||||
|
"""
|
||||||
|
)
|
58
kdb-bot/src/bot_data/model/achievement_history.py
Normal file
58
kdb-bot/src/bot_data/model/achievement_history.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
from bot_data.abc.history_table_abc import HistoryTableABC
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementHistory(HistoryTableABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
description: str,
|
||||||
|
attribute: str,
|
||||||
|
operator: str,
|
||||||
|
value: str,
|
||||||
|
server: int,
|
||||||
|
deleted: bool,
|
||||||
|
date_from: str,
|
||||||
|
date_to: str,
|
||||||
|
id=0,
|
||||||
|
):
|
||||||
|
HistoryTableABC.__init__(self)
|
||||||
|
|
||||||
|
self._id = id
|
||||||
|
self._name = name
|
||||||
|
self._description = description
|
||||||
|
self._attribute = attribute
|
||||||
|
self._operator = operator
|
||||||
|
self._value = value
|
||||||
|
self._server = server
|
||||||
|
|
||||||
|
self._deleted = deleted
|
||||||
|
self._date_from = date_from
|
||||||
|
self._date_to = date_to
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self) -> int:
|
||||||
|
return self._id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> str:
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self) -> str:
|
||||||
|
return self._description
|
||||||
|
|
||||||
|
@property
|
||||||
|
def attribute(self) -> str:
|
||||||
|
return self._attribute
|
||||||
|
|
||||||
|
@property
|
||||||
|
def operator(self) -> str:
|
||||||
|
return self._operator
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value(self) -> str:
|
||||||
|
return self._value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def server(self) -> int:
|
||||||
|
return self._server
|
@ -15,6 +15,8 @@ class User(TableABC):
|
|||||||
self,
|
self,
|
||||||
dc_id: int,
|
dc_id: int,
|
||||||
xp: int,
|
xp: int,
|
||||||
|
message_count: int,
|
||||||
|
reaction_count: int,
|
||||||
server: Optional[Server],
|
server: Optional[Server],
|
||||||
created_at: datetime = None,
|
created_at: datetime = None,
|
||||||
modified_at: datetime = None,
|
modified_at: datetime = None,
|
||||||
@ -23,6 +25,8 @@ class User(TableABC):
|
|||||||
self._user_id = id
|
self._user_id = id
|
||||||
self._discord_id = dc_id
|
self._discord_id = dc_id
|
||||||
self._xp = xp
|
self._xp = xp
|
||||||
|
self._message_count = message_count
|
||||||
|
self._reaction_count = reaction_count
|
||||||
self._server = server
|
self._server = server
|
||||||
|
|
||||||
TableABC.__init__(self)
|
TableABC.__init__(self)
|
||||||
@ -59,6 +63,22 @@ class User(TableABC):
|
|||||||
def xp(self, value: int):
|
def xp(self, value: int):
|
||||||
self._xp = value
|
self._xp = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def message_count(self) -> int:
|
||||||
|
return self._message_count
|
||||||
|
|
||||||
|
@message_count.setter
|
||||||
|
def message_count(self, value: int):
|
||||||
|
self._message_count = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reaction_count(self) -> int:
|
||||||
|
return self._reaction_count
|
||||||
|
|
||||||
|
@reaction_count.setter
|
||||||
|
def reaction_count(self, value: int):
|
||||||
|
self._reaction_count = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ServiceProviderABC.inject
|
@ServiceProviderABC.inject
|
||||||
def ontime(self, services: ServiceProviderABC) -> float:
|
def ontime(self, services: ServiceProviderABC) -> float:
|
||||||
@ -151,10 +171,12 @@ class User(TableABC):
|
|||||||
return str(
|
return str(
|
||||||
f"""
|
f"""
|
||||||
INSERT INTO `Users` (
|
INSERT INTO `Users` (
|
||||||
`DiscordId`, `XP`, `ServerId`
|
`DiscordId`, `XP`, `MessageCount`, `ReactionCount`, `ServerId`
|
||||||
) VALUES (
|
) VALUES (
|
||||||
{self._discord_id},
|
{self._discord_id},
|
||||||
{self._xp},
|
{self._xp},
|
||||||
|
{self._message_count},
|
||||||
|
{self._reaction_count},
|
||||||
{self._server.id}
|
{self._server.id}
|
||||||
);
|
);
|
||||||
"""
|
"""
|
||||||
@ -165,7 +187,9 @@ class User(TableABC):
|
|||||||
return str(
|
return str(
|
||||||
f"""
|
f"""
|
||||||
UPDATE `Users`
|
UPDATE `Users`
|
||||||
SET `XP` = {self._xp}
|
SET `XP` = {self._xp},
|
||||||
|
`MessageCount` = {self._message_count},
|
||||||
|
`ReactionCount` = {self._reaction_count}
|
||||||
WHERE `UserId` = {self._user_id};
|
WHERE `UserId` = {self._user_id};
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
105
kdb-bot/src/bot_data/model/user_got_achievement.py
Normal file
105
kdb-bot/src/bot_data/model/user_got_achievement.py
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from cpl_core.database import TableABC
|
||||||
|
|
||||||
|
from bot_data.model.achievement import Achievement
|
||||||
|
from bot_data.model.user import User
|
||||||
|
|
||||||
|
|
||||||
|
class UserGotAchievement(TableABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
user: Optional[User],
|
||||||
|
achievement: Optional[Achievement],
|
||||||
|
created_at: datetime = None,
|
||||||
|
modified_at: datetime = None,
|
||||||
|
id=0,
|
||||||
|
):
|
||||||
|
self._id = id
|
||||||
|
self._user = user
|
||||||
|
self._achievement = achievement
|
||||||
|
|
||||||
|
TableABC.__init__(self)
|
||||||
|
self._created_at = created_at if created_at is not None else self._created_at
|
||||||
|
self._modified_at = modified_at if modified_at is not None else self._modified_at
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self) -> int:
|
||||||
|
return self._id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user(self) -> User:
|
||||||
|
return self._user
|
||||||
|
|
||||||
|
@property
|
||||||
|
def achievement(self) -> Achievement:
|
||||||
|
return self._achievement
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_select_all_string() -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
SELECT * FROM `UserGotAchievements`;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_select_by_id_string(id: int) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
SELECT * FROM `UserGotAchievements`
|
||||||
|
WHERE `Id` = {id};
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_select_by_user_id_string(id: int) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
SELECT * FROM `UserGotAchievements`
|
||||||
|
WHERE `UserId` = {id};
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_select_by_achievement_id_string(id: int) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
SELECT * FROM `UserGotAchievements`
|
||||||
|
WHERE `AchievementId` = {id};
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def insert_string(self) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
INSERT INTO `UserGotAchievements` (
|
||||||
|
`UserId`, `AchievementId`
|
||||||
|
) VALUES (
|
||||||
|
{self._user.id},
|
||||||
|
{self._achievement.id}
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def udpate_string(self) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
UPDATE `UserGotAchievements`
|
||||||
|
SET `UserId` = '{self._user.id}',
|
||||||
|
`AchievementId` = '{self._achievement.id}'
|
||||||
|
WHERE `Id` = {self._id};
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def delete_string(self) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
DELETE FROM `UserGotAchievements`
|
||||||
|
WHERE `Id` = {self._id};
|
||||||
|
"""
|
||||||
|
)
|
@ -9,6 +9,8 @@ class UserHistory(HistoryTableABC):
|
|||||||
self,
|
self,
|
||||||
dc_id: int,
|
dc_id: int,
|
||||||
xp: int,
|
xp: int,
|
||||||
|
message_count: int,
|
||||||
|
reaction_count: int,
|
||||||
server: int,
|
server: int,
|
||||||
deleted: bool,
|
deleted: bool,
|
||||||
date_from: str,
|
date_from: str,
|
||||||
@ -20,6 +22,8 @@ class UserHistory(HistoryTableABC):
|
|||||||
self._user_id = id
|
self._user_id = id
|
||||||
self._discord_id = dc_id
|
self._discord_id = dc_id
|
||||||
self._xp = xp
|
self._xp = xp
|
||||||
|
self._message_count = message_count
|
||||||
|
self._reaction_count = reaction_count
|
||||||
self._server = server
|
self._server = server
|
||||||
|
|
||||||
self._deleted = deleted
|
self._deleted = deleted
|
||||||
@ -38,6 +42,14 @@ class UserHistory(HistoryTableABC):
|
|||||||
def xp(self) -> int:
|
def xp(self) -> int:
|
||||||
return self._xp
|
return self._xp
|
||||||
|
|
||||||
|
@property
|
||||||
|
def message_count(self) -> int:
|
||||||
|
return self._message_count
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reaction_count(self) -> int:
|
||||||
|
return self._reaction_count
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def server(self) -> int:
|
def server(self) -> int:
|
||||||
return self._server
|
return self._server
|
||||||
|
123
kdb-bot/src/bot_data/service/achievements_repository_service.py
Normal file
123
kdb-bot/src/bot_data/service/achievements_repository_service.py
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
from cpl_core.database.context import DatabaseContextABC
|
||||||
|
from cpl_query.extension import List
|
||||||
|
|
||||||
|
from bot_core.logging.database_logger import DatabaseLogger
|
||||||
|
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
|
||||||
|
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||||
|
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||||
|
from bot_data.model.achievement import Achievement
|
||||||
|
from bot_data.model.user_got_achievement import UserGotAchievement
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementRepositoryService(AchievementRepositoryABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
logger: DatabaseLogger,
|
||||||
|
db_context: DatabaseContextABC,
|
||||||
|
servers: ServerRepositoryABC,
|
||||||
|
users: UserRepositoryABC,
|
||||||
|
):
|
||||||
|
self._logger = logger
|
||||||
|
self._context = db_context
|
||||||
|
|
||||||
|
self._servers = servers
|
||||||
|
self._users = users
|
||||||
|
|
||||||
|
AchievementRepositoryABC.__init__(self)
|
||||||
|
|
||||||
|
def _from_result(self, result: tuple):
|
||||||
|
return Achievement(
|
||||||
|
result[1],
|
||||||
|
result[2],
|
||||||
|
result[3],
|
||||||
|
result[4],
|
||||||
|
result[5],
|
||||||
|
self._servers.get_server_by_id(result[6]),
|
||||||
|
result[7],
|
||||||
|
result[8],
|
||||||
|
id=result[0],
|
||||||
|
)
|
||||||
|
|
||||||
|
def _join_from_result(self, result: tuple):
|
||||||
|
return UserGotAchievement(
|
||||||
|
self._users.get_user_by_id(result[1]),
|
||||||
|
self.get_achievement_by_id(result[2]),
|
||||||
|
result[3],
|
||||||
|
result[4],
|
||||||
|
id=result[0],
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_achievements(self) -> List[Achievement]:
|
||||||
|
achievements = List(Achievement)
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {Achievement.get_select_all_string()}")
|
||||||
|
results = self._context.select(Achievement.get_select_all_string())
|
||||||
|
for result in results:
|
||||||
|
self._logger.trace(__name__, f"Get user with id {result[0]}")
|
||||||
|
achievements.append(self._from_result(result))
|
||||||
|
|
||||||
|
return achievements
|
||||||
|
|
||||||
|
def get_achievement_by_id(self, id: int) -> Achievement:
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {Achievement.get_select_by_id_string(id)}")
|
||||||
|
result = self._context.select(Achievement.get_select_by_id_string(id))[0]
|
||||||
|
|
||||||
|
return self._from_result(result)
|
||||||
|
|
||||||
|
def get_achievements_by_server_id(self, server_id: int) -> List[Achievement]:
|
||||||
|
achievements = List(Achievement)
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {Achievement.get_select_by_id_string(server_id)}")
|
||||||
|
results = self._context.select(Achievement.get_select_all_string())
|
||||||
|
for result in results:
|
||||||
|
self._logger.trace(__name__, f"Get user with id {result[0]}")
|
||||||
|
achievements.append(self._from_result(result))
|
||||||
|
|
||||||
|
return achievements
|
||||||
|
|
||||||
|
def get_achievements_by_user_id(self, user_id: int) -> List[Achievement]:
|
||||||
|
achievements = List(Achievement)
|
||||||
|
achievements_joins = List(UserGotAchievement)
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {UserGotAchievement.get_select_by_user_id_string(user_id)}")
|
||||||
|
results = self._context.select(UserGotAchievement.get_select_by_user_id_string(user_id))
|
||||||
|
for result in results:
|
||||||
|
self._logger.trace(__name__, f"Got UserGotAchievement with id {result[0]}")
|
||||||
|
achievements_joins.append(self._join_from_result(result))
|
||||||
|
|
||||||
|
for achievements_join in achievements_joins:
|
||||||
|
results = self._context.select(Achievement.get_select_by_id_string(achievements_join.achievement.id))
|
||||||
|
for result in results:
|
||||||
|
self._logger.trace(__name__, f"Got Achievement with id {result[0]}")
|
||||||
|
achievements.append(self._from_result(result))
|
||||||
|
|
||||||
|
return achievements
|
||||||
|
|
||||||
|
def get_user_got_achievements_by_achievement_id(self, achievement_id: int) -> List[Achievement]:
|
||||||
|
achievements_joins = List(UserGotAchievement)
|
||||||
|
self._logger.trace(
|
||||||
|
__name__, f"Send SQL command: {UserGotAchievement.get_select_by_achievement_id_string(achievement_id)}"
|
||||||
|
)
|
||||||
|
results = self._context.select(UserGotAchievement.get_select_by_achievement_id_string(achievement_id))
|
||||||
|
for result in results:
|
||||||
|
self._logger.trace(__name__, f"Got UserGotAchievement with id {result[0]}")
|
||||||
|
achievements_joins.append(self._join_from_result(result))
|
||||||
|
|
||||||
|
return achievements_joins
|
||||||
|
|
||||||
|
def add_achievement(self, achievement: Achievement):
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {achievement.insert_string}")
|
||||||
|
self._context.cursor.execute(achievement.insert_string)
|
||||||
|
|
||||||
|
def update_achievement(self, achievement: Achievement):
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {achievement.udpate_string}")
|
||||||
|
self._context.cursor.execute(achievement.udpate_string)
|
||||||
|
|
||||||
|
def delete_achievement(self, achievement: Achievement):
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {achievement.delete_string}")
|
||||||
|
self._context.cursor.execute(achievement.delete_string)
|
||||||
|
|
||||||
|
def add_user_got_achievement(self, join: UserGotAchievement):
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {join.insert_string}")
|
||||||
|
self._context.cursor.execute(join.insert_string)
|
||||||
|
|
||||||
|
def delete_user_got_achievement(self, join: UserGotAchievement):
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {join.delete_string}")
|
||||||
|
self._context.cursor.execute(join.delete_string)
|
@ -5,12 +5,21 @@ from bot_data.model.server import Server
|
|||||||
|
|
||||||
class CacheService:
|
class CacheService:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._cached_server = List(Server)
|
self._cached_servers = List(Server)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cached_server(self) -> List[Server]:
|
def cached_server(self) -> List[Server]:
|
||||||
return self._cached_server
|
return self._cached_servers
|
||||||
|
|
||||||
@cached_server.setter
|
def add_server(self, server: Server):
|
||||||
def cached_server(self, value: List[Server]):
|
if self._cached_servers.where(lambda x: x.id == server.id).count() > 0:
|
||||||
self._cached_server = value
|
return
|
||||||
|
self._cached_servers.add(server)
|
||||||
|
|
||||||
|
def add_servers(self, servers: List[Server]):
|
||||||
|
new_ids = servers.select(lambda x: x.id)
|
||||||
|
for s in self._cached_servers:
|
||||||
|
if s.id in new_ids:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._cached_servers.extend(servers)
|
||||||
|
@ -26,7 +26,7 @@ class ServerRepositoryService(ServerRepositoryABC):
|
|||||||
for result in results:
|
for result in results:
|
||||||
servers.append(Server(result[1], result[2], result[3], id=result[0]))
|
servers.append(Server(result[1], result[2], result[3], id=result[0]))
|
||||||
|
|
||||||
self._cache.cached_server = List(Server, servers)
|
self._cache.add_servers(servers)
|
||||||
return servers
|
return servers
|
||||||
|
|
||||||
def get_filtered_servers(self, criteria: ServerSelectCriteria) -> FilteredResult:
|
def get_filtered_servers(self, criteria: ServerSelectCriteria) -> FilteredResult:
|
||||||
@ -56,13 +56,14 @@ class ServerRepositoryService(ServerRepositoryABC):
|
|||||||
|
|
||||||
def get_server_by_id(self, server_id: int) -> Server:
|
def get_server_by_id(self, server_id: int) -> Server:
|
||||||
cs = self._cache.cached_server.where(lambda x: x.id == server_id).single_or_default()
|
cs = self._cache.cached_server.where(lambda x: x.id == server_id).single_or_default()
|
||||||
|
|
||||||
if cs is not None:
|
if cs is not None:
|
||||||
return cs
|
return cs
|
||||||
|
|
||||||
self._logger.trace(__name__, f"Send SQL command: {Server.get_select_by_id_string(server_id)}")
|
self._logger.trace(__name__, f"Send SQL command: {Server.get_select_by_id_string(server_id)}")
|
||||||
result = self._context.select(Server.get_select_by_id_string(server_id))[0]
|
result = self._context.select(Server.get_select_by_id_string(server_id))[0]
|
||||||
server = Server(result[1], result[2], result[3], id=result[0])
|
server = Server(result[1], result[2], result[3], id=result[0])
|
||||||
self._cache.cached_server.add(server)
|
self._cache.add_server(server)
|
||||||
return server
|
return server
|
||||||
|
|
||||||
def get_server_by_discord_id(self, discord_id: int) -> Server:
|
def get_server_by_discord_id(self, discord_id: int) -> Server:
|
||||||
|
@ -27,9 +27,11 @@ class UserRepositoryService(UserRepositoryABC):
|
|||||||
return User(
|
return User(
|
||||||
result[1],
|
result[1],
|
||||||
result[2],
|
result[2],
|
||||||
self._servers.get_server_by_id(result[3]),
|
result[3],
|
||||||
result[4],
|
result[4],
|
||||||
result[5],
|
self._servers.get_server_by_id(result[5]),
|
||||||
|
result[6],
|
||||||
|
result[7],
|
||||||
id=result[0],
|
id=result[0],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
67
kdb-bot/src/bot_graphql/filter/achievement_filter.py
Normal file
67
kdb-bot/src/bot_graphql/filter/achievement_filter.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
from cpl_query.extension import List
|
||||||
|
|
||||||
|
from bot_data.model.user import User
|
||||||
|
from bot_graphql.abc.filter_abc import FilterABC
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementFilter(FilterABC):
|
||||||
|
def __init__(self):
|
||||||
|
FilterABC.__init__(self)
|
||||||
|
|
||||||
|
self._id = None
|
||||||
|
self._name = None
|
||||||
|
self._description = None
|
||||||
|
self._attribute = None
|
||||||
|
self._operator = None
|
||||||
|
self._value = None
|
||||||
|
self._server = None
|
||||||
|
|
||||||
|
def from_dict(self, values: dict):
|
||||||
|
if "id" in values:
|
||||||
|
self._id = int(values["id"])
|
||||||
|
|
||||||
|
if "name" in values:
|
||||||
|
self._name = values["name"]
|
||||||
|
|
||||||
|
if "description" in values:
|
||||||
|
self._description = values["description"]
|
||||||
|
|
||||||
|
if "attribute" in values:
|
||||||
|
self._attribute = values["attribute"]
|
||||||
|
|
||||||
|
if "operator" in values:
|
||||||
|
self._operator = values["operator"]
|
||||||
|
|
||||||
|
if "value" in values:
|
||||||
|
self._value = values["value"]
|
||||||
|
|
||||||
|
if "server" in values:
|
||||||
|
from bot_graphql.filter.server_filter import ServerFilter
|
||||||
|
|
||||||
|
self._server: ServerFilter = self._services.get_service(ServerFilter)
|
||||||
|
self._server.from_dict(values["server"])
|
||||||
|
|
||||||
|
def filter(self, query: List[User]) -> List[User]:
|
||||||
|
if self._id is not None:
|
||||||
|
query = query.where(lambda x: x.id == self._id)
|
||||||
|
|
||||||
|
if self._name is not None:
|
||||||
|
query = query.where(lambda x: x.name == self._name or self._name in x.name)
|
||||||
|
|
||||||
|
if self._description is not None:
|
||||||
|
query = query.where(lambda x: x.description == self._description or self._description in x.description)
|
||||||
|
|
||||||
|
if self._attribute is not None:
|
||||||
|
query = query.where(lambda x: x.attribute == self._attribute or self._attribute in x.attribute)
|
||||||
|
|
||||||
|
if self._operator is not None:
|
||||||
|
query = query.where(lambda x: x.operator == self._operator)
|
||||||
|
|
||||||
|
if self._value is not None:
|
||||||
|
query = query.where(lambda x: x.value == self._value)
|
||||||
|
|
||||||
|
if self._server is not None:
|
||||||
|
servers = self._server.filter(query.select(lambda x: x.server)).select(lambda x: x.id)
|
||||||
|
query = query.where(lambda x: x.server.id in servers)
|
||||||
|
|
||||||
|
return query
|
@ -8,6 +8,7 @@ from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
|||||||
from bot_data.service.seeder_service import SeederService
|
from bot_data.service.seeder_service import SeederService
|
||||||
from bot_graphql.abc.filter_abc import FilterABC
|
from bot_graphql.abc.filter_abc import FilterABC
|
||||||
from bot_graphql.abc.query_abc import QueryABC
|
from bot_graphql.abc.query_abc import QueryABC
|
||||||
|
from bot_graphql.filter.achievement_filter import AchievementFilter
|
||||||
from bot_graphql.filter.auto_role_filter import AutoRoleFilter
|
from bot_graphql.filter.auto_role_filter import AutoRoleFilter
|
||||||
from bot_graphql.filter.auto_role_rule_filter import AutoRoleRuleFilter
|
from bot_graphql.filter.auto_role_rule_filter import AutoRoleRuleFilter
|
||||||
from bot_graphql.filter.client_filter import ClientFilter
|
from bot_graphql.filter.client_filter import ClientFilter
|
||||||
@ -19,17 +20,22 @@ from bot_graphql.filter.user_joined_server_filter import UserJoinedServerFilter
|
|||||||
from bot_graphql.filter.user_joined_voice_channel_filter import UserJoinedVoiceChannelFilter
|
from bot_graphql.filter.user_joined_voice_channel_filter import UserJoinedVoiceChannelFilter
|
||||||
from bot_graphql.graphql_service import GraphQLService
|
from bot_graphql.graphql_service import GraphQLService
|
||||||
from bot_graphql.mutation import Mutation
|
from bot_graphql.mutation import Mutation
|
||||||
|
from bot_graphql.mutations.achievement_mutation import AchievementMutation
|
||||||
from bot_graphql.mutations.auto_role_mutation import AutoRoleMutation
|
from bot_graphql.mutations.auto_role_mutation import AutoRoleMutation
|
||||||
from bot_graphql.mutations.auto_role_rule_mutation import AutoRoleRuleMutation
|
from bot_graphql.mutations.auto_role_rule_mutation import AutoRoleRuleMutation
|
||||||
from bot_graphql.mutations.level_mutation import LevelMutation
|
from bot_graphql.mutations.level_mutation import LevelMutation
|
||||||
from bot_graphql.mutations.user_joined_game_server_mutation import UserJoinedGameServerMutation
|
from bot_graphql.mutations.user_joined_game_server_mutation import UserJoinedGameServerMutation
|
||||||
from bot_graphql.mutations.user_mutation import UserMutation
|
from bot_graphql.mutations.user_mutation import UserMutation
|
||||||
|
from bot_graphql.queries.achievement_attribute_query import AchievementAttributeQuery
|
||||||
|
from bot_graphql.queries.achievement_history_query import AchievementHistoryQuery
|
||||||
|
from bot_graphql.queries.achievement_query import AchievementQuery
|
||||||
from bot_graphql.queries.auto_role_history_query import AutoRoleHistoryQuery
|
from bot_graphql.queries.auto_role_history_query import AutoRoleHistoryQuery
|
||||||
from bot_graphql.queries.auto_role_query import AutoRoleQuery
|
from bot_graphql.queries.auto_role_query import AutoRoleQuery
|
||||||
from bot_graphql.queries.auto_role_rule_history_query import AutoRoleRuleHistoryQuery
|
from bot_graphql.queries.auto_role_rule_history_query import AutoRoleRuleHistoryQuery
|
||||||
from bot_graphql.queries.auto_role_rule_query import AutoRoleRuleQuery
|
from bot_graphql.queries.auto_role_rule_query import AutoRoleRuleQuery
|
||||||
from bot_graphql.queries.client_history_query import ClientHistoryQuery
|
from bot_graphql.queries.client_history_query import ClientHistoryQuery
|
||||||
from bot_graphql.queries.client_query import ClientQuery
|
from bot_graphql.queries.client_query import ClientQuery
|
||||||
|
from bot_graphql.queries.game_server_query import GameServerQuery
|
||||||
from bot_graphql.queries.known_user_history_query import KnownUserHistoryQuery
|
from bot_graphql.queries.known_user_history_query import KnownUserHistoryQuery
|
||||||
from bot_graphql.queries.known_user_query import KnownUserQuery
|
from bot_graphql.queries.known_user_query import KnownUserQuery
|
||||||
from bot_graphql.queries.level_history_query import LevelHistoryQuery
|
from bot_graphql.queries.level_history_query import LevelHistoryQuery
|
||||||
@ -62,6 +68,9 @@ class GraphQLModule(ModuleABC):
|
|||||||
services.add_singleton(Mutation)
|
services.add_singleton(Mutation)
|
||||||
|
|
||||||
# queries
|
# queries
|
||||||
|
services.add_transient(QueryABC, AchievementAttributeQuery)
|
||||||
|
services.add_transient(QueryABC, AchievementQuery)
|
||||||
|
services.add_transient(QueryABC, AchievementHistoryQuery)
|
||||||
services.add_transient(QueryABC, AutoRoleHistoryQuery)
|
services.add_transient(QueryABC, AutoRoleHistoryQuery)
|
||||||
services.add_transient(QueryABC, AutoRoleQuery)
|
services.add_transient(QueryABC, AutoRoleQuery)
|
||||||
services.add_transient(QueryABC, AutoRoleRuleHistoryQuery)
|
services.add_transient(QueryABC, AutoRoleRuleHistoryQuery)
|
||||||
@ -74,6 +83,7 @@ class GraphQLModule(ModuleABC):
|
|||||||
services.add_transient(QueryABC, LevelQuery)
|
services.add_transient(QueryABC, LevelQuery)
|
||||||
services.add_transient(QueryABC, ServerHistoryQuery)
|
services.add_transient(QueryABC, ServerHistoryQuery)
|
||||||
services.add_transient(QueryABC, ServerQuery)
|
services.add_transient(QueryABC, ServerQuery)
|
||||||
|
services.add_transient(QueryABC, GameServerQuery)
|
||||||
services.add_transient(QueryABC, UserHistoryQuery)
|
services.add_transient(QueryABC, UserHistoryQuery)
|
||||||
services.add_transient(QueryABC, UserQuery)
|
services.add_transient(QueryABC, UserQuery)
|
||||||
services.add_transient(QueryABC, UserJoinedServerHistoryQuery)
|
services.add_transient(QueryABC, UserJoinedServerHistoryQuery)
|
||||||
@ -90,6 +100,7 @@ class GraphQLModule(ModuleABC):
|
|||||||
services.add_transient(FilterABC, LevelFilter)
|
services.add_transient(FilterABC, LevelFilter)
|
||||||
services.add_transient(FilterABC, ServerFilter)
|
services.add_transient(FilterABC, ServerFilter)
|
||||||
services.add_transient(FilterABC, UserFilter)
|
services.add_transient(FilterABC, UserFilter)
|
||||||
|
services.add_transient(FilterABC, AchievementFilter)
|
||||||
services.add_transient(FilterABC, UserJoinedServerFilter)
|
services.add_transient(FilterABC, UserJoinedServerFilter)
|
||||||
services.add_transient(FilterABC, UserJoinedVoiceChannelFilter)
|
services.add_transient(FilterABC, UserJoinedVoiceChannelFilter)
|
||||||
services.add_transient(FilterABC, UserJoinedGameServerFilter)
|
services.add_transient(FilterABC, UserJoinedGameServerFilter)
|
||||||
@ -99,6 +110,7 @@ class GraphQLModule(ModuleABC):
|
|||||||
services.add_transient(QueryABC, AutoRoleRuleMutation)
|
services.add_transient(QueryABC, AutoRoleRuleMutation)
|
||||||
services.add_transient(QueryABC, LevelMutation)
|
services.add_transient(QueryABC, LevelMutation)
|
||||||
services.add_transient(QueryABC, UserMutation)
|
services.add_transient(QueryABC, UserMutation)
|
||||||
|
services.add_transient(QueryABC, AchievementMutation)
|
||||||
services.add_transient(QueryABC, UserJoinedGameServerMutation)
|
services.add_transient(QueryABC, UserJoinedGameServerMutation)
|
||||||
|
|
||||||
services.add_transient(SeederService)
|
services.add_transient(SeederService)
|
||||||
|
64
kdb-bot/src/bot_graphql/model/achievement.gql
Normal file
64
kdb-bot/src/bot_graphql/model/achievement.gql
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
type AchievementAttribute {
|
||||||
|
name: String
|
||||||
|
type: String
|
||||||
|
|
||||||
|
createdAt: String
|
||||||
|
modifiedAt: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type Achievement implements TableWithHistoryQuery {
|
||||||
|
id: ID
|
||||||
|
name: String
|
||||||
|
description: String
|
||||||
|
attribute: String
|
||||||
|
operator: String
|
||||||
|
value: String
|
||||||
|
|
||||||
|
server: Server
|
||||||
|
|
||||||
|
createdAt: String
|
||||||
|
modifiedAt: String
|
||||||
|
|
||||||
|
history: [AchievementHistory]
|
||||||
|
}
|
||||||
|
|
||||||
|
type AchievementHistory implements HistoryTableQuery {
|
||||||
|
id: ID
|
||||||
|
name: String
|
||||||
|
description: String
|
||||||
|
attribute: String
|
||||||
|
operator: String
|
||||||
|
value: String
|
||||||
|
|
||||||
|
server: ID
|
||||||
|
|
||||||
|
deleted: Boolean
|
||||||
|
dateFrom: String
|
||||||
|
dateTo: String
|
||||||
|
}
|
||||||
|
|
||||||
|
input AchievementFilter {
|
||||||
|
id: ID
|
||||||
|
name: String
|
||||||
|
description: String
|
||||||
|
attribute: String
|
||||||
|
operator: String
|
||||||
|
value: String
|
||||||
|
server: ServerFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
type AchievementMutation {
|
||||||
|
createAchievement(input: AchievementInput!): Achievement
|
||||||
|
updateAchievement(input: AchievementInput!): Achievement
|
||||||
|
deleteAchievement(id: ID): Achievement
|
||||||
|
}
|
||||||
|
|
||||||
|
input AchievementInput {
|
||||||
|
id: ID
|
||||||
|
name: String
|
||||||
|
description: String
|
||||||
|
attribute: String
|
||||||
|
operator: String
|
||||||
|
value: String
|
||||||
|
serverId: ID
|
||||||
|
}
|
@ -4,4 +4,5 @@ type Mutation {
|
|||||||
level: LevelMutation
|
level: LevelMutation
|
||||||
user: UserMutation
|
user: UserMutation
|
||||||
userJoinedGameServer: UserJoinedGameServerMutation
|
userJoinedGameServer: UserJoinedGameServerMutation
|
||||||
|
achievement: AchievementMutation
|
||||||
}
|
}
|
@ -17,6 +17,9 @@ type Query {
|
|||||||
serverCount: Int
|
serverCount: Int
|
||||||
servers(filter: ServerFilter, page: Page, sort: Sort): [Server]
|
servers(filter: ServerFilter, page: Page, sort: Sort): [Server]
|
||||||
|
|
||||||
|
gameServerCount: Int
|
||||||
|
gameServers: [GameServer]
|
||||||
|
|
||||||
userJoinedServerCount: Int
|
userJoinedServerCount: Int
|
||||||
userJoinedServers(filter: UserJoinedServerFilter, page: Page, sort: Sort): [UserJoinedServer]
|
userJoinedServers(filter: UserJoinedServerFilter, page: Page, sort: Sort): [UserJoinedServer]
|
||||||
|
|
||||||
@ -29,5 +32,10 @@ type Query {
|
|||||||
userCount: Int
|
userCount: Int
|
||||||
users(filter: UserFilter, page: Page, sort: Sort): [User]
|
users(filter: UserFilter, page: Page, sort: Sort): [User]
|
||||||
|
|
||||||
|
achievementCount: Int
|
||||||
|
achievements(filter: AchievementFilter, page: Page, sort: Sort): [Achievement]
|
||||||
|
achievementAttributes: [AchievementAttribute]
|
||||||
|
achievementOperators: [String]
|
||||||
|
|
||||||
guilds(filter: GuildFilter): [Guild]
|
guilds(filter: GuildFilter): [Guild]
|
||||||
}
|
}
|
@ -1,3 +1,12 @@
|
|||||||
|
type GameServer {
|
||||||
|
id: ID
|
||||||
|
name: String
|
||||||
|
server: Server
|
||||||
|
|
||||||
|
createdAt: String
|
||||||
|
modifiedAt: String
|
||||||
|
}
|
||||||
|
|
||||||
type Server implements TableWithHistoryQuery {
|
type Server implements TableWithHistoryQuery {
|
||||||
id: ID
|
id: ID
|
||||||
discordId: String
|
discordId: String
|
||||||
@ -13,9 +22,15 @@ type Server implements TableWithHistoryQuery {
|
|||||||
levelCount: Int
|
levelCount: Int
|
||||||
levels(filter: LevelFilter, page: Page, sort: Sort): [Level]
|
levels(filter: LevelFilter, page: Page, sort: Sort): [Level]
|
||||||
|
|
||||||
|
gameServerCount: Int
|
||||||
|
gameServers: [GameServer]
|
||||||
|
|
||||||
userCount: Int
|
userCount: Int
|
||||||
users(filter: UserFilter, page: Page, sort: Sort): [User]
|
users(filter: UserFilter, page: Page, sort: Sort): [User]
|
||||||
|
|
||||||
|
achievementCount: Int
|
||||||
|
achievements(filter: AchievementFilter, page: Page, sort: Sort): [Achievement]
|
||||||
|
|
||||||
createdAt: String
|
createdAt: String
|
||||||
modifiedAt: String
|
modifiedAt: String
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ type User implements TableWithHistoryQuery {
|
|||||||
discordId: String
|
discordId: String
|
||||||
name: String
|
name: String
|
||||||
xp: Int
|
xp: Int
|
||||||
|
messageCount: Int
|
||||||
|
reactionCount: Int
|
||||||
ontime: Float
|
ontime: Float
|
||||||
level: Level
|
level: Level
|
||||||
|
|
||||||
@ -15,6 +17,9 @@ type User implements TableWithHistoryQuery {
|
|||||||
userJoinedGameServerCount: Int
|
userJoinedGameServerCount: Int
|
||||||
userJoinedGameServers(filter: UserJoinedGameServerFilter, page: Page, sort: Sort): [UserJoinedGameServer]
|
userJoinedGameServers(filter: UserJoinedGameServerFilter, page: Page, sort: Sort): [UserJoinedGameServer]
|
||||||
|
|
||||||
|
achievementCount: Int
|
||||||
|
achievements(filter: AchievementFilter, page: Page, sort: Sort): [Achievement]
|
||||||
|
|
||||||
server: Server
|
server: Server
|
||||||
leftServer: Boolean
|
leftServer: Boolean
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from ariadne import MutationType
|
from ariadne import MutationType
|
||||||
|
|
||||||
from bot_data.model.user_joined_game_server import UserJoinedGameServer
|
from bot_graphql.mutations.achievement_mutation import AchievementMutation
|
||||||
from bot_graphql.mutations.auto_role_mutation import AutoRoleMutation
|
from bot_graphql.mutations.auto_role_mutation import AutoRoleMutation
|
||||||
from bot_graphql.mutations.auto_role_rule_mutation import AutoRoleRuleMutation
|
from bot_graphql.mutations.auto_role_rule_mutation import AutoRoleRuleMutation
|
||||||
from bot_graphql.mutations.level_mutation import LevelMutation
|
from bot_graphql.mutations.level_mutation import LevelMutation
|
||||||
@ -15,6 +15,7 @@ class Mutation(MutationType):
|
|||||||
auto_role_rule_mutation: AutoRoleRuleMutation,
|
auto_role_rule_mutation: AutoRoleRuleMutation,
|
||||||
level_mutation: LevelMutation,
|
level_mutation: LevelMutation,
|
||||||
user_mutation: UserMutation,
|
user_mutation: UserMutation,
|
||||||
|
achievement_mutation: AchievementMutation,
|
||||||
user_joined_game_server: UserJoinedGameServerMutation,
|
user_joined_game_server: UserJoinedGameServerMutation,
|
||||||
):
|
):
|
||||||
MutationType.__init__(self)
|
MutationType.__init__(self)
|
||||||
@ -23,4 +24,5 @@ class Mutation(MutationType):
|
|||||||
self.set_field("autoRoleRule", lambda *_: auto_role_rule_mutation)
|
self.set_field("autoRoleRule", lambda *_: auto_role_rule_mutation)
|
||||||
self.set_field("level", lambda *_: level_mutation)
|
self.set_field("level", lambda *_: level_mutation)
|
||||||
self.set_field("user", lambda *_: user_mutation)
|
self.set_field("user", lambda *_: user_mutation)
|
||||||
|
self.set_field("achievement", lambda *_: achievement_mutation)
|
||||||
self.set_field("userJoinedGameServer", lambda *_: user_joined_game_server)
|
self.set_field("userJoinedGameServer", lambda *_: user_joined_game_server)
|
||||||
|
87
kdb-bot/src/bot_graphql/mutations/achievement_mutation.py
Normal file
87
kdb-bot/src/bot_graphql/mutations/achievement_mutation.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
from cpl_core.database.context import DatabaseContextABC
|
||||||
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
|
|
||||||
|
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
|
||||||
|
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||||
|
from bot_data.model.achievement import Achievement
|
||||||
|
from bot_data.model.user_role_enum import UserRoleEnum
|
||||||
|
from bot_graphql.abc.query_abc import QueryABC
|
||||||
|
from modules.permission.service.permission_service import PermissionService
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementMutation(QueryABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
servers: ServerRepositoryABC,
|
||||||
|
achievements: AchievementRepositoryABC,
|
||||||
|
bot: DiscordBotServiceABC,
|
||||||
|
db: DatabaseContextABC,
|
||||||
|
permissions: PermissionService,
|
||||||
|
):
|
||||||
|
QueryABC.__init__(self, "AchievementMutation")
|
||||||
|
|
||||||
|
self._servers = servers
|
||||||
|
self._achievements = achievements
|
||||||
|
self._bot = bot
|
||||||
|
self._db = db
|
||||||
|
self._permissions = permissions
|
||||||
|
|
||||||
|
self.set_field("createAchievement", self.resolve_create_achievement)
|
||||||
|
self.set_field("updateAchievement", self.resolve_update_achievement)
|
||||||
|
self.set_field("deleteAchievement", self.resolve_delete_achievement)
|
||||||
|
|
||||||
|
def resolve_create_achievement(self, *_, input: dict):
|
||||||
|
server = self._servers.get_server_by_id(input["serverId"])
|
||||||
|
self._can_user_mutate_data(server, UserRoleEnum.admin)
|
||||||
|
|
||||||
|
achievement = Achievement(
|
||||||
|
input["name"],
|
||||||
|
input["description"],
|
||||||
|
input["attribute"],
|
||||||
|
input["operator"],
|
||||||
|
input["value"],
|
||||||
|
server,
|
||||||
|
)
|
||||||
|
self._achievements.add_achievement(achievement)
|
||||||
|
self._db.save_changes()
|
||||||
|
|
||||||
|
def get_new_achievement(a: Achievement):
|
||||||
|
return (
|
||||||
|
a.name == achievement.name
|
||||||
|
and a.description == achievement.description
|
||||||
|
and a.attribute == achievement.attribute
|
||||||
|
and a.operator == achievement.operator
|
||||||
|
and a.value == achievement.value
|
||||||
|
and a.server.id == server.id
|
||||||
|
)
|
||||||
|
|
||||||
|
return self._achievements.get_achievements_by_server_id(achievement.server.id).where(get_new_achievement).last()
|
||||||
|
|
||||||
|
def resolve_update_achievement(self, *_, input: dict):
|
||||||
|
achievement = self._achievements.get_achievement_by_id(input["id"])
|
||||||
|
self._can_user_mutate_data(achievement.server, UserRoleEnum.moderator)
|
||||||
|
|
||||||
|
achievement.name = input["name"] if "name" in input else achievement.name
|
||||||
|
achievement.description = input["description"] if "description" in input else achievement.description
|
||||||
|
achievement.attribute = input["attribute"] if "attribute" in input else achievement.attribute
|
||||||
|
achievement.operator = input["operator"] if "operator" in input else achievement.operator
|
||||||
|
achievement.value = input["value"] if "value" in input else achievement.value
|
||||||
|
|
||||||
|
self._achievements.update_achievement(achievement)
|
||||||
|
self._db.save_changes()
|
||||||
|
|
||||||
|
achievement = self._achievements.get_achievement_by_id(input["id"])
|
||||||
|
return achievement
|
||||||
|
|
||||||
|
def resolve_delete_achievement(self, *_, id: int):
|
||||||
|
achievement = self._achievements.get_achievement_by_id(id)
|
||||||
|
self._can_user_mutate_data(achievement.server, UserRoleEnum.admin)
|
||||||
|
|
||||||
|
joins = self._achievements.get_user_got_achievements_by_achievement_id(id)
|
||||||
|
for join in joins:
|
||||||
|
self._achievements.delete_user_got_achievement(join)
|
||||||
|
|
||||||
|
self._achievements.delete_achievement(achievement)
|
||||||
|
self._db.save_changes()
|
||||||
|
|
||||||
|
return achievement
|
@ -50,6 +50,7 @@ class LevelMutation(QueryABC):
|
|||||||
and l.color == level.color
|
and l.color == level.color
|
||||||
and l.min_xp == level.min_xp
|
and l.min_xp == level.min_xp
|
||||||
and l.permissions == level.permissions
|
and l.permissions == level.permissions
|
||||||
|
and l.server.id == server.id
|
||||||
)
|
)
|
||||||
|
|
||||||
self._bot.loop.create_task(self._level_seeder.seed())
|
self._bot.loop.create_task(self._level_seeder.seed())
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
from bot_graphql.abc.data_query_abc import DataQueryABC
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementAttributeQuery(DataQueryABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
):
|
||||||
|
DataQueryABC.__init__(self, "AchievementAttribute")
|
||||||
|
|
||||||
|
self.set_field("name", lambda x, *_: x.name)
|
||||||
|
self.set_field("type", lambda x, *_: x.type)
|
14
kdb-bot/src/bot_graphql/queries/achievement_history_query.py
Normal file
14
kdb-bot/src/bot_graphql/queries/achievement_history_query.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from bot_graphql.abc.history_query_abc import HistoryQueryABC
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementHistoryQuery(HistoryQueryABC):
|
||||||
|
def __init__(self):
|
||||||
|
HistoryQueryABC.__init__(self, "Achievement")
|
||||||
|
|
||||||
|
self.set_field("id", lambda x, *_: x.id)
|
||||||
|
self.set_field("name", lambda x, *_: x.name)
|
||||||
|
self.set_field("description", lambda x, *_: x.description)
|
||||||
|
self.set_field("attribute", lambda x, *_: x.attribute)
|
||||||
|
self.set_field("operator", lambda x, *_: x.operator)
|
||||||
|
self.set_field("value", lambda x, *_: x.value)
|
||||||
|
self.set_field("server", lambda x, *_: x.server)
|
20
kdb-bot/src/bot_graphql/queries/achievement_query.py
Normal file
20
kdb-bot/src/bot_graphql/queries/achievement_query.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from cpl_core.database.context import DatabaseContextABC
|
||||||
|
|
||||||
|
from bot_data.model.achievement_history import AchievementHistory
|
||||||
|
from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementQuery(DataQueryWithHistoryABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
db: DatabaseContextABC,
|
||||||
|
):
|
||||||
|
DataQueryWithHistoryABC.__init__(self, "Achievement", "AchievementsHistory", AchievementHistory, db)
|
||||||
|
|
||||||
|
self.set_field("id", lambda x, *_: x.id)
|
||||||
|
self.set_field("name", lambda x, *_: x.name)
|
||||||
|
self.set_field("description", lambda x, *_: x.description)
|
||||||
|
self.set_field("attribute", lambda x, *_: x.attribute)
|
||||||
|
self.set_field("operator", lambda x, *_: x.operator)
|
||||||
|
self.set_field("value", lambda x, *_: x.value)
|
||||||
|
self.set_field("server", lambda x, *_: x.server)
|
10
kdb-bot/src/bot_graphql/queries/game_server_query.py
Normal file
10
kdb-bot/src/bot_graphql/queries/game_server_query.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from bot_graphql.abc.data_query_abc import DataQueryABC
|
||||||
|
|
||||||
|
|
||||||
|
class GameServerQuery(DataQueryABC):
|
||||||
|
def __init__(self):
|
||||||
|
DataQueryABC.__init__(self, "GameServer")
|
||||||
|
|
||||||
|
self.set_field("id", lambda x, *_: x.id)
|
||||||
|
self.set_field("name", lambda x, *_: x.name)
|
||||||
|
self.set_field("server", lambda x, *_: x.server)
|
@ -1,16 +1,18 @@
|
|||||||
from cpl_core.database.context import DatabaseContextABC
|
from cpl_core.database.context import DatabaseContextABC
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
|
|
||||||
|
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
|
||||||
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
|
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
|
||||||
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
||||||
|
from bot_data.abc.game_server_repository_abc import GameServerRepositoryABC
|
||||||
from bot_data.abc.level_repository_abc import LevelRepositoryABC
|
from bot_data.abc.level_repository_abc import LevelRepositoryABC
|
||||||
from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
|
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_joined_voice_channel_repository_abc import UserJoinedVoiceChannelRepositoryABC
|
||||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||||
from bot_data.model.server import Server
|
from bot_data.model.server import Server
|
||||||
from bot_data.model.server_history import ServerHistory
|
from bot_data.model.server_history import ServerHistory
|
||||||
from bot_graphql.abc.data_query_abc import DataQueryABC
|
|
||||||
from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC
|
from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC
|
||||||
|
from bot_graphql.filter.achievement_filter import AchievementFilter
|
||||||
from bot_graphql.filter.auto_role_filter import AutoRoleFilter
|
from bot_graphql.filter.auto_role_filter import AutoRoleFilter
|
||||||
from bot_graphql.filter.client_filter import ClientFilter
|
from bot_graphql.filter.client_filter import ClientFilter
|
||||||
from bot_graphql.filter.level_filter import LevelFilter
|
from bot_graphql.filter.level_filter import LevelFilter
|
||||||
@ -25,9 +27,11 @@ class ServerQuery(DataQueryWithHistoryABC):
|
|||||||
auto_roles: AutoRoleRepositoryABC,
|
auto_roles: AutoRoleRepositoryABC,
|
||||||
clients: ClientRepositoryABC,
|
clients: ClientRepositoryABC,
|
||||||
levels: LevelRepositoryABC,
|
levels: LevelRepositoryABC,
|
||||||
|
game_servers: GameServerRepositoryABC,
|
||||||
users: UserRepositoryABC,
|
users: UserRepositoryABC,
|
||||||
ujs: UserJoinedServerRepositoryABC,
|
ujs: UserJoinedServerRepositoryABC,
|
||||||
ujvs: UserJoinedVoiceChannelRepositoryABC,
|
ujvs: UserJoinedVoiceChannelRepositoryABC,
|
||||||
|
achievements: AchievementRepositoryABC,
|
||||||
):
|
):
|
||||||
DataQueryWithHistoryABC.__init__(self, "Server", "ServersHistory", ServerHistory, db)
|
DataQueryWithHistoryABC.__init__(self, "Server", "ServersHistory", ServerHistory, db)
|
||||||
|
|
||||||
@ -54,6 +58,10 @@ class ServerQuery(DataQueryWithHistoryABC):
|
|||||||
)
|
)
|
||||||
self.add_collection("level", lambda server, *_: self._levels.get_levels_by_server_id(server.id), LevelFilter)
|
self.add_collection("level", lambda server, *_: self._levels.get_levels_by_server_id(server.id), LevelFilter)
|
||||||
self.add_collection("user", lambda server, *_: self._users.get_users_by_server_id(server.id), UserFilter)
|
self.add_collection("user", lambda server, *_: self._users.get_users_by_server_id(server.id), UserFilter)
|
||||||
|
self.add_collection("gameServer", lambda server, *_: game_servers.get_game_servers_by_server_id(server.id))
|
||||||
|
self.add_collection(
|
||||||
|
"achievement", lambda server, *_: achievements.get_achievements_by_server_id(server.id), AchievementFilter
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_id(server: Server, *_):
|
def resolve_id(server: Server, *_):
|
||||||
|
@ -2,12 +2,14 @@ from cpl_core.database.context import DatabaseContextABC
|
|||||||
from cpl_discord.service import DiscordBotServiceABC
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
|
|
||||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
||||||
|
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
|
||||||
from bot_data.abc.user_joined_game_server_repository_abc import UserJoinedGameServerRepositoryABC
|
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_server_repository_abc import UserJoinedServerRepositoryABC
|
||||||
from bot_data.abc.user_joined_voice_channel_repository_abc import UserJoinedVoiceChannelRepositoryABC
|
from bot_data.abc.user_joined_voice_channel_repository_abc import UserJoinedVoiceChannelRepositoryABC
|
||||||
from bot_data.model.user import User
|
from bot_data.model.user import User
|
||||||
from bot_data.model.user_history import UserHistory
|
from bot_data.model.user_history import UserHistory
|
||||||
from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC
|
from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC
|
||||||
|
from bot_graphql.filter.achievement_filter import AchievementFilter
|
||||||
from bot_graphql.filter.user_joined_game_server_filter import UserJoinedGameServerFilter
|
from bot_graphql.filter.user_joined_game_server_filter import UserJoinedGameServerFilter
|
||||||
from bot_graphql.filter.user_joined_server_filter import UserJoinedServerFilter
|
from bot_graphql.filter.user_joined_server_filter import UserJoinedServerFilter
|
||||||
from bot_graphql.filter.user_joined_voice_channel_filter import UserJoinedVoiceChannelFilter
|
from bot_graphql.filter.user_joined_voice_channel_filter import UserJoinedVoiceChannelFilter
|
||||||
@ -26,6 +28,7 @@ class UserQuery(DataQueryWithHistoryABC):
|
|||||||
ujvs: UserJoinedVoiceChannelRepositoryABC,
|
ujvs: UserJoinedVoiceChannelRepositoryABC,
|
||||||
user_joined_game_server: UserJoinedGameServerRepositoryABC,
|
user_joined_game_server: UserJoinedGameServerRepositoryABC,
|
||||||
permissions: PermissionServiceABC,
|
permissions: PermissionServiceABC,
|
||||||
|
achievements: AchievementRepositoryABC,
|
||||||
):
|
):
|
||||||
DataQueryWithHistoryABC.__init__(self, "User", "UsersHistory", UserHistory, db)
|
DataQueryWithHistoryABC.__init__(self, "User", "UsersHistory", UserHistory, db)
|
||||||
|
|
||||||
@ -36,11 +39,14 @@ class UserQuery(DataQueryWithHistoryABC):
|
|||||||
self._ujs = ujs
|
self._ujs = ujs
|
||||||
self._ujvs = ujvs
|
self._ujvs = ujvs
|
||||||
self._permissions = permissions
|
self._permissions = permissions
|
||||||
|
self._achievements = achievements
|
||||||
|
|
||||||
self.set_field("id", self.resolve_id)
|
self.set_field("id", self.resolve_id)
|
||||||
self.set_field("discordId", self.resolve_discord_id)
|
self.set_field("discordId", self.resolve_discord_id)
|
||||||
self.set_field("name", self.resolve_name)
|
self.set_field("name", self.resolve_name)
|
||||||
self.set_field("xp", self.resolve_xp)
|
self.set_field("xp", self.resolve_xp)
|
||||||
|
self.set_field("messageCount", lambda x, *_: x.message_count)
|
||||||
|
self.set_field("reactionCount", lambda x, *_: x.reaction_count)
|
||||||
self.set_field("ontime", self.resolve_ontime)
|
self.set_field("ontime", self.resolve_ontime)
|
||||||
self.set_field("level", self.resolve_level)
|
self.set_field("level", self.resolve_level)
|
||||||
self.add_collection(
|
self.add_collection(
|
||||||
@ -58,6 +64,10 @@ class UserQuery(DataQueryWithHistoryABC):
|
|||||||
lambda user, *_: self._user_joined_game_server.get_user_joined_game_servers_by_user_id(user.id),
|
lambda user, *_: self._user_joined_game_server.get_user_joined_game_servers_by_user_id(user.id),
|
||||||
UserJoinedGameServerFilter,
|
UserJoinedGameServerFilter,
|
||||||
)
|
)
|
||||||
|
self.add_collection(
|
||||||
|
"achievement", lambda user, *_: achievements.get_achievements_by_user_id(user.id), AchievementFilter
|
||||||
|
)
|
||||||
|
|
||||||
self.set_field("server", self.resolve_server)
|
self.set_field("server", self.resolve_server)
|
||||||
self.set_field("leftServer", self.resolve_left_server)
|
self.set_field("leftServer", self.resolve_left_server)
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
from cpl_discord.service import DiscordBotServiceABC
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
|
|
||||||
|
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
|
||||||
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
|
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
|
||||||
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
||||||
|
from bot_data.abc.game_server_repository_abc import GameServerRepositoryABC
|
||||||
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
|
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
|
||||||
from bot_data.abc.level_repository_abc import LevelRepositoryABC
|
from bot_data.abc.level_repository_abc import LevelRepositoryABC
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||||
@ -10,6 +12,7 @@ from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepos
|
|||||||
from bot_data.abc.user_joined_voice_channel_repository_abc import UserJoinedVoiceChannelRepositoryABC
|
from bot_data.abc.user_joined_voice_channel_repository_abc import UserJoinedVoiceChannelRepositoryABC
|
||||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||||
from bot_graphql.abc.query_abc import QueryABC
|
from bot_graphql.abc.query_abc import QueryABC
|
||||||
|
from bot_graphql.filter.achievement_filter import AchievementFilter
|
||||||
from bot_graphql.filter.auto_role_filter import AutoRoleFilter
|
from bot_graphql.filter.auto_role_filter import AutoRoleFilter
|
||||||
from bot_graphql.filter.auto_role_rule_filter import AutoRoleRuleFilter
|
from bot_graphql.filter.auto_role_rule_filter import AutoRoleRuleFilter
|
||||||
from bot_graphql.filter.client_filter import ClientFilter
|
from bot_graphql.filter.client_filter import ClientFilter
|
||||||
@ -19,6 +22,7 @@ from bot_graphql.filter.user_filter import UserFilter
|
|||||||
from bot_graphql.filter.user_joined_game_server_filter import UserJoinedGameServerFilter
|
from bot_graphql.filter.user_joined_game_server_filter import UserJoinedGameServerFilter
|
||||||
from bot_graphql.filter.user_joined_server_filter import UserJoinedServerFilter
|
from bot_graphql.filter.user_joined_server_filter import UserJoinedServerFilter
|
||||||
from bot_graphql.filter.user_joined_voice_channel_filter import UserJoinedVoiceChannelFilter
|
from bot_graphql.filter.user_joined_voice_channel_filter import UserJoinedVoiceChannelFilter
|
||||||
|
from modules.achievements.achievement_service import AchievementService
|
||||||
|
|
||||||
|
|
||||||
class Query(QueryABC):
|
class Query(QueryABC):
|
||||||
@ -30,10 +34,13 @@ class Query(QueryABC):
|
|||||||
known_users: KnownUserRepositoryABC,
|
known_users: KnownUserRepositoryABC,
|
||||||
levels: LevelRepositoryABC,
|
levels: LevelRepositoryABC,
|
||||||
servers: ServerRepositoryABC,
|
servers: ServerRepositoryABC,
|
||||||
|
game_servers: GameServerRepositoryABC,
|
||||||
user_joined_servers: UserJoinedServerRepositoryABC,
|
user_joined_servers: UserJoinedServerRepositoryABC,
|
||||||
user_joined_voice_channels: UserJoinedVoiceChannelRepositoryABC,
|
user_joined_voice_channels: UserJoinedVoiceChannelRepositoryABC,
|
||||||
user_joined_game_server: UserJoinedGameServerRepositoryABC,
|
user_joined_game_server: UserJoinedGameServerRepositoryABC,
|
||||||
users: UserRepositoryABC,
|
users: UserRepositoryABC,
|
||||||
|
achievements: AchievementRepositoryABC,
|
||||||
|
achievement_service: AchievementService,
|
||||||
):
|
):
|
||||||
QueryABC.__init__(self, "Query")
|
QueryABC.__init__(self, "Query")
|
||||||
|
|
||||||
@ -45,6 +52,7 @@ class Query(QueryABC):
|
|||||||
self.add_collection("knownUser", lambda *_: known_users.get_users())
|
self.add_collection("knownUser", lambda *_: known_users.get_users())
|
||||||
self.add_collection("level", lambda *_: levels.get_levels(), LevelFilter)
|
self.add_collection("level", lambda *_: levels.get_levels(), LevelFilter)
|
||||||
self.add_collection("server", lambda *_: servers.get_servers(), ServerFilter)
|
self.add_collection("server", lambda *_: servers.get_servers(), ServerFilter)
|
||||||
|
self.add_collection("gameServer", lambda *_: game_servers.get_game_servers())
|
||||||
self.add_collection(
|
self.add_collection(
|
||||||
"userJoinedServer", lambda *_: user_joined_servers.get_user_joined_servers(), UserJoinedServerFilter
|
"userJoinedServer", lambda *_: user_joined_servers.get_user_joined_servers(), UserJoinedServerFilter
|
||||||
)
|
)
|
||||||
@ -59,8 +67,11 @@ class Query(QueryABC):
|
|||||||
UserJoinedGameServerFilter,
|
UserJoinedGameServerFilter,
|
||||||
)
|
)
|
||||||
self.add_collection("user", lambda *_: users.get_users(), UserFilter)
|
self.add_collection("user", lambda *_: users.get_users(), UserFilter)
|
||||||
|
self.add_collection("achievement", lambda *_: achievements.get_achievements(), AchievementFilter)
|
||||||
|
|
||||||
self.set_field("guilds", self._resolve_guilds)
|
self.set_field("guilds", self._resolve_guilds)
|
||||||
|
self.set_field("achievementAttributes", lambda x, *_: achievement_service.get_attributes())
|
||||||
|
self.set_field("achievementOperators", lambda x, *_: achievement_service.get_operators())
|
||||||
|
|
||||||
def _resolve_guilds(self, *_, filter=None):
|
def _resolve_guilds(self, *_, filter=None):
|
||||||
if filter is None or "id" not in filter:
|
if filter is None or "id" not in filter:
|
||||||
|
1
kdb-bot/src/modules/achievements/__init__.py
Normal file
1
kdb-bot/src/modules/achievements/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# imports
|
@ -0,0 +1,50 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
|
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
|
||||||
|
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
|
||||||
|
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
||||||
|
from bot_data.abc.game_server_repository_abc import GameServerRepositoryABC
|
||||||
|
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
|
||||||
|
from bot_data.abc.level_repository_abc import LevelRepositoryABC
|
||||||
|
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||||
|
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.user import User
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementAttributeResolver:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
auto_roles: AutoRoleRepositoryABC,
|
||||||
|
clients: ClientRepositoryABC,
|
||||||
|
known_users: KnownUserRepositoryABC,
|
||||||
|
levels: LevelRepositoryABC,
|
||||||
|
servers: ServerRepositoryABC,
|
||||||
|
game_servers: GameServerRepositoryABC,
|
||||||
|
user_joined_servers: UserJoinedServerRepositoryABC,
|
||||||
|
user_joined_voice_channels: UserJoinedVoiceChannelRepositoryABC,
|
||||||
|
user_joined_game_server: UserJoinedGameServerRepositoryABC,
|
||||||
|
users: UserRepositoryABC,
|
||||||
|
achievements: AchievementRepositoryABC,
|
||||||
|
):
|
||||||
|
self._auto_roles = auto_roles
|
||||||
|
self._clients = clients
|
||||||
|
self._known_users = known_users
|
||||||
|
self._levels = levels
|
||||||
|
self._servers = servers
|
||||||
|
self._game_servers = game_servers
|
||||||
|
self._user_joined_servers = user_joined_servers
|
||||||
|
self._user_joined_voice_channels = user_joined_voice_channels
|
||||||
|
self._user_joined_game_server = user_joined_game_server
|
||||||
|
self._users = users
|
||||||
|
self._achievements = achievements
|
||||||
|
|
||||||
|
def get_played_on_game_server(self, user: User) -> List[str]:
|
||||||
|
joins = self._user_joined_game_server.get_user_joined_game_servers_by_user_id(user.id)
|
||||||
|
return joins.select(lambda x: x.game_server.name)
|
||||||
|
|
||||||
|
def get_last_ontime_hours(self, user: User) -> int:
|
||||||
|
ujvs = self._user_joined_voice_channels.get_user_joined_voice_channels_by_user_id(user.id)
|
||||||
|
return int(str(ujvs.max(lambda join: (join.leaved_on - join.joined_on).total_seconds() / 3600)))
|
116
kdb-bot/src/modules/achievements/achievement_service.py
Normal file
116
kdb-bot/src/modules/achievements/achievement_service.py
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
from cpl_core.configuration import ConfigurationABC
|
||||||
|
from cpl_core.database.context import DatabaseContextABC
|
||||||
|
from cpl_core.logging import LoggerABC
|
||||||
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
|
from cpl_query.extension import List
|
||||||
|
from cpl_translation import TranslatePipe
|
||||||
|
|
||||||
|
from bot_core.configuration.server_settings import ServerSettings
|
||||||
|
from bot_core.service.message_service import MessageService
|
||||||
|
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
|
||||||
|
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||||
|
from bot_data.model.achievement import Achievement
|
||||||
|
from bot_data.model.user import User
|
||||||
|
from bot_data.model.user_got_achievement import UserGotAchievement
|
||||||
|
from modules.achievements.achievement_attribute_resolver import AchievementAttributeResolver
|
||||||
|
from modules.achievements.model.achievement_attribute import AchievementAttribute
|
||||||
|
from modules.base.configuration.base_server_settings import BaseServerSettings
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementService:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: ConfigurationABC,
|
||||||
|
logger: LoggerABC,
|
||||||
|
bot: DiscordBotServiceABC,
|
||||||
|
achievements: AchievementRepositoryABC,
|
||||||
|
users: UserRepositoryABC,
|
||||||
|
db: DatabaseContextABC,
|
||||||
|
message_service: MessageService,
|
||||||
|
resolver: AchievementAttributeResolver,
|
||||||
|
t: TranslatePipe,
|
||||||
|
):
|
||||||
|
self._config = config
|
||||||
|
self._logger = logger
|
||||||
|
self._bot = bot
|
||||||
|
self._achievements = achievements
|
||||||
|
self._users = users
|
||||||
|
self._db = db
|
||||||
|
self._message_service = message_service
|
||||||
|
self._t = t
|
||||||
|
|
||||||
|
self._attributes = List(AchievementAttribute)
|
||||||
|
|
||||||
|
self._attributes.extend(
|
||||||
|
[
|
||||||
|
AchievementAttribute("xp", lambda user: user.xp, "number"),
|
||||||
|
AchievementAttribute("message_count", lambda user: user.message_count, "number"),
|
||||||
|
AchievementAttribute("reaction_count", lambda user: user.reaction_count, "number"),
|
||||||
|
AchievementAttribute("ontime", lambda user: user.ontime, "number"),
|
||||||
|
AchievementAttribute("level", lambda user: user.level, "Level"),
|
||||||
|
# special cases
|
||||||
|
AchievementAttribute(
|
||||||
|
"played_on_game_server", lambda user: resolver.get_played_on_game_server(user), "GameServer"
|
||||||
|
),
|
||||||
|
AchievementAttribute(
|
||||||
|
"last_single_ontime_hours", lambda user: resolver.get_last_ontime_hours(user), "number"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self._operators = {
|
||||||
|
"==": lambda value, expected_value: value == expected_value,
|
||||||
|
"!=": lambda value, expected_value: value != expected_value,
|
||||||
|
"<=": lambda value, expected_value: value <= expected_value,
|
||||||
|
">=": lambda value, expected_value: value >= expected_value,
|
||||||
|
"<": lambda value, expected_value: value < expected_value,
|
||||||
|
">": lambda value, expected_value: value > expected_value,
|
||||||
|
"contains": lambda value, expected_value: expected_value in value,
|
||||||
|
}
|
||||||
|
|
||||||
|
def add_achievement_attribute(self, atr: AchievementAttribute):
|
||||||
|
self._attributes.add(atr)
|
||||||
|
|
||||||
|
def get_operators(self) -> list[str]:
|
||||||
|
return [x for x in self._operators.keys()]
|
||||||
|
|
||||||
|
def get_attributes(self) -> List[AchievementAttribute]:
|
||||||
|
return self._attributes
|
||||||
|
|
||||||
|
def _match(self, value: any, operator: str, expected_value: str) -> bool:
|
||||||
|
return self._operators[operator](str(value), expected_value)
|
||||||
|
|
||||||
|
def has_user_achievement_already(self, user: User, achievement: Achievement) -> bool:
|
||||||
|
user_achievements = self._achievements.get_achievements_by_user_id(user.id)
|
||||||
|
return user_achievements.where(lambda x: x.name == achievement.name).count() > 0
|
||||||
|
|
||||||
|
def has_user_achievement(self, user: User, achievement: Achievement) -> bool:
|
||||||
|
attribute: AchievementAttribute = self._attributes.where(lambda x: x.name == achievement.attribute).single()
|
||||||
|
return self._match(attribute.resolve(user), achievement.operator, achievement.value)
|
||||||
|
|
||||||
|
async def validate_achievements_for_user(self, user: User):
|
||||||
|
achievements = self._achievements.get_achievements_by_server_id(user.server.id)
|
||||||
|
for achievement in achievements:
|
||||||
|
if self.has_user_achievement_already(user, achievement) or not self.has_user_achievement(user, achievement):
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._achievements.add_user_got_achievement(UserGotAchievement(user, achievement, user.server))
|
||||||
|
self._db.save_changes()
|
||||||
|
self._give_user_xp(user)
|
||||||
|
await self._send_achievement_notification(user.server.discord_id, user.discord_id, achievement.name)
|
||||||
|
|
||||||
|
def _give_user_xp(self, user: User):
|
||||||
|
settings: BaseServerSettings = self._config.get_configuration(f"BaseServerSettings_{user.server.discord_id}")
|
||||||
|
user.xp += settings.xp_per_achievement
|
||||||
|
self._users.update_user(user)
|
||||||
|
self._db.save_changes()
|
||||||
|
|
||||||
|
async def _send_achievement_notification(self, guild_id: int, member_id: int, achievement_name: str):
|
||||||
|
member = self._bot.get_guild(guild_id).get_member(member_id)
|
||||||
|
|
||||||
|
settings: ServerSettings = self._config.get_configuration(f"ServerSettings_{guild_id}")
|
||||||
|
await self._message_service.send_channel_message(
|
||||||
|
self._bot.get_channel(settings.notification_chat_id),
|
||||||
|
self._t.transform("modules.achievements.got_new_achievement").format(member.mention, achievement_name),
|
||||||
|
is_persistent=True,
|
||||||
|
)
|
44
kdb-bot/src/modules/achievements/achievements.json
Normal file
44
kdb-bot/src/modules/achievements/achievements.json
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"ProjectSettings": {
|
||||||
|
"Name": "achievements",
|
||||||
|
"Version": {
|
||||||
|
"Major": "1",
|
||||||
|
"Minor": "1",
|
||||||
|
"Micro": "0"
|
||||||
|
},
|
||||||
|
"Author": "Sven Heidemann",
|
||||||
|
"AuthorEmail": "sven.heidemann@sh-edraft.de",
|
||||||
|
"Description": "Keksdose bot - achievements",
|
||||||
|
"LongDescription": "Discord bot for the Keksdose discord Server - achievements module",
|
||||||
|
"URL": "https://www.sh-edraft.de",
|
||||||
|
"CopyrightDate": "2023",
|
||||||
|
"CopyrightName": "sh-edraft.de",
|
||||||
|
"LicenseName": "MIT",
|
||||||
|
"LicenseDescription": "MIT, see LICENSE for more details.",
|
||||||
|
"Dependencies": [
|
||||||
|
"cpl-core>=2023.4.0.post2"
|
||||||
|
],
|
||||||
|
"DevDependencies": [
|
||||||
|
"cpl-cli>=2023.4.0.post3"
|
||||||
|
],
|
||||||
|
"PythonVersion": ">=3.10.4",
|
||||||
|
"PythonPath": {},
|
||||||
|
"Classifiers": []
|
||||||
|
},
|
||||||
|
"BuildSettings": {
|
||||||
|
"ProjectType": "library",
|
||||||
|
"SourcePath": "",
|
||||||
|
"OutputPath": "../../dist",
|
||||||
|
"Main": "achievements.main",
|
||||||
|
"EntryPoint": "achievements",
|
||||||
|
"IncludePackageData": false,
|
||||||
|
"Included": [],
|
||||||
|
"Excluded": [
|
||||||
|
"*/__pycache__",
|
||||||
|
"*/logs",
|
||||||
|
"*/tests"
|
||||||
|
],
|
||||||
|
"PackageData": {},
|
||||||
|
"ProjectReferences": []
|
||||||
|
}
|
||||||
|
}
|
28
kdb-bot/src/modules/achievements/achievements_module.py
Normal file
28
kdb-bot/src/modules/achievements/achievements_module.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
from cpl_core.configuration import ConfigurationABC
|
||||||
|
from cpl_core.dependency_injection import ServiceCollectionABC
|
||||||
|
from cpl_core.environment import ApplicationEnvironmentABC
|
||||||
|
from cpl_discord.discord_event_types_enum import DiscordEventTypesEnum
|
||||||
|
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 modules.achievements.achievement_attribute_resolver import AchievementAttributeResolver
|
||||||
|
from modules.achievements.achievement_service import AchievementService
|
||||||
|
from modules.achievements.commands.achievements_group import AchievementGroup
|
||||||
|
from modules.achievements.events.achievement_on_message_event import AchievementOnMessageEvent
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementsModule(ModuleABC):
|
||||||
|
def __init__(self, dc: DiscordCollectionABC):
|
||||||
|
ModuleABC.__init__(self, dc, FeatureFlagsEnum.auto_role_module)
|
||||||
|
|
||||||
|
def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
|
||||||
|
services.add_transient(AchievementAttributeResolver)
|
||||||
|
services.add_transient(AchievementService)
|
||||||
|
|
||||||
|
self._dc.add_command(AchievementGroup)
|
||||||
|
|
||||||
|
self._dc.add_event(DiscordEventTypesEnum.on_message.value, AchievementOnMessageEvent)
|
1
kdb-bot/src/modules/achievements/commands/__init__.py
Normal file
1
kdb-bot/src/modules/achievements/commands/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# imports
|
@ -0,0 +1,57 @@
|
|||||||
|
import discord
|
||||||
|
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.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.server_repository_abc import ServerRepositoryABC
|
||||||
|
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||||
|
from modules.achievements.achievement_service import AchievementService
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementGroup(DiscordCommandABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
logger: CommandLogger,
|
||||||
|
message_service: MessageServiceABC,
|
||||||
|
bot: DiscordBotServiceABC,
|
||||||
|
servers: ServerRepositoryABC,
|
||||||
|
users: UserRepositoryABC,
|
||||||
|
achievement_service: AchievementService,
|
||||||
|
translate: TranslatePipe,
|
||||||
|
):
|
||||||
|
DiscordCommandABC.__init__(self)
|
||||||
|
|
||||||
|
self._logger = logger
|
||||||
|
self._message_service = message_service
|
||||||
|
self._bot = bot
|
||||||
|
self._servers = servers
|
||||||
|
self._users = users
|
||||||
|
self._achievement_service = achievement_service
|
||||||
|
self._t = translate
|
||||||
|
|
||||||
|
@commands.hybrid_group()
|
||||||
|
@commands.guild_only()
|
||||||
|
async def achievement(self, ctx: Context):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@achievement.command()
|
||||||
|
@commands.guild_only()
|
||||||
|
@CommandChecks.check_is_ready()
|
||||||
|
@CommandChecks.check_is_member_moderator()
|
||||||
|
async def check(self, ctx: Context, member: discord.Member):
|
||||||
|
self._logger.debug(__name__, f"Received command achievement check {ctx}")
|
||||||
|
|
||||||
|
server = self._servers.get_server_by_discord_id(member.guild.id)
|
||||||
|
user = self._users.get_user_by_discord_id_and_server_id(member.id, server.id)
|
||||||
|
await self._message_service.send_ctx_msg(
|
||||||
|
ctx,
|
||||||
|
self._t.transform("modules.achievements.commands.check"),
|
||||||
|
)
|
||||||
|
await self._achievement_service.validate_achievements_for_user(user)
|
||||||
|
|
||||||
|
self._logger.trace(__name__, f"Finished command achievement check")
|
1
kdb-bot/src/modules/achievements/events/__init__.py
Normal file
1
kdb-bot/src/modules/achievements/events/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# imports
|
@ -0,0 +1,43 @@
|
|||||||
|
import discord
|
||||||
|
from cpl_core.database.context import DatabaseContextABC
|
||||||
|
from cpl_core.logging import LoggerABC
|
||||||
|
from cpl_discord.events import OnMessageABC
|
||||||
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
|
|
||||||
|
from bot_core.helper.event_checks import EventChecks
|
||||||
|
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||||
|
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||||
|
from modules.achievements.achievement_service import AchievementService
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementOnMessageEvent(OnMessageABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
logger: LoggerABC,
|
||||||
|
bot: DiscordBotServiceABC,
|
||||||
|
achievements: AchievementService,
|
||||||
|
db: DatabaseContextABC,
|
||||||
|
servers: ServerRepositoryABC,
|
||||||
|
users: UserRepositoryABC,
|
||||||
|
):
|
||||||
|
OnMessageABC.__init__(self)
|
||||||
|
|
||||||
|
self._logger = logger
|
||||||
|
self._bot = bot
|
||||||
|
self._achievements = achievements
|
||||||
|
self._db = db
|
||||||
|
self._servers = servers
|
||||||
|
self._users = users
|
||||||
|
|
||||||
|
@EventChecks.check_is_ready()
|
||||||
|
async def on_message(self, message: discord.Message):
|
||||||
|
if message.author.bot:
|
||||||
|
return
|
||||||
|
|
||||||
|
server = self._servers.get_server_by_discord_id(message.guild.id)
|
||||||
|
user = self._users.get_user_by_discord_id_and_server_id(message.author.id, server.id)
|
||||||
|
|
||||||
|
user.message_count += 1
|
||||||
|
self._db.save_changes()
|
||||||
|
|
||||||
|
await self._achievements.validate_achievements_for_user(user)
|
1
kdb-bot/src/modules/achievements/model/__init__.py
Normal file
1
kdb-bot/src/modules/achievements/model/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# imports
|
@ -0,0 +1,20 @@
|
|||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementAttribute:
|
||||||
|
# frontend type = TypeScript types
|
||||||
|
def __init__(self, name: str, resolver: Callable, frontend_type: str):
|
||||||
|
self._name = name
|
||||||
|
self._resolver = resolver
|
||||||
|
self._frontend_type = frontend_type
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> str:
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self) -> str:
|
||||||
|
return self._frontend_type
|
||||||
|
|
||||||
|
def resolve(self, *args, **kwargs):
|
||||||
|
return self._resolver(*args, **kwargs)
|
@ -16,6 +16,7 @@ class BaseServerSettings(ConfigurationModelABC):
|
|||||||
self._max_message_xp_per_hour: int = 0
|
self._max_message_xp_per_hour: int = 0
|
||||||
self._xp_per_ontime_hour: int = 0
|
self._xp_per_ontime_hour: int = 0
|
||||||
self._xp_per_event_participation: int = 0
|
self._xp_per_event_participation: int = 0
|
||||||
|
self._xp_per_achievement: int = 0
|
||||||
self._afk_channel_ids: List[int] = List(int)
|
self._afk_channel_ids: List[int] = List(int)
|
||||||
self._afk_command_channel_id: int = 0
|
self._afk_command_channel_id: int = 0
|
||||||
self._help_command_reference_url: str = ""
|
self._help_command_reference_url: str = ""
|
||||||
@ -51,6 +52,10 @@ class BaseServerSettings(ConfigurationModelABC):
|
|||||||
def xp_per_event_participation(self) -> int:
|
def xp_per_event_participation(self) -> int:
|
||||||
return self._xp_per_event_participation
|
return self._xp_per_event_participation
|
||||||
|
|
||||||
|
@property
|
||||||
|
def xp_per_achievement(self) -> int:
|
||||||
|
return self._xp_per_achievement
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def afk_channel_ids(self) -> List[int]:
|
def afk_channel_ids(self) -> List[int]:
|
||||||
return self._afk_channel_ids
|
return self._afk_channel_ids
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import traceback
|
|
||||||
|
|
||||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
|
||||||
from cpl_core.console import Console
|
|
||||||
|
|
||||||
|
|
||||||
class LevelServerSettings(ConfigurationModelABC):
|
|
||||||
def __init__(self):
|
|
||||||
ConfigurationModelABC.__init__(self)
|
|
||||||
|
|
||||||
self._id: int = 0
|
|
||||||
self._changed_level_notification_channel = 0
|
|
||||||
|
|
||||||
@property
|
|
||||||
def id(self) -> int:
|
|
||||||
return self._id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def changed_level_notification_channel(self) -> int:
|
|
||||||
return self._changed_level_notification_channel
|
|
||||||
|
|
||||||
def from_dict(self, settings: dict):
|
|
||||||
try:
|
|
||||||
self._id = int(settings["Id"])
|
|
||||||
self._changed_level_notification_channel = int(settings["ChangedLevelNotificationChannelId"])
|
|
||||||
except Exception as e:
|
|
||||||
Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
|
|
||||||
Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
|
|
@ -1,31 +0,0 @@
|
|||||||
import traceback
|
|
||||||
|
|
||||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
|
||||||
from cpl_core.console import Console
|
|
||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
from modules.level.configuration.level_server_settings import LevelServerSettings
|
|
||||||
|
|
||||||
|
|
||||||
class LevelSettings(ConfigurationModelABC):
|
|
||||||
def __init__(self):
|
|
||||||
ConfigurationModelABC.__init__(self)
|
|
||||||
|
|
||||||
self._servers: List[LevelServerSettings] = List()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def servers(self) -> List[LevelServerSettings]:
|
|
||||||
return self._servers
|
|
||||||
|
|
||||||
def from_dict(self, settings: dict):
|
|
||||||
try:
|
|
||||||
servers = List(LevelServerSettings)
|
|
||||||
for s in settings:
|
|
||||||
st = LevelServerSettings()
|
|
||||||
settings[s]["Id"] = s
|
|
||||||
st.from_dict(settings[s])
|
|
||||||
servers.append(st)
|
|
||||||
self._servers = servers
|
|
||||||
except Exception as e:
|
|
||||||
Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
|
|
||||||
Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
|
|
@ -6,13 +6,13 @@ from cpl_discord.container import Guild, Role, Member
|
|||||||
from cpl_discord.service import DiscordBotServiceABC
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
from cpl_translation import TranslatePipe
|
from cpl_translation import TranslatePipe
|
||||||
|
|
||||||
|
from bot_core.configuration.server_settings import ServerSettings
|
||||||
from bot_core.service.message_service import MessageService
|
from bot_core.service.message_service import MessageService
|
||||||
from bot_data.model.level import Level
|
from bot_data.model.level import Level
|
||||||
from bot_data.model.user import User
|
from bot_data.model.user import User
|
||||||
from bot_data.service.level_repository_service import LevelRepositoryService
|
from bot_data.service.level_repository_service import LevelRepositoryService
|
||||||
from bot_data.service.server_repository_service import ServerRepositoryService
|
from bot_data.service.server_repository_service import ServerRepositoryService
|
||||||
from bot_data.service.user_repository_service import UserRepositoryService
|
from bot_data.service.user_repository_service import UserRepositoryService
|
||||||
from modules.level.configuration.level_server_settings import LevelServerSettings
|
|
||||||
|
|
||||||
|
|
||||||
class LevelService:
|
class LevelService:
|
||||||
@ -75,9 +75,9 @@ class LevelService:
|
|||||||
self._logger.error(__name__, f"Adding role {level_role.name} to {member.name} failed!", e)
|
self._logger.error(__name__, f"Adding role {level_role.name} to {member.name} failed!", e)
|
||||||
|
|
||||||
if notification_needed:
|
if notification_needed:
|
||||||
level_settings: LevelServerSettings = self._config.get_configuration(f"LevelServerSettings_{guild.id}")
|
settings: ServerSettings = self._config.get_configuration(f"ServerSettings_{guild.id}")
|
||||||
await self._message_service.send_channel_message(
|
await self._message_service.send_channel_message(
|
||||||
self._bot.get_channel(level_settings.changed_level_notification_channel),
|
self._bot.get_channel(settings.notification_chat_id),
|
||||||
self._t.transform("modules.level.new_level_message").format(member.mention, level.name),
|
self._t.transform("modules.level.new_level_message").format(member.mention, level.name),
|
||||||
is_persistent=True,
|
is_persistent=True,
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "kdb-web",
|
"name": "kdb-web",
|
||||||
"version": "1.0.7",
|
"version": "1.0.dev268_achievements",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"update-version": "ts-node-esm update-version.ts",
|
"update-version": "ts-node-esm update-version.ts",
|
||||||
|
29
kdb-web/src/app/models/data/achievement.model.ts
Normal file
29
kdb-web/src/app/models/data/achievement.model.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { DataWithHistory } from "./data.model";
|
||||||
|
import { Server, ServerFilter } from "./server.model";
|
||||||
|
|
||||||
|
export interface AchievementAttribute {
|
||||||
|
name?: string;
|
||||||
|
type?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Achievement extends DataWithHistory {
|
||||||
|
id?: number;
|
||||||
|
name?: string;
|
||||||
|
description?: string;
|
||||||
|
attribute?: string | AchievementAttribute;
|
||||||
|
operator?: string;
|
||||||
|
value?: string;
|
||||||
|
server?: Server;
|
||||||
|
|
||||||
|
createdAt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AchievementFilter {
|
||||||
|
id?: number;
|
||||||
|
name?: string;
|
||||||
|
description?: string;
|
||||||
|
attribute?: string;
|
||||||
|
operator?: string;
|
||||||
|
value?: string;
|
||||||
|
server?: ServerFilter;
|
||||||
|
}
|
@ -4,6 +4,11 @@ import {Level} from "./level.model";
|
|||||||
import {Client} from "./client.model";
|
import {Client} from "./client.model";
|
||||||
import { AutoRole } from "./auto_role.model";
|
import { AutoRole } from "./auto_role.model";
|
||||||
|
|
||||||
|
export interface GameServer {
|
||||||
|
id?: number;
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Server extends Data {
|
export interface Server extends Data {
|
||||||
id?: number;
|
id?: number;
|
||||||
discordId?: String;
|
discordId?: String;
|
||||||
|
@ -4,12 +4,15 @@ import { Server, ServerFilter } from "./server.model";
|
|||||||
import { UserJoinedServer } from "./user_joined_server.model";
|
import { UserJoinedServer } from "./user_joined_server.model";
|
||||||
import { UserJoinedVoiceChannel } from "./user_joined_voice_channel.model";
|
import { UserJoinedVoiceChannel } from "./user_joined_voice_channel.model";
|
||||||
import { UserJoinedGameServer } from "./user_joined_game_server.model";
|
import { UserJoinedGameServer } from "./user_joined_game_server.model";
|
||||||
|
import { Achievement } from "./achievement.model";
|
||||||
|
|
||||||
export interface User extends DataWithHistory {
|
export interface User extends DataWithHistory {
|
||||||
id?: number;
|
id?: number;
|
||||||
discordId?: number;
|
discordId?: number;
|
||||||
name?: string;
|
name?: string;
|
||||||
xp?: number;
|
xp?: number;
|
||||||
|
message_count?: number;
|
||||||
|
reaction_count?: number;
|
||||||
ontime?: number;
|
ontime?: number;
|
||||||
level?: Level;
|
level?: Level;
|
||||||
server?: Server;
|
server?: Server;
|
||||||
@ -23,6 +26,9 @@ export interface User extends DataWithHistory {
|
|||||||
|
|
||||||
userJoinedGameServerCount?: number;
|
userJoinedGameServerCount?: number;
|
||||||
userJoinedGameServers?: UserJoinedGameServer[];
|
userJoinedGameServers?: UserJoinedGameServer[];
|
||||||
|
|
||||||
|
achievementCount?: number;
|
||||||
|
achievements?: Achievement[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserFilter {
|
export interface UserFilter {
|
||||||
|
@ -121,4 +121,48 @@ export class Mutations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
static createAchievement = `
|
||||||
|
mutation createAchievement($name: String, $description: String, $attribute: String, $operator: String, $value: String, $serverId: ID) {
|
||||||
|
achievement {
|
||||||
|
createAchievement(input: { name: $name, description: $description, attribute: $attribute, operator: $operator, value: $value, serverId: $serverId}) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
attribute
|
||||||
|
operator
|
||||||
|
value
|
||||||
|
server {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
static updateAchievement = `
|
||||||
|
mutation updateAchievement($id: ID, $name: String, $description: String, $attribute: String, $operator: String, $value: String) {
|
||||||
|
achievement {
|
||||||
|
updateAchievement(input: { id: $id, name: $name, description: $description, attribute: $attribute, operator: $operator, value: $value}) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
attribute
|
||||||
|
operator
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
static deleteAchievement = `
|
||||||
|
mutation deleteAchievement($id: ID) {
|
||||||
|
achievement {
|
||||||
|
deleteAchievement(id: $id) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,16 @@ export class Queries {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
static gameServerQuery = `
|
||||||
|
query GameServersList($serverId: ID) {
|
||||||
|
servers(filter: {id: $serverId}) {
|
||||||
|
gameServers {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
static levelQuery = `
|
static levelQuery = `
|
||||||
query LevelsList($serverId: ID, $filter: LevelFilter, $page: Page, $sort: Sort) {
|
query LevelsList($serverId: ID, $filter: LevelFilter, $page: Page, $sort: Sort) {
|
||||||
servers(filter: {id: $serverId}) {
|
servers(filter: {id: $serverId}) {
|
||||||
@ -90,6 +100,62 @@ export class Queries {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
static achievementTypeQuery = `
|
||||||
|
query AchievementType {
|
||||||
|
achievementOperators
|
||||||
|
achievementAttributes {
|
||||||
|
name
|
||||||
|
type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
static achievementQuery = `
|
||||||
|
query AchievementList($serverId: ID, $filter: AchievementFilter, $page: Page, $sort: Sort) {
|
||||||
|
servers(filter: {id: $serverId}) {
|
||||||
|
achievementCount
|
||||||
|
achievements(filter: $filter, page: $page, sort: $sort) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
attribute
|
||||||
|
operator
|
||||||
|
value
|
||||||
|
server {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
createdAt
|
||||||
|
modifiedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
static achievementWithHistoryQuery = `
|
||||||
|
query AchievementHistory($serverId: ID, $id: ID) {
|
||||||
|
servers(filter: {id: $serverId}) {
|
||||||
|
achievementCount
|
||||||
|
achievements(filter: {id: $id}) {
|
||||||
|
id
|
||||||
|
|
||||||
|
history {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
attribute
|
||||||
|
operator
|
||||||
|
value
|
||||||
|
server
|
||||||
|
deleted
|
||||||
|
dateFrom
|
||||||
|
dateTo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
static usersQuery = `
|
static usersQuery = `
|
||||||
query UsersList($serverId: ID, $filter: UserFilter, $page: Page, $sort: Sort) {
|
query UsersList($serverId: ID, $filter: UserFilter, $page: Page, $sort: Sort) {
|
||||||
servers(filter: {id: $serverId}) {
|
servers(filter: {id: $serverId}) {
|
||||||
@ -158,6 +224,12 @@ export class Queries {
|
|||||||
joinedOn
|
joinedOn
|
||||||
leavedOn
|
leavedOn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
achievements {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
createdAt
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { Server } from "../data/server.model";
|
import { GameServer, Server } from "../data/server.model";
|
||||||
import { User } from "../data/user.model";
|
import { User } from "../data/user.model";
|
||||||
import { AutoRole, AutoRoleRule } from "../data/auto_role.model";
|
import { AutoRole, AutoRoleRule } from "../data/auto_role.model";
|
||||||
import { Guild } from "../data/discord.model";
|
import { Guild } from "../data/discord.model";
|
||||||
import { Level } from "../data/level.model";
|
import { Level } from "../data/level.model";
|
||||||
|
import { Achievement, AchievementAttribute } from "../data/achievement.model";
|
||||||
|
|
||||||
export interface Query {
|
export interface Query {
|
||||||
serverCount: number;
|
serverCount: number;
|
||||||
@ -18,11 +19,26 @@ export interface UserListQuery {
|
|||||||
users: User[];
|
users: User[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GameServerListQuery {
|
||||||
|
gameServerCount: number;
|
||||||
|
gameServers: GameServer[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface LevelListQuery {
|
export interface LevelListQuery {
|
||||||
levelCount: number;
|
levelCount: number;
|
||||||
levels: Level[];
|
levels: Level[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AchievementTypeQuery {
|
||||||
|
achievementAttributes: AchievementAttribute[];
|
||||||
|
achievementOperators: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AchievementListQuery {
|
||||||
|
achievementCount: number;
|
||||||
|
achievements: Achievement[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface AutoRoleQuery {
|
export interface AutoRoleQuery {
|
||||||
autoRoleCount: number;
|
autoRoleCount: number;
|
||||||
autoRoles: AutoRole[];
|
autoRoles: AutoRole[];
|
||||||
|
@ -2,6 +2,7 @@ import { User } from "../data/user.model";
|
|||||||
import { AutoRole, AutoRoleRule } from "../data/auto_role.model";
|
import { AutoRole, AutoRoleRule } from "../data/auto_role.model";
|
||||||
import { Level } from "../data/level.model";
|
import { Level } from "../data/level.model";
|
||||||
import { Server } from "../data/server.model";
|
import { Server } from "../data/server.model";
|
||||||
|
import { Achievement } from "../data/achievement.model";
|
||||||
|
|
||||||
export interface GraphQLResult {
|
export interface GraphQLResult {
|
||||||
data: {
|
data: {
|
||||||
@ -45,3 +46,11 @@ export interface LevelMutationResult {
|
|||||||
deleteLevel?: Level
|
deleteLevel?: Level
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AchievementMutationResult {
|
||||||
|
achievement: {
|
||||||
|
createAchievement?: Achievement
|
||||||
|
updateAchievement?: Achievement
|
||||||
|
deleteAchievement?: Achievement
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
import {NgModule} from "@angular/core";
|
||||||
|
import {RouterModule, Routes} from "@angular/router";
|
||||||
|
import { AchievementComponent } from "./components/achievement/achievement.component";
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
|
||||||
|
{path: '', component: AchievementComponent},
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class AchievementsRoutingModule {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
import { NgModule } from "@angular/core";
|
||||||
|
import { CommonModule } from "@angular/common";
|
||||||
|
import { AchievementComponent } from "./components/achievement/achievement.component";
|
||||||
|
import { AchievementsRoutingModule } from "./achievements-routing.module";
|
||||||
|
import { SharedModule } from "../../../shared/shared.module";
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AchievementComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
AchievementsRoutingModule,
|
||||||
|
SharedModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AchievementsModule { }
|
@ -0,0 +1,258 @@
|
|||||||
|
<h1>
|
||||||
|
{{'view.server.achievements.header' | translate}}
|
||||||
|
</h1>
|
||||||
|
<div class="content-wrapper">
|
||||||
|
<div class="content">
|
||||||
|
<p-table #dt [value]="achievements" dataKey="id" editMode="row" [rowHover]="true" [rows]="10"
|
||||||
|
[rowsPerPageOptions]="[10,25,50]" [paginator]="true" [loading]="loading" [totalRecords]="totalRecords"
|
||||||
|
[lazy]="true" (onLazyLoad)="nextPage($event)">
|
||||||
|
|
||||||
|
<ng-template pTemplate="caption">
|
||||||
|
<div class="table-caption">
|
||||||
|
<div class="table-caption-text">
|
||||||
|
<ng-container *ngIf="!loading">{{achievements.length}} {{'common.of' | translate}}
|
||||||
|
{{dt.totalRecords}}
|
||||||
|
</ng-container>
|
||||||
|
{{'view.server.achievements.achievements' | translate}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-caption-btn-wrapper btn-wrapper">
|
||||||
|
<button pButton label="{{'common.add' | translate}}" class="icon-btn btn"
|
||||||
|
icon="pi pi-user-plus" (click)="addAchievement(dt)" [disabled]="isEditingNew || !user?.isModerator && !user?.isAdmin">
|
||||||
|
</button>
|
||||||
|
<button pButton label="{{'common.reset_filters' | translate}}" icon="pi pi-undo"
|
||||||
|
class="icon-btn btn" (click)="resetFilters()">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template pTemplate="header">
|
||||||
|
<tr>
|
||||||
|
<th pSortableColumn="id">
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'common.id' | translate}}</div>
|
||||||
|
<p-sortIcon field="id" class="table-header-icon"></p-sortIcon>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th pSortableColumn="name">
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'view.server.achievements.headers.name' | translate}}</div>
|
||||||
|
<p-sortIcon field="name" class="table-header-icon"></p-sortIcon>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th pSortableColumn="description">
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'view.server.achievements.headers.description' | translate}}</div>
|
||||||
|
<p-sortIcon field="name" class="table-header-icon"></p-sortIcon>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th pSortableColumn="attribute">
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'view.server.achievements.headers.attribute' | translate}}</div>
|
||||||
|
<p-sortIcon field="attribute" class="table-header-icon"></p-sortIcon>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th pSortableColumn="operator">
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'view.server.achievements.headers.operator' | translate}}</div>
|
||||||
|
<p-sortIcon field="operator" class="table-header-icon"></p-sortIcon>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th pSortableColumn="value">
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'view.server.achievements.headers.value' | translate}}</div>
|
||||||
|
<p-sortIcon field="value" class="table-header-icon"></p-sortIcon>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th>
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'common.created_at' | translate}}</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th>
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'common.modified_at' | translate}}</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th>
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'common.actions' | translate}}</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="table-header-small">
|
||||||
|
<form [formGroup]="filterForm">
|
||||||
|
<input type="text" pInputText formControlName="id"
|
||||||
|
placeholder="{{'common.id' | translate}}">
|
||||||
|
</form>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<form [formGroup]="filterForm">
|
||||||
|
<input type="text" pInputText formControlName="name"
|
||||||
|
placeholder="{{'view.server.achievements.headers.name' | translate}}">
|
||||||
|
</form>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<form [formGroup]="filterForm">
|
||||||
|
<input type="text" pInputText formControlName="name"
|
||||||
|
placeholder="{{'view.server.achievements.headers.description' | translate}}">
|
||||||
|
</form>
|
||||||
|
</th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
<th class="table-header-small-dropdown"></th>
|
||||||
|
<th class="table-header-small-dropdown"></th>
|
||||||
|
<th class="table-header-actions"></th>
|
||||||
|
</tr>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template pTemplate="body" let-achievement let-editing="editing" let-ri="rowIndex">
|
||||||
|
<tr [pEditableRow]="achievement">
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
{{achievement.id}}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.id}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
<input class="table-edit-input" pInputText type="text" [(ngModel)]="achievement.name">
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.name}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
<input class="table-edit-input" pInputText type="text" [(ngModel)]="achievement.description">
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.description}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
<p-dropdown [options]="attributes" [(ngModel)]="achievement.attribute"
|
||||||
|
placeholder="{{'view.server.achievements.headers.attribute' | translate}}"></p-dropdown>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.attribute}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
<p-dropdown [options]="operators" [(ngModel)]="achievement.operator" placeholder="{{'view.server.achievements.headers.operator' | translate}}"></p-dropdown>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.operator}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<p-cellEditor *ngIf="getAchievementAttributeByName(achievement.attribute)?.type === 'number'">
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
<input class="table-edit-input" pInputText min="0" type="number" [(ngModel)]="achievement.value">
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.value}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
|
||||||
|
<p-cellEditor *ngIf="getAchievementAttributeByName(achievement.attribute)?.type === 'Level'">
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
<p-dropdown [options]="levels" [(ngModel)]="achievement.value" placeholder="{{'view.server.members.headers.level' | translate}}"></p-dropdown>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.value}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
|
||||||
|
<p-cellEditor *ngIf="getAchievementAttributeByName(achievement.attribute)?.type === 'GameServer'">
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
<p-dropdown [options]="gameServers" [(ngModel)]="achievement.value" placeholder="{{'view.server.profile.joined_game_server.name' | translate}}"></p-dropdown>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.value}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
{{achievement.createdAt | date:'dd.MM.yy HH:mm'}}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.createdAt | date:'dd.MM.yy HH:mm'}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
{{achievement.modifiedAt | date:'dd.MM.yy HH:mm'}}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.modifiedAt | date:'dd.MM.yy HH:mm'}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="btn-wrapper">
|
||||||
|
<app-history-btn *ngIf="!isEditingNew" [id]="achievement.id" [query]="query" translationKey="view.server.achievements.header"></app-history-btn>
|
||||||
|
<button *ngIf="!editing" pButton pInitEditableRow class="btn icon-btn" icon="pi pi-pencil"
|
||||||
|
(click)="onRowEditInit(dt, achievement, ri)" [disabled]="!user || !user.isModerator && !user.isAdmin"></button>
|
||||||
|
<button *ngIf="!editing" pButton class="btn icon-btn danger-icon-btn" icon="pi pi-trash"
|
||||||
|
(click)="deleteAchievement(achievement)" [disabled]="!user || !user.isModerator && !user.isAdmin"></button>
|
||||||
|
|
||||||
|
<button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn"
|
||||||
|
icon="pi pi-check-circle" (click)="onRowEditSave(dt, achievement, ri)" [disabled]="!user || !user.isModerator && !user.isAdmin"></button>
|
||||||
|
<button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn"
|
||||||
|
icon="pi pi-times-circle" (click)="onRowEditCancel(ri)" [disabled]="!user || !user.isModerator && !user.isAdmin"></button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template pTemplate="emptymessage">
|
||||||
|
<tr></tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="10">{{'common.no_entries_found' | translate}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr></tr>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template pTemplate="paginatorleft">
|
||||||
|
</ng-template>
|
||||||
|
</p-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AchievementComponent } from './achievement.component';
|
||||||
|
|
||||||
|
describe('AchievementComponent', () => {
|
||||||
|
let component: AchievementComponent;
|
||||||
|
let fixture: ComponentFixture<AchievementComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ AchievementComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(AchievementComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,323 @@
|
|||||||
|
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||||
|
import { Achievement, AchievementAttribute, AchievementFilter } from "../../../../../../models/data/achievement.model";
|
||||||
|
import { FormBuilder, FormControl, FormGroup } from "@angular/forms";
|
||||||
|
import { Page } from "../../../../../../models/graphql/filter/page.model";
|
||||||
|
import { Sort, SortDirection } from "../../../../../../models/graphql/filter/sort.model";
|
||||||
|
import { Subject, throwError } from "rxjs";
|
||||||
|
import { Server } from "../../../../../../models/data/server.model";
|
||||||
|
import { UserDTO } from "../../../../../../models/auth/auth-user.dto";
|
||||||
|
import { Queries } from "../../../../../../models/graphql/queries.model";
|
||||||
|
import { AuthService } from "../../../../../../services/auth/auth.service";
|
||||||
|
import { SpinnerService } from "../../../../../../services/spinner/spinner.service";
|
||||||
|
import { ToastService } from "../../../../../../services/toast/toast.service";
|
||||||
|
import { ConfirmationDialogService } from "../../../../../../services/confirmation-dialog/confirmation-dialog.service";
|
||||||
|
import { TranslateService } from "@ngx-translate/core";
|
||||||
|
import { DataService } from "../../../../../../services/data/data.service";
|
||||||
|
import { SidebarService } from "../../../../../../services/sidebar/sidebar.service";
|
||||||
|
import { ActivatedRoute } from "@angular/router";
|
||||||
|
import { AchievementListQuery, AchievementTypeQuery, GameServerListQuery, LevelListQuery, Query } from "../../../../../../models/graphql/query.model";
|
||||||
|
import { catchError, debounceTime, takeUntil } from "rxjs/operators";
|
||||||
|
import { LazyLoadEvent, MenuItem } from "primeng/api";
|
||||||
|
import { Table } from "primeng/table";
|
||||||
|
import { User } from "../../../../../../models/data/user.model";
|
||||||
|
import { AchievementMutationResult } from "../../../../../../models/graphql/result.model";
|
||||||
|
import { Mutations } from "../../../../../../models/graphql/mutations.model";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "app-achievement",
|
||||||
|
templateUrl: "./achievement.component.html",
|
||||||
|
styleUrls: ["./achievement.component.scss"]
|
||||||
|
})
|
||||||
|
export class AchievementComponent implements OnInit, OnDestroy {
|
||||||
|
public achievements: Achievement[] = [];
|
||||||
|
public loading = true;
|
||||||
|
|
||||||
|
public isEditingNew: boolean = false;
|
||||||
|
|
||||||
|
public filterForm!: FormGroup<{
|
||||||
|
id: FormControl<number | null>,
|
||||||
|
name: FormControl<string | null>,
|
||||||
|
color: FormControl<string | null>,
|
||||||
|
min_xp: FormControl<number | null>,
|
||||||
|
permissions: FormControl<string | null>,
|
||||||
|
}>;
|
||||||
|
|
||||||
|
public filter: AchievementFilter = {};
|
||||||
|
public page: Page = {
|
||||||
|
pageSize: undefined,
|
||||||
|
pageIndex: undefined
|
||||||
|
};
|
||||||
|
public sort: Sort = {
|
||||||
|
sortColumn: undefined,
|
||||||
|
sortDirection: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
public totalRecords: number = 0;
|
||||||
|
|
||||||
|
public clonedAchievements: { [s: string]: Achievement; } = {};
|
||||||
|
|
||||||
|
private unsubscriber = new Subject<void>();
|
||||||
|
private server: Server = {};
|
||||||
|
public user: UserDTO | null = null;
|
||||||
|
|
||||||
|
public operators: string[] = [];
|
||||||
|
public attributes: MenuItem[] = [];
|
||||||
|
private achievementsAttributes: AchievementAttribute[] = [];
|
||||||
|
|
||||||
|
public levels!: MenuItem[];
|
||||||
|
public gameServers!: MenuItem[];
|
||||||
|
|
||||||
|
query: string = Queries.achievementWithHistoryQuery;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
private authService: AuthService,
|
||||||
|
private spinner: SpinnerService,
|
||||||
|
private toastService: ToastService,
|
||||||
|
private confirmDialog: ConfirmationDialogService,
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private translate: TranslateService,
|
||||||
|
private data: DataService,
|
||||||
|
private sidebar: SidebarService,
|
||||||
|
private route: ActivatedRoute) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ngOnInit(): void {
|
||||||
|
this.loading = true;
|
||||||
|
this.setFilterForm();
|
||||||
|
this.data.getServerFromRoute(this.route).then(async server => {
|
||||||
|
this.server = server;
|
||||||
|
let authUser = await this.authService.getLoggedInUser();
|
||||||
|
this.user = authUser?.users?.find(u => u.server == this.server.id) ?? null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public ngOnDestroy(): void {
|
||||||
|
this.unsubscriber.next();
|
||||||
|
this.unsubscriber.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadLevels() {
|
||||||
|
this.data.query<LevelListQuery>(Queries.levelQuery, {
|
||||||
|
serverId: this.server.id
|
||||||
|
},
|
||||||
|
(data: Query) => {
|
||||||
|
return data.servers[0];
|
||||||
|
}
|
||||||
|
).subscribe(data => {
|
||||||
|
this.levels = data.levels.map(level => {
|
||||||
|
return { label: level.name, value: level.name };
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadGameServers() {
|
||||||
|
this.data.query<GameServerListQuery>(Queries.gameServerQuery, {
|
||||||
|
serverId: this.server.id
|
||||||
|
},
|
||||||
|
(data: Query) => {
|
||||||
|
return data.servers[0];
|
||||||
|
}
|
||||||
|
).subscribe(data => {
|
||||||
|
this.gameServers = data.gameServers.map(gameServer => {
|
||||||
|
return { label: gameServer.name, value: gameServer.name };
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadNextData() {
|
||||||
|
this.data.query<AchievementListQuery>(Queries.achievementQuery, {
|
||||||
|
serverId: this.server.id, filter: this.filter, page: this.page, sort: this.sort
|
||||||
|
},
|
||||||
|
(data: Query) => {
|
||||||
|
return data.servers[0];
|
||||||
|
}
|
||||||
|
).subscribe(data => {
|
||||||
|
this.totalRecords = data.achievementCount;
|
||||||
|
this.achievements = data.achievements;
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public loadNextPage(): void {
|
||||||
|
this.data.query<AchievementTypeQuery>(Queries.achievementTypeQuery
|
||||||
|
).subscribe(data => {
|
||||||
|
this.operators = data.achievementOperators;
|
||||||
|
this.achievementsAttributes = data.achievementAttributes;
|
||||||
|
this.attributes = data.achievementAttributes.map(attribute => {
|
||||||
|
return { label: attribute.name, value: attribute.name };
|
||||||
|
});
|
||||||
|
this.loadLevels();
|
||||||
|
this.loadGameServers();
|
||||||
|
this.loadNextData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public setFilterForm(): void {
|
||||||
|
this.filterForm = this.fb.group({
|
||||||
|
id: new FormControl<number | null>(null),
|
||||||
|
name: new FormControl<string | null>(null),
|
||||||
|
color: new FormControl<string | null>(null),
|
||||||
|
min_xp: new FormControl<number | null>(null),
|
||||||
|
permissions: new FormControl<string | null>(null)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.filterForm.valueChanges.pipe(
|
||||||
|
takeUntil(this.unsubscriber),
|
||||||
|
debounceTime(600)
|
||||||
|
).subscribe(changes => {
|
||||||
|
if (changes.id) {
|
||||||
|
this.filter.id = changes.id;
|
||||||
|
} else {
|
||||||
|
this.filter.id = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changes.name) {
|
||||||
|
this.filter.name = changes.name;
|
||||||
|
} else {
|
||||||
|
this.filter.name = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.page.pageSize)
|
||||||
|
this.page.pageSize = 10;
|
||||||
|
|
||||||
|
if (this.page.pageIndex)
|
||||||
|
this.page.pageIndex = 0;
|
||||||
|
|
||||||
|
this.loadNextPage();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public newAchievementTemplate: Achievement = {
|
||||||
|
id: 0,
|
||||||
|
createdAt: "",
|
||||||
|
modifiedAt: ""
|
||||||
|
};
|
||||||
|
|
||||||
|
public nextPage(event: LazyLoadEvent): void {
|
||||||
|
this.page.pageSize = event.rows ?? 0;
|
||||||
|
if (event.first != null && event.rows != null)
|
||||||
|
this.page.pageIndex = event.first / event.rows;
|
||||||
|
this.sort.sortColumn = event.sortField ?? undefined;
|
||||||
|
this.sort.sortDirection = event.sortOrder === 1 ? SortDirection.ASC : event.sortOrder === -1 ? SortDirection.DESC : SortDirection.ASC;
|
||||||
|
|
||||||
|
this.loadNextPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public resetFilters(): void {
|
||||||
|
this.filterForm.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public onRowEditInit(table: Table, user: User, index: number): void {
|
||||||
|
this.clonedAchievements[index] = { ...user };
|
||||||
|
}
|
||||||
|
|
||||||
|
public onRowEditSave(table: Table, newAchievement: Achievement, index: number): void {
|
||||||
|
if (this.isEditingNew && JSON.stringify(newAchievement) === JSON.stringify(this.newAchievementTemplate)) {
|
||||||
|
this.isEditingNew = false;
|
||||||
|
this.achievements.splice(index, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newAchievement.id && !this.isEditingNew || !newAchievement.name && !newAchievement.attribute && !newAchievement?.operator && !newAchievement?.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isEditingNew) {
|
||||||
|
this.spinner.showSpinner();
|
||||||
|
this.data.mutation<AchievementMutationResult>(Mutations.createAchievement, {
|
||||||
|
name: newAchievement.name,
|
||||||
|
description: newAchievement.description,
|
||||||
|
attribute: newAchievement.attribute,
|
||||||
|
operator: newAchievement.operator,
|
||||||
|
value: newAchievement.value + "",
|
||||||
|
serverId: this.server.id
|
||||||
|
}
|
||||||
|
).pipe(catchError(err => {
|
||||||
|
this.isEditingNew = false;
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.toastService.error(this.translate.instant("view.server.achievements.message.achievement_create_failed"), this.translate.instant("view.server.achievements.message.achievement_create_failed_d"));
|
||||||
|
return throwError(err);
|
||||||
|
})).subscribe(result => {
|
||||||
|
this.isEditingNew = false;
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.toastService.success(this.translate.instant("view.server.achievements.message.achievement_create"), this.translate.instant("view.server.achievements.message.achievement_create_d", { name: result.achievement.createAchievement?.name }));
|
||||||
|
this.loadNextPage();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.spinner.showSpinner();
|
||||||
|
this.data.mutation<AchievementMutationResult>(Mutations.updateAchievement, {
|
||||||
|
id: newAchievement.id,
|
||||||
|
name: newAchievement.name,
|
||||||
|
description: newAchievement.description,
|
||||||
|
attribute: newAchievement.attribute,
|
||||||
|
operator: newAchievement.operator,
|
||||||
|
value: newAchievement.value + ""
|
||||||
|
}
|
||||||
|
).pipe(catchError(err => {
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.toastService.error(this.translate.instant("view.server.achievements.message.achievement_update_failed"), this.translate.instant("view.server.achievements.message.achievement_update_failed_d", { name: newAchievement.name }));
|
||||||
|
return throwError(err);
|
||||||
|
})).subscribe(_ => {
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.toastService.success(this.translate.instant("view.server.achievements.message.achievement_update"), this.translate.instant("view.server.achievements.message.achievement_update_d", { name: newAchievement.name }));
|
||||||
|
this.loadNextPage();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public onRowEditCancel(index: number): void {
|
||||||
|
if (this.isEditingNew) {
|
||||||
|
this.achievements.splice(index, 1);
|
||||||
|
delete this.clonedAchievements[index];
|
||||||
|
this.isEditingNew = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.achievements[index] = this.clonedAchievements[index];
|
||||||
|
delete this.clonedAchievements[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public deleteAchievement(achievement: Achievement): void {
|
||||||
|
this.confirmDialog.confirmDialog(
|
||||||
|
this.translate.instant("view.server.achievements.message.achievement_delete"), this.translate.instant("view.server.achievements.message.achievement_delete_q", { name: achievement.name }),
|
||||||
|
() => {
|
||||||
|
this.spinner.showSpinner();
|
||||||
|
this.data.mutation<AchievementMutationResult>(Mutations.deleteAchievement, {
|
||||||
|
id: achievement.id
|
||||||
|
}
|
||||||
|
).pipe(catchError(err => {
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.toastService.error(this.translate.instant("view.server.achievements.message.achievement_delete_failed"), this.translate.instant("view.server.achievements.message.achievement_delete_failed_d", { name: achievement.name }));
|
||||||
|
return throwError(err);
|
||||||
|
})).subscribe(l => {
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.toastService.success(this.translate.instant("view.server.achievements.message.achievement_deleted"), this.translate.instant("view.server.achievements.message.achievement_deleted_d", { name: achievement.name }));
|
||||||
|
this.loadNextPage();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public addAchievement(table: Table): void {
|
||||||
|
const newAchievement = JSON.parse(JSON.stringify(this.newAchievementTemplate));
|
||||||
|
newAchievement.id = Math.max.apply(Math, this.achievements.map(l => {
|
||||||
|
return l.id ?? 0;
|
||||||
|
})) + 1;
|
||||||
|
|
||||||
|
this.achievements.push(newAchievement);
|
||||||
|
|
||||||
|
table.initRowEdit(newAchievement);
|
||||||
|
|
||||||
|
const index = this.achievements.findIndex(l => l.id == newAchievement.id);
|
||||||
|
this.onRowEditInit(table, newAchievement, index);
|
||||||
|
|
||||||
|
this.isEditingNew = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAchievementAttributeByName(name: string): AchievementAttribute {
|
||||||
|
const [found] = this.achievementsAttributes.filter(x => x.name === name);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
}
|
@ -41,12 +41,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="content-row">-->
|
<!-- <div class="content-row">-->
|
||||||
<!-- <div class="content-column">-->
|
<!-- <div class="content-column">-->
|
||||||
<!-- <div class="content-data-name">{{'view.server.profile.minecraft_id' | translate}}:</div>-->
|
<!-- <div class="content-data-name">{{'view.server.profile.minecraft_id' | translate}}:</div>-->
|
||||||
<!-- <div class="content-data-value">{{user.minecraftId}}</div>-->
|
<!-- <div class="content-data-value">{{user.minecraftId}}</div>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
|
|
||||||
<div class="content-row">
|
<div class="content-row">
|
||||||
<div class="content-column">
|
<div class="content-column">
|
||||||
@ -78,6 +78,22 @@
|
|||||||
|
|
||||||
<div class="content-divider"></div>
|
<div class="content-divider"></div>
|
||||||
|
|
||||||
|
<p-panel header="{{'view.server.profile.achievements.header' | translate}}" [toggleable]="true">
|
||||||
|
<div *ngFor="let achievement of user.achievements;">
|
||||||
|
<div class="content-row">
|
||||||
|
<div class="content-column">
|
||||||
|
<div class="content-data-name">{{'common.name' | translate}}:</div>
|
||||||
|
<div class="content-data-value">{{achievement.name}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content-column">
|
||||||
|
<div class="content-data-name">{{'view.server.profile.achievements.time' | translate}}:</div>
|
||||||
|
<div class="content-data-value">{{achievement.createdAt | date:'dd.MM.yyyy HH:mm:ss'}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</p-panel>
|
||||||
|
|
||||||
<p-panel header="{{'view.server.profile.joined_voice_channel.header' | translate}}" [toggleable]="true">
|
<p-panel header="{{'view.server.profile.joined_voice_channel.header' | translate}}" [toggleable]="true">
|
||||||
<div *ngFor="let join of user.joinedVoiceChannels;">
|
<div *ngFor="let join of user.joinedVoiceChannels;">
|
||||||
<div class="content-row">
|
<div class="content-row">
|
||||||
@ -102,8 +118,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</p-panel>
|
</p-panel>
|
||||||
|
|
||||||
<p-panel header="{{'view.server.profile.joined_game_server.header' | translate}}" [toggleable]="true">
|
<p-panel header="{{'view.server.profile.joined_game_server.header' | translate}}" [toggleable]="true">
|
||||||
<div *ngFor="let join of user.userJoinedGameServers;">
|
<div *ngFor="let join of user.userJoinedGameServers;">
|
||||||
<div class="content-row">
|
<div class="content-row">
|
||||||
|
@ -9,7 +9,8 @@ const routes: Routes = [
|
|||||||
{ path: "members", component: MembersComponent },
|
{ path: "members", component: MembersComponent },
|
||||||
{ path: "members/:memberId", component: ProfileComponent },
|
{ path: "members/:memberId", component: ProfileComponent },
|
||||||
{ path: "auto-roles", loadChildren: () => import("./auto-role/auto-role.module").then(m => m.AutoRoleModule) },
|
{ path: "auto-roles", loadChildren: () => import("./auto-role/auto-role.module").then(m => m.AutoRoleModule) },
|
||||||
{ path: "levels", loadChildren: () => import("./levels/levels.module").then(m => m.LevelsModule) }
|
{ path: "levels", loadChildren: () => import("./levels/levels.module").then(m => m.LevelsModule) },
|
||||||
|
{ path: "achievements", loadChildren: () => import("./achievements/achievements.module").then(m => m.AchievementsModule) }
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -24,6 +24,7 @@ export class SidebarService {
|
|||||||
serverMembers: MenuItem = {};
|
serverMembers: MenuItem = {};
|
||||||
serverAutoRoles: MenuItem = {};
|
serverAutoRoles: MenuItem = {};
|
||||||
serverLevels: MenuItem = {};
|
serverLevels: MenuItem = {};
|
||||||
|
serverAchievements: MenuItem = {};
|
||||||
serverMenu: MenuItem = {};
|
serverMenu: MenuItem = {};
|
||||||
adminConfig: MenuItem = {};
|
adminConfig: MenuItem = {};
|
||||||
adminUsers: MenuItem = {};
|
adminUsers: MenuItem = {};
|
||||||
@ -102,12 +103,19 @@ export class SidebarService {
|
|||||||
routerLink: `server/${this.server$.value?.id}/levels`
|
routerLink: `server/${this.server$.value?.id}/levels`
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.serverAchievements = {
|
||||||
|
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.achievements") : "",
|
||||||
|
icon: "pi pi-angle-double-up",
|
||||||
|
visible: true,
|
||||||
|
routerLink: `server/${this.server$.value?.id}/achievements`
|
||||||
|
};
|
||||||
|
|
||||||
this.serverMenu = {
|
this.serverMenu = {
|
||||||
label: this.isSidebarOpen ? this.server$.value?.name : "",
|
label: this.isSidebarOpen ? this.server$.value?.name : "",
|
||||||
icon: "pi pi-server",
|
icon: "pi pi-server",
|
||||||
visible: false,
|
visible: false,
|
||||||
expanded: true,
|
expanded: true,
|
||||||
items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels]
|
items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels, this.serverAchievements]
|
||||||
};
|
};
|
||||||
this.adminConfig = {
|
this.adminConfig = {
|
||||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "",
|
label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "",
|
||||||
@ -142,6 +150,7 @@ export class SidebarService {
|
|||||||
this.serverMembers.visible = !!user?.isModerator;
|
this.serverMembers.visible = !!user?.isModerator;
|
||||||
this.serverAutoRoles.visible = !!user?.isModerator;
|
this.serverAutoRoles.visible = !!user?.isModerator;
|
||||||
this.serverLevels.visible = !!user?.isModerator;
|
this.serverLevels.visible = !!user?.isModerator;
|
||||||
|
this.serverAchievements.visible = !!user?.isModerator;
|
||||||
} else {
|
} else {
|
||||||
this.serverMenu.visible = false;
|
this.serverMenu.visible = false;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"WebVersion": {
|
"WebVersion": {
|
||||||
"Major": "1",
|
"Major": "1",
|
||||||
"Minor": "0",
|
"Minor": "0",
|
||||||
"Micro": "7"
|
"Micro": "dev268_achievements"
|
||||||
},
|
},
|
||||||
"Themes": [
|
"Themes": [
|
||||||
{
|
{
|
||||||
|
@ -97,6 +97,7 @@
|
|||||||
"wrong_password": "Falsches Passwort"
|
"wrong_password": "Falsches Passwort"
|
||||||
},
|
},
|
||||||
"register": {
|
"register": {
|
||||||
|
"confirm_privacy": "Ich erkläre mich mit der <a href=\"{{url}}\">Datenschutzerklärung</a> einverstanden.",
|
||||||
"email_required": "E-Mail benötigt",
|
"email_required": "E-Mail benötigt",
|
||||||
"emails_not_match": "E-Mails stimmen nicht überein",
|
"emails_not_match": "E-Mails stimmen nicht überein",
|
||||||
"first_name": "Vorname",
|
"first_name": "Vorname",
|
||||||
@ -113,8 +114,7 @@
|
|||||||
"register_with_discord": "Mit Discord Registrieren",
|
"register_with_discord": "Mit Discord Registrieren",
|
||||||
"repeat_email": "E-Mail wiederholen",
|
"repeat_email": "E-Mail wiederholen",
|
||||||
"repeat_password": "Passwort wiederholen",
|
"repeat_password": "Passwort wiederholen",
|
||||||
"user_already_exists": "Benutzer existiert bereits",
|
"user_already_exists": "Benutzer existiert bereits"
|
||||||
"confirm_privacy": "Ich erkläre mich mit der <a href=\"{{url}}\">Datenschutzerklärung</a> einverstanden."
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
@ -147,12 +147,16 @@
|
|||||||
"permissions": "Berechtigung",
|
"permissions": "Berechtigung",
|
||||||
"roleId": "Rolle",
|
"roleId": "Rolle",
|
||||||
"server": "Server",
|
"server": "Server",
|
||||||
"xp": "XP"
|
"xp": "XP",
|
||||||
|
"attribute": "Attribut",
|
||||||
|
"operator": "Operator",
|
||||||
|
"value": "Wert"
|
||||||
},
|
},
|
||||||
"id": "Id",
|
"id": "Id",
|
||||||
"joined_at": "Beigetreten am",
|
"joined_at": "Beigetreten am",
|
||||||
"leaved_at": "Verlassen am",
|
"leaved_at": "Verlassen am",
|
||||||
"modified_at": "Bearbeitet am",
|
"modified_at": "Bearbeitet am",
|
||||||
|
"name": "Name",
|
||||||
"no_entries_found": "Keine Einträge gefunden",
|
"no_entries_found": "Keine Einträge gefunden",
|
||||||
"of": "von",
|
"of": "von",
|
||||||
"reset_filters": "Filter zurücksetzen"
|
"reset_filters": "Filter zurücksetzen"
|
||||||
@ -276,6 +280,7 @@
|
|||||||
"dashboard": "Dashboard",
|
"dashboard": "Dashboard",
|
||||||
"members": "Mitglieder",
|
"members": "Mitglieder",
|
||||||
"server": {
|
"server": {
|
||||||
|
"achievements": "Errungenschaften",
|
||||||
"auto_roles": "Auto Rollen",
|
"auto_roles": "Auto Rollen",
|
||||||
"dashboard": "Dashboard",
|
"dashboard": "Dashboard",
|
||||||
"levels": "Level",
|
"levels": "Level",
|
||||||
@ -315,6 +320,33 @@
|
|||||||
"servers": "Server"
|
"servers": "Server"
|
||||||
},
|
},
|
||||||
"server": {
|
"server": {
|
||||||
|
"achievements": {
|
||||||
|
"achievements": "Errungenschaften",
|
||||||
|
"header": "Errungenschaften",
|
||||||
|
"headers": {
|
||||||
|
"attribute": "Attribut",
|
||||||
|
"name": "Name",
|
||||||
|
"description": "Beschreibung",
|
||||||
|
"operator": "Operator",
|
||||||
|
"value": "Wert"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"achievement_create": "Errungenschaft erstellt",
|
||||||
|
"achievement_create_d": "Errungenschaft {{name}} erfolgreich erstellt",
|
||||||
|
"achievement_create_failed": "Errungenschaft Erstellung fehlgeschlagen",
|
||||||
|
"achievement_create_failed_d": "Die Erstellung der Errungenschaft ist fehlgeschlagen!",
|
||||||
|
"achievement_delete": "Errungenschaft löschen",
|
||||||
|
"achievement_delete_failed": "Errungenschaft Löschung fehlgeschlagen",
|
||||||
|
"achievement_delete_failed_d": "Die Löschung der Errungenschaft {{name}} ist fehlgeschlagen!",
|
||||||
|
"achievement_delete_q": "Sind Sie sich sicher, dass Sie das Errungenschaft {{name}} löschen möchten?",
|
||||||
|
"achievement_deleted": "Errungenschaft gelöscht",
|
||||||
|
"achievement_deleted_d": "Errungenschaft {{name}} erfolgreich gelöscht",
|
||||||
|
"achievement_update": "Errungenschaft bearbeitet",
|
||||||
|
"achievement_update_d": "Errungenschaft {{name}} erfolgreich bearbeitet",
|
||||||
|
"achievement_update_failed": "Errungenschaft Bearbeitung fehlgeschlagen",
|
||||||
|
"achievement_update_failed_d": "Die Bearbeitung der Errungenschaft ist fehlgeschlagen!"
|
||||||
|
}
|
||||||
|
},
|
||||||
"auto_roles": {
|
"auto_roles": {
|
||||||
"auto_roles": "Auto Rollen",
|
"auto_roles": "Auto Rollen",
|
||||||
"header": "Auto Rollen",
|
"header": "Auto Rollen",
|
||||||
@ -415,6 +447,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
|
"achievements": {
|
||||||
|
"header": "Errungeschaften",
|
||||||
|
"time": "Erreicht am"
|
||||||
|
},
|
||||||
"header": "Dein Profil",
|
"header": "Dein Profil",
|
||||||
"joined_game_server": {
|
"joined_game_server": {
|
||||||
"header": "Gameserver-beitritte",
|
"header": "Gameserver-beitritte",
|
||||||
|
@ -97,6 +97,7 @@
|
|||||||
"wrong_password": "Wrong password"
|
"wrong_password": "Wrong password"
|
||||||
},
|
},
|
||||||
"register": {
|
"register": {
|
||||||
|
"confirm_privacy": "I agree to the <a href=\"{{url}}\">Privacy Policy</a>.",
|
||||||
"email_required": "E-Mail required",
|
"email_required": "E-Mail required",
|
||||||
"emails_not_match": "E-Mails do not match",
|
"emails_not_match": "E-Mails do not match",
|
||||||
"first_name": "First name",
|
"first_name": "First name",
|
||||||
@ -113,8 +114,7 @@
|
|||||||
"register_with_discord": "Register with discord",
|
"register_with_discord": "Register with discord",
|
||||||
"repeat_email": "Repeat E-mail",
|
"repeat_email": "Repeat E-mail",
|
||||||
"repeat_password": "Repeat password",
|
"repeat_password": "Repeat password",
|
||||||
"user_already_exists": "User already exists",
|
"user_already_exists": "User already exists"
|
||||||
"confirm_privacy": "I agree to the <a href=\"{{url}}\">Privacy Policy</a>."
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
@ -147,12 +147,16 @@
|
|||||||
"permissions": "Permissions",
|
"permissions": "Permissions",
|
||||||
"roleId": "Role",
|
"roleId": "Role",
|
||||||
"server": "Server",
|
"server": "Server",
|
||||||
"xp": "XP"
|
"xp": "XP",
|
||||||
|
"attribute": "Attribute",
|
||||||
|
"operator": "Operator",
|
||||||
|
"value": "Value"
|
||||||
},
|
},
|
||||||
"id": "Id",
|
"id": "Id",
|
||||||
"joined_at": "Joined at",
|
"joined_at": "Joined at",
|
||||||
"leaved_at": "Leaved at",
|
"leaved_at": "Leaved at",
|
||||||
"modified_at": "Modified at",
|
"modified_at": "Modified at",
|
||||||
|
"name": "Name",
|
||||||
"no_entries_found": "No entries found",
|
"no_entries_found": "No entries found",
|
||||||
"of": "of",
|
"of": "of",
|
||||||
"reset_filters": "Reset filters"
|
"reset_filters": "Reset filters"
|
||||||
@ -276,6 +280,7 @@
|
|||||||
"dashboard": "Dashboard",
|
"dashboard": "Dashboard",
|
||||||
"members": "Members",
|
"members": "Members",
|
||||||
"server": {
|
"server": {
|
||||||
|
"achievements": "Achievements",
|
||||||
"auto_roles": "Auto role",
|
"auto_roles": "Auto role",
|
||||||
"dashboard": "Dashboard",
|
"dashboard": "Dashboard",
|
||||||
"levels": "Level",
|
"levels": "Level",
|
||||||
@ -315,6 +320,32 @@
|
|||||||
"servers": "Server"
|
"servers": "Server"
|
||||||
},
|
},
|
||||||
"server": {
|
"server": {
|
||||||
|
"achievements": {
|
||||||
|
"achievements": "Achievements",
|
||||||
|
"header": "Achievements",
|
||||||
|
"headers": {
|
||||||
|
"attribute": "Attribute",
|
||||||
|
"name": "Namer",
|
||||||
|
"operator": "Operator",
|
||||||
|
"value": "Value"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"achievement_create": "Achievement created",
|
||||||
|
"achievement_create_d": "Achievement {{name}} successfully created",
|
||||||
|
"achievement_create_failed": "Achievement creation failed",
|
||||||
|
"achievement_create_failed_d": "Creation of achievement failed!",
|
||||||
|
"achievement_delete": "Delete achievement",
|
||||||
|
"achievement_delete_failed": "Achievement deletion failed",
|
||||||
|
"achievement_delete_failed_d": "Deletion of achievement {{name}} failed!",
|
||||||
|
"achievement_delete_q": "Are you sure you want to delete the {{name}} achievement?",
|
||||||
|
"achievement_deleted": "Achievement deleted",
|
||||||
|
"achievement_deleted_d": "Achievement {{name}} successfully deleted\t",
|
||||||
|
"achievement_update": "Achievement edited",
|
||||||
|
"achievement_update_d": "Achievement {{name}} edited successfully",
|
||||||
|
"achievement_update_failed": "Achievement editing failed",
|
||||||
|
"achievement_update_failed_d": "Achievement editing failed!"
|
||||||
|
}
|
||||||
|
},
|
||||||
"auto_roles": {
|
"auto_roles": {
|
||||||
"auto_roles": "Auto roles",
|
"auto_roles": "Auto roles",
|
||||||
"header": "Auto roles",
|
"header": "Auto roles",
|
||||||
@ -415,6 +446,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
|
"achievements": {
|
||||||
|
"header": "Achievements",
|
||||||
|
"time": "Reached at"
|
||||||
|
},
|
||||||
"header": "Profile",
|
"header": "Profile",
|
||||||
"joined_game_server": {
|
"joined_game_server": {
|
||||||
"header": "Game server accessions",
|
"header": "Game server accessions",
|
||||||
|
Loading…
Reference in New Issue
Block a user