Compare commits
6 Commits
1.1.10
...
d448ad7707
Author | SHA1 | Date | |
---|---|---|---|
d448ad7707 | |||
19791ff9d8 | |||
3cba8de675 | |||
b7ff070676 | |||
c88e07d743 | |||
f5b978b231 |
@@ -17,6 +17,7 @@
|
|||||||
"permission": "src/modules/permission/permission.json",
|
"permission": "src/modules/permission/permission.json",
|
||||||
"technician": "src/modules/technician/technician.json",
|
"technician": "src/modules/technician/technician.json",
|
||||||
"short-role-name": "src/modules/short_role_name/short-role-name.json",
|
"short-role-name": "src/modules/short_role_name/short-role-name.json",
|
||||||
|
"special-offers": "src/modules/special_offers/special-offers.json",
|
||||||
"checks": "tools/checks/checks.json",
|
"checks": "tools/checks/checks.json",
|
||||||
"get-version": "tools/get_version/get-version.json",
|
"get-version": "tools/get_version/get-version.json",
|
||||||
"post-build": "tools/post_build/post-build.json",
|
"post-build": "tools/post_build/post-build.json",
|
||||||
|
@@ -69,6 +69,7 @@
|
|||||||
"../modules/level/level.json",
|
"../modules/level/level.json",
|
||||||
"../modules/permission/permission.json",
|
"../modules/permission/permission.json",
|
||||||
"../modules/short_role_name/short-role-name.json",
|
"../modules/short_role_name/short-role-name.json",
|
||||||
|
"../modules/special_offers/special-offers.json",
|
||||||
"../modules/technician/technician.json"
|
"../modules/technician/technician.json"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Submodule kdb-bot/src/bot/config updated: 23eafb2e21...839bbb823a
@@ -14,6 +14,7 @@ from modules.database.database_module import DatabaseModule
|
|||||||
from modules.level.level_module import LevelModule
|
from modules.level.level_module import LevelModule
|
||||||
from modules.permission.permission_module import PermissionModule
|
from modules.permission.permission_module import PermissionModule
|
||||||
from modules.short_role_name.short_role_name_module import ShortRoleNameModule
|
from modules.short_role_name.short_role_name_module import ShortRoleNameModule
|
||||||
|
from modules.special_offers.special_offers_module import SteamSpecialOffersModule
|
||||||
from modules.technician.technician_module import TechnicianModule
|
from modules.technician.technician_module import TechnicianModule
|
||||||
|
|
||||||
|
|
||||||
@@ -37,6 +38,7 @@ class ModuleList:
|
|||||||
TechnicianModule,
|
TechnicianModule,
|
||||||
AchievementsModule,
|
AchievementsModule,
|
||||||
ShortRoleNameModule,
|
ShortRoleNameModule,
|
||||||
|
SteamSpecialOffersModule,
|
||||||
# has to be last!
|
# has to be last!
|
||||||
BootLogModule,
|
BootLogModule,
|
||||||
CoreExtensionModule,
|
CoreExtensionModule,
|
||||||
|
@@ -16,6 +16,7 @@ from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
|||||||
from bot_core.logging.command_logger import CommandLogger
|
from bot_core.logging.command_logger import CommandLogger
|
||||||
from bot_core.logging.database_logger import DatabaseLogger
|
from bot_core.logging.database_logger import DatabaseLogger
|
||||||
from bot_core.logging.message_logger import MessageLogger
|
from bot_core.logging.message_logger import MessageLogger
|
||||||
|
from bot_core.logging.task_logger import TaskLogger
|
||||||
from bot_data.db_context import DBContext
|
from bot_data.db_context import DBContext
|
||||||
|
|
||||||
|
|
||||||
@@ -43,6 +44,7 @@ class Startup(StartupABC):
|
|||||||
services.add_singleton(CustomFileLoggerABC, CommandLogger)
|
services.add_singleton(CustomFileLoggerABC, CommandLogger)
|
||||||
services.add_singleton(CustomFileLoggerABC, DatabaseLogger)
|
services.add_singleton(CustomFileLoggerABC, DatabaseLogger)
|
||||||
services.add_singleton(CustomFileLoggerABC, MessageLogger)
|
services.add_singleton(CustomFileLoggerABC, MessageLogger)
|
||||||
|
services.add_singleton(CustomFileLoggerABC, TaskLogger)
|
||||||
|
|
||||||
if self._feature_flags.get_flag(FeatureFlagsEnum.api_module):
|
if self._feature_flags.get_flag(FeatureFlagsEnum.api_module):
|
||||||
services.add_singleton(CustomFileLoggerABC, ApiLogger)
|
services.add_singleton(CustomFileLoggerABC, ApiLogger)
|
||||||
|
@@ -9,17 +9,20 @@ 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
|
||||||
from bot_data.migration.auto_role_migration import AutoRoleMigration
|
from bot_data.migration.auto_role_migration import AutoRoleMigration
|
||||||
|
from bot_data.migration.birthday_migration import BirthdayMigration
|
||||||
from bot_data.migration.config_feature_flags_migration import ConfigFeatureFlagsMigration
|
from bot_data.migration.config_feature_flags_migration import ConfigFeatureFlagsMigration
|
||||||
from bot_data.migration.config_migration import ConfigMigration
|
from bot_data.migration.config_migration import ConfigMigration
|
||||||
from bot_data.migration.db_history_migration import DBHistoryMigration
|
from bot_data.migration.db_history_migration import DBHistoryMigration
|
||||||
from bot_data.migration.default_role_migration import DefaultRoleMigration
|
from bot_data.migration.default_role_migration import DefaultRoleMigration
|
||||||
from bot_data.migration.fix_updates_migration import FixUpdatesMigration
|
from bot_data.migration.fix_updates_migration import FixUpdatesMigration
|
||||||
|
from bot_data.migration.fix_user_history_migration import FixUserHistoryMigration
|
||||||
from bot_data.migration.initial_migration import InitialMigration
|
from bot_data.migration.initial_migration import InitialMigration
|
||||||
from bot_data.migration.level_migration import LevelMigration
|
from bot_data.migration.level_migration import LevelMigration
|
||||||
from bot_data.migration.remove_stats_migration import RemoveStatsMigration
|
from bot_data.migration.remove_stats_migration import RemoveStatsMigration
|
||||||
from bot_data.migration.short_role_name_migration import ShortRoleNameMigration
|
from bot_data.migration.short_role_name_migration import ShortRoleNameMigration
|
||||||
from bot_data.migration.short_role_name_only_highest_migration import ShortRoleNameOnlyHighestMigration
|
from bot_data.migration.short_role_name_only_highest_migration import ShortRoleNameOnlyHighestMigration
|
||||||
from bot_data.migration.stats_migration import StatsMigration
|
from bot_data.migration.stats_migration import StatsMigration
|
||||||
|
from bot_data.migration.steam_special_offer_migration import SteamSpecialOfferMigration
|
||||||
from bot_data.migration.user_joined_game_server_migration import UserJoinedGameServerMigration
|
from bot_data.migration.user_joined_game_server_migration import UserJoinedGameServerMigration
|
||||||
from bot_data.migration.user_message_count_per_hour_migration import (
|
from bot_data.migration.user_message_count_per_hour_migration import (
|
||||||
UserMessageCountPerHourMigration,
|
UserMessageCountPerHourMigration,
|
||||||
@@ -56,3 +59,6 @@ class StartupMigrationExtension(StartupExtensionABC):
|
|||||||
services.add_transient(MigrationABC, ShortRoleNameMigration) # 28.09.2023 #378 - 1.1.7
|
services.add_transient(MigrationABC, ShortRoleNameMigration) # 28.09.2023 #378 - 1.1.7
|
||||||
services.add_transient(MigrationABC, FixUpdatesMigration) # 28.09.2023 #378 - 1.1.7
|
services.add_transient(MigrationABC, FixUpdatesMigration) # 28.09.2023 #378 - 1.1.7
|
||||||
services.add_transient(MigrationABC, ShortRoleNameOnlyHighestMigration) # 02.10.2023 #391 - 1.1.9
|
services.add_transient(MigrationABC, ShortRoleNameOnlyHighestMigration) # 02.10.2023 #391 - 1.1.9
|
||||||
|
services.add_transient(MigrationABC, FixUserHistoryMigration) # 10.10.2023 #401 - 1.2.0
|
||||||
|
services.add_transient(MigrationABC, BirthdayMigration) # 10.10.2023 #401 - 1.2.0
|
||||||
|
services.add_transient(MigrationABC, SteamSpecialOfferMigration) # 10.10.2023 #188 - 1.2.0
|
||||||
|
@@ -94,6 +94,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
|
"special_offers": {
|
||||||
|
"price": "Preis",
|
||||||
|
"discount": "Rabatt",
|
||||||
|
"discount_price": "Neuer Preis"
|
||||||
|
},
|
||||||
"achievements": {
|
"achievements": {
|
||||||
"commands": {
|
"commands": {
|
||||||
"check": "Alles klar, ich schaue eben nach... nom nom"
|
"check": "Alles klar, ich schaue eben nach... nom nom"
|
||||||
@@ -229,6 +234,10 @@
|
|||||||
"success": "Verlinkung wurde entfernt :D"
|
"success": "Verlinkung wurde entfernt :D"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
|
"birthday": {
|
||||||
|
"success": "Dein Geburtstag wurde eingetragen.",
|
||||||
|
"success_team": "{} hat seinen Geburtstag eingetragen: {}"
|
||||||
|
},
|
||||||
"add": {
|
"add": {
|
||||||
"xp": "Die {} von {} wurden um {} erhöht"
|
"xp": "Die {} von {} wurden um {} erhöht"
|
||||||
},
|
},
|
||||||
|
@@ -17,6 +17,7 @@ class FeatureFlagsEnum(Enum):
|
|||||||
moderator_module = "ModeratorModule"
|
moderator_module = "ModeratorModule"
|
||||||
permission_module = "PermissionModule"
|
permission_module = "PermissionModule"
|
||||||
short_role_name_module = "ShortRoleNameModule"
|
short_role_name_module = "ShortRoleNameModule"
|
||||||
|
steam_special_offers_module = "SteamSpecialOffersModule"
|
||||||
# features
|
# features
|
||||||
api_only = "ApiOnly"
|
api_only = "ApiOnly"
|
||||||
presence = "Presence"
|
presence = "Presence"
|
||||||
@@ -25,3 +26,4 @@ class FeatureFlagsEnum(Enum):
|
|||||||
sync_xp = "SyncXp"
|
sync_xp = "SyncXp"
|
||||||
short_role_name = "ShortRoleName"
|
short_role_name = "ShortRoleName"
|
||||||
technician_full_access = "TechnicianFullAccess"
|
technician_full_access = "TechnicianFullAccess"
|
||||||
|
steam_special_offers = "SteamSpecialOffers"
|
||||||
|
@@ -19,6 +19,7 @@ class FeatureFlagsSettings(ConfigurationModelABC):
|
|||||||
FeatureFlagsEnum.permission_module.value: True, # 02.10.2022 #48
|
FeatureFlagsEnum.permission_module.value: True, # 02.10.2022 #48
|
||||||
FeatureFlagsEnum.config_module.value: True, # 19.07.2023 #127
|
FeatureFlagsEnum.config_module.value: True, # 19.07.2023 #127
|
||||||
FeatureFlagsEnum.short_role_name_module.value: True, # 28.09.2023 #378
|
FeatureFlagsEnum.short_role_name_module.value: True, # 28.09.2023 #378
|
||||||
|
FeatureFlagsEnum.steam_special_offers_module.value: True, # 11.10.2023 #188
|
||||||
# features
|
# features
|
||||||
FeatureFlagsEnum.api_only.value: False, # 13.10.2022 #70
|
FeatureFlagsEnum.api_only.value: False, # 13.10.2022 #70
|
||||||
FeatureFlagsEnum.presence.value: True, # 03.10.2022 #56
|
FeatureFlagsEnum.presence.value: True, # 03.10.2022 #56
|
||||||
@@ -27,6 +28,7 @@ class FeatureFlagsSettings(ConfigurationModelABC):
|
|||||||
FeatureFlagsEnum.sync_xp.value: False, # 25.09.2023 #366
|
FeatureFlagsEnum.sync_xp.value: False, # 25.09.2023 #366
|
||||||
FeatureFlagsEnum.short_role_name.value: False, # 28.09.2023 #378
|
FeatureFlagsEnum.short_role_name.value: False, # 28.09.2023 #378
|
||||||
FeatureFlagsEnum.technician_full_access.value: False, # 03.10.2023 #393
|
FeatureFlagsEnum.technician_full_access.value: False, # 03.10.2023 #393
|
||||||
|
FeatureFlagsEnum.steam_special_offers.value: False, # 11.10.2023 #188
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, **kwargs: dict):
|
def __init__(self, **kwargs: dict):
|
||||||
|
15
kdb-bot/src/bot_core/logging/task_logger.py
Normal file
15
kdb-bot/src/bot_core/logging/task_logger.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
from cpl_core.configuration import ConfigurationABC
|
||||||
|
from cpl_core.environment import ApplicationEnvironmentABC
|
||||||
|
from cpl_core.time import TimeFormatSettings
|
||||||
|
|
||||||
|
from bot_core.abc.custom_file_logger_abc import CustomFileLoggerABC
|
||||||
|
|
||||||
|
|
||||||
|
class TaskLogger(CustomFileLoggerABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: ConfigurationABC,
|
||||||
|
time_format: TimeFormatSettings,
|
||||||
|
env: ApplicationEnvironmentABC,
|
||||||
|
):
|
||||||
|
CustomFileLoggerABC.__init__(self, "Task", config, time_format, env)
|
@@ -131,7 +131,7 @@ class ClientUtilsService(ClientUtilsABC):
|
|||||||
if current in sl:
|
if current in sl:
|
||||||
sl = sl.skip(sl.index_of(current))
|
sl = sl.skip(sl.index_of(current))
|
||||||
|
|
||||||
_l = _l.where(lambda x: x.name in sl)
|
_l = _l.where(lambda x: select(x) in sl)
|
||||||
|
|
||||||
return _l.take(25)
|
return _l.take(25)
|
||||||
|
|
||||||
|
@@ -71,7 +71,7 @@ class MessageService(MessageServiceABC):
|
|||||||
async def send_channel_message(
|
async def send_channel_message(
|
||||||
self,
|
self,
|
||||||
channel: discord.TextChannel,
|
channel: discord.TextChannel,
|
||||||
message: Union[str, discord.Embed],
|
message: Union[str, discord.Embed, list[discord.Embed]],
|
||||||
is_persistent: bool = False,
|
is_persistent: bool = False,
|
||||||
wait_before_delete: int = None,
|
wait_before_delete: int = None,
|
||||||
without_tracking=False,
|
without_tracking=False,
|
||||||
@@ -81,6 +81,8 @@ class MessageService(MessageServiceABC):
|
|||||||
try:
|
try:
|
||||||
if isinstance(message, discord.Embed):
|
if isinstance(message, discord.Embed):
|
||||||
msg = await channel.send(embed=message)
|
msg = await channel.send(embed=message)
|
||||||
|
elif isinstance(message, list):
|
||||||
|
msg = await channel.send(embeds=message)
|
||||||
else:
|
else:
|
||||||
msg = await channel.send(message)
|
msg = await channel.send(message)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@@ -0,0 +1,32 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from cpl_query.extension import List
|
||||||
|
|
||||||
|
from bot_data.model.steam_special_offer import SteamSpecialOffer
|
||||||
|
|
||||||
|
|
||||||
|
class SteamSpecialOfferRepositoryABC(ABC):
|
||||||
|
@abstractmethod
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_steam_special_offers(self) -> List[SteamSpecialOffer]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_steam_special_offer_by_name(self, name: str) -> SteamSpecialOffer:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def add_steam_special_offer(self, steam_special_offer: SteamSpecialOffer):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def update_steam_special_offer(self, steam_special_offer: SteamSpecialOffer):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def delete_steam_special_offer(self, steam_special_offer: SteamSpecialOffer):
|
||||||
|
pass
|
@@ -17,6 +17,7 @@ from bot_data.abc.level_repository_abc import LevelRepositoryABC
|
|||||||
from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC
|
from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||||
from bot_data.abc.short_role_name_repository_abc import ShortRoleNameRepositoryABC
|
from bot_data.abc.short_role_name_repository_abc import ShortRoleNameRepositoryABC
|
||||||
|
from bot_data.abc.steam_special_offer_repository_abc import SteamSpecialOfferRepositoryABC
|
||||||
from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC
|
from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC
|
||||||
from bot_data.abc.user_game_ident_repository_abc import UserGameIdentRepositoryABC
|
from bot_data.abc.user_game_ident_repository_abc import UserGameIdentRepositoryABC
|
||||||
from bot_data.abc.user_joined_game_server_repository_abc import UserJoinedGameServerRepositoryABC
|
from bot_data.abc.user_joined_game_server_repository_abc import UserJoinedGameServerRepositoryABC
|
||||||
@@ -43,6 +44,7 @@ from bot_data.service.server_config_repository_service import ServerConfigReposi
|
|||||||
from bot_data.service.server_config_seeder import ServerConfigSeeder
|
from bot_data.service.server_config_seeder import ServerConfigSeeder
|
||||||
from bot_data.service.server_repository_service import ServerRepositoryService
|
from bot_data.service.server_repository_service import ServerRepositoryService
|
||||||
from bot_data.service.short_role_name_repository_service import ShortRoleNameRepositoryService
|
from bot_data.service.short_role_name_repository_service import ShortRoleNameRepositoryService
|
||||||
|
from bot_data.service.steam_special_offer_repository_service import SteamSpecialOfferRepositoryService
|
||||||
from bot_data.service.technician_config_repository_service import TechnicianConfigRepositoryService
|
from bot_data.service.technician_config_repository_service import TechnicianConfigRepositoryService
|
||||||
from bot_data.service.technician_config_seeder import TechnicianConfigSeeder
|
from bot_data.service.technician_config_seeder import TechnicianConfigSeeder
|
||||||
from bot_data.service.user_game_ident_repository_service import UserGameIdentRepositoryService
|
from bot_data.service.user_game_ident_repository_service import UserGameIdentRepositoryService
|
||||||
@@ -92,6 +94,7 @@ class DataModule(ModuleABC):
|
|||||||
services.add_transient(TechnicianConfigRepositoryABC, TechnicianConfigRepositoryService)
|
services.add_transient(TechnicianConfigRepositoryABC, TechnicianConfigRepositoryService)
|
||||||
services.add_transient(ServerConfigRepositoryABC, ServerConfigRepositoryService)
|
services.add_transient(ServerConfigRepositoryABC, ServerConfigRepositoryService)
|
||||||
services.add_transient(ShortRoleNameRepositoryABC, ShortRoleNameRepositoryService)
|
services.add_transient(ShortRoleNameRepositoryABC, ShortRoleNameRepositoryService)
|
||||||
|
services.add_transient(SteamSpecialOfferRepositoryABC, SteamSpecialOfferRepositoryService)
|
||||||
|
|
||||||
services.add_transient(SeederService)
|
services.add_transient(SeederService)
|
||||||
services.add_transient(DataSeederABC, TechnicianConfigSeeder)
|
services.add_transient(DataSeederABC, TechnicianConfigSeeder)
|
||||||
|
84
kdb-bot/src/bot_data/migration/birthday_migration.py
Normal file
84
kdb-bot/src/bot_data/migration/birthday_migration.py
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
from bot_core.logging.database_logger import DatabaseLogger
|
||||||
|
from bot_data.abc.migration_abc import MigrationABC
|
||||||
|
from bot_data.db_context import DBContext
|
||||||
|
|
||||||
|
|
||||||
|
class BirthdayMigration(MigrationABC):
|
||||||
|
name = "1.2.0_BirthdayMigration"
|
||||||
|
|
||||||
|
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"""
|
||||||
|
ALTER TABLE Users
|
||||||
|
ADD Birthday DATE NULL AFTER MessageCount;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE UsersHistory
|
||||||
|
ADD Birthday DATE NULL AFTER MessageCount;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._exec(__file__, "users.sql")
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE CFG_Server
|
||||||
|
ADD XpForBirthday BIGINT(20) NOT NULL DEFAULT 0 AFTER XpPerAchievement;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE CFG_ServerHistory
|
||||||
|
ADD XpForBirthday BIGINT(20) NOT NULL DEFAULT 0 AFTER XpPerAchievement;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._exec(__file__, "config/server.sql")
|
||||||
|
|
||||||
|
def downgrade(self):
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE Users DROP COLUMN Birthday;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE UsersHistory DROP COLUMN Birthday;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE CFG_Server DROP COLUMN XpForBirthday;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE CFG_ServerHistory DROP COLUMN XpForBirthday;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
@@ -6,13 +6,16 @@ ALTER TABLE `Users`
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `UsersHistory`
|
CREATE TABLE IF NOT EXISTS `UsersHistory`
|
||||||
(
|
(
|
||||||
`Id` BIGINT(20) NOT NULL,
|
`Id` BIGINT(20) NOT NULL,
|
||||||
`DiscordId` BIGINT(20) NOT NULL,
|
`DiscordId` BIGINT(20) NOT NULL,
|
||||||
`XP` BIGINT(20) NOT NULL DEFAULT 0,
|
`XP` BIGINT(20) NOT NULL DEFAULT 0,
|
||||||
`ServerId` BIGINT(20) DEFAULT NULL,
|
`ReactionCount` BIGINT(20) NOT NULL DEFAULT 0,
|
||||||
`Deleted` BOOL DEFAULT FALSE,
|
`MessageCount` BIGINT(20) NOT NULL DEFAULT 0,
|
||||||
`DateFrom` DATETIME(6) NOT NULL,
|
`Birthday` DATE NULL,
|
||||||
`DateTo` DATETIME(6) NOT NULL
|
`ServerId` BIGINT(20) DEFAULT NULL,
|
||||||
|
`Deleted` BOOL DEFAULT FALSE,
|
||||||
|
`DateFrom` DATETIME(6) NOT NULL,
|
||||||
|
`DateTo` DATETIME(6) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS `TR_UsersUpdate`;
|
DROP TRIGGER IF EXISTS `TR_UsersUpdate`;
|
||||||
@@ -22,12 +25,10 @@ CREATE TRIGGER `TR_UsersUpdate`
|
|||||||
ON `Users`
|
ON `Users`
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
BEGIN
|
BEGIN
|
||||||
INSERT INTO `UsersHistory` (
|
INSERT INTO `UsersHistory` (`Id`, `DiscordId`, `XP`, `ReactionCount`, `MessageCount`, `Birthday`, `ServerId`,
|
||||||
`Id`, `DiscordId`, `XP`, `ServerId`, `DateFrom`, `DateTo`
|
`DateFrom`, `DateTo`)
|
||||||
)
|
VALUES (OLD.UserId, OLD.DiscordId, OLD.XP, OLD.ReactionCount, OLD.MessageCount, OLD.Birthday, OLD.ServerId,
|
||||||
VALUES (
|
OLD.LastModifiedAt, CURRENT_TIMESTAMP(6));
|
||||||
OLD.UserId, OLD.DiscordId, OLD.XP, OLD.ServerId, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)
|
|
||||||
);
|
|
||||||
END;
|
END;
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS `TR_UsersDelete`;
|
DROP TRIGGER IF EXISTS `TR_UsersDelete`;
|
||||||
@@ -37,10 +38,8 @@ CREATE TRIGGER `TR_UsersDelete`
|
|||||||
ON `Users`
|
ON `Users`
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
BEGIN
|
BEGIN
|
||||||
INSERT INTO `UsersHistory` (
|
INSERT INTO `UsersHistory` (`Id`, `DiscordId`, `XP`, `ReactionCount`, `MessageCount`, `Birthday`, `ServerId`,
|
||||||
`Id`, `DiscordId`, `XP`, `ServerId`, `Deleted`, `DateFrom`, `DateTo`
|
`Deleted`, `DateFrom`, `DateTo`)
|
||||||
)
|
VALUES (OLD.UserId, OLD.DiscordId, OLD.XP, OLD.ReactionCount, OLD.MessageCount, OLD.Birthday, OLD.ServerId, TRUE,
|
||||||
VALUES (
|
OLD.LastModifiedAt, CURRENT_TIMESTAMP(6));
|
||||||
OLD.UserId, OLD.DiscordId, OLD.XP, OLD.ServerId, TRUE, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)
|
|
||||||
);
|
|
||||||
END;
|
END;
|
45
kdb-bot/src/bot_data/migration/fix_user_history_migration.py
Normal file
45
kdb-bot/src/bot_data/migration/fix_user_history_migration.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
from bot_core.logging.database_logger import DatabaseLogger
|
||||||
|
from bot_data.abc.migration_abc import MigrationABC
|
||||||
|
from bot_data.db_context import DBContext
|
||||||
|
|
||||||
|
|
||||||
|
class FixUserHistoryMigration(MigrationABC):
|
||||||
|
name = "1.2.0_FixUserHistoryMigration"
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# fix 1.1.0_AchievementsMigration
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""ALTER TABLE UsersHistory ADD COLUMN IF NOT EXISTS ReactionCount BIGINT NOT NULL DEFAULT 0 AFTER XP;"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""ALTER TABLE UsersHistory ADD COLUMN IF NOT EXISTS MessageCount BIGINT NOT NULL DEFAULT 0 AFTER ReactionCount;"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._exec(__file__, "users.sql")
|
||||||
|
|
||||||
|
def downgrade(self):
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE UsersHistory DROP COLUMN MessageCount;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE UsersHistory DROP COLUMN ReactionCount;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
@@ -0,0 +1,68 @@
|
|||||||
|
from bot_core.logging.database_logger import DatabaseLogger
|
||||||
|
from bot_data.abc.migration_abc import MigrationABC
|
||||||
|
from bot_data.db_context import DBContext
|
||||||
|
|
||||||
|
|
||||||
|
class SteamSpecialOfferMigration(MigrationABC):
|
||||||
|
name = "1.2.0_SteamSpecialOfferMigration"
|
||||||
|
|
||||||
|
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 `SteamSpecialOffers` (
|
||||||
|
`Id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`Game` VARCHAR(255) NOT NULL,
|
||||||
|
`OriginalPrice` FLOAT NOT NULL,
|
||||||
|
`DiscountPrice` FLOAT NOT NULL,
|
||||||
|
`DiscountPct` BIGINT NOT NULL,
|
||||||
|
`CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||||
|
`LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||||
|
PRIMARY KEY(`Id`)
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE CFG_Server
|
||||||
|
ADD COLUMN IF NOT EXISTS GameOfferNotificationChatId BIGINT NULL AFTER ShortRoleNameSetOnlyHighest;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE CFG_ServerHistory
|
||||||
|
ADD COLUMN IF NOT EXISTS GameOfferNotificationChatId BIGINT NULL AFTER ShortRoleNameSetOnlyHighest;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def downgrade(self):
|
||||||
|
self._cursor.execute("DROP TABLE `SteamSpecialOffers`;")
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE CFG_Server DROP COLUMN ShortRoleNameSetOnlyHighest;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._cursor.execute(
|
||||||
|
str(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE CFG_ServerHistory DROP COLUMN ShortRoleNameSetOnlyHighest;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
@@ -24,12 +24,14 @@ class ServerConfig(TableABC, ConfigurationModelABC):
|
|||||||
xp_per_ontime_hour: int,
|
xp_per_ontime_hour: int,
|
||||||
xp_per_event_participation: int,
|
xp_per_event_participation: int,
|
||||||
xp_per_achievement: int,
|
xp_per_achievement: int,
|
||||||
|
xp_for_birthday: int,
|
||||||
afk_command_channel_id: int,
|
afk_command_channel_id: int,
|
||||||
help_voice_channel_id: int,
|
help_voice_channel_id: int,
|
||||||
team_channel_id: int,
|
team_channel_id: int,
|
||||||
login_message_channel_id: int,
|
login_message_channel_id: int,
|
||||||
default_role_id: Optional[int],
|
default_role_id: Optional[int],
|
||||||
short_role_name_only_set_highest_role: bool,
|
short_role_name_only_set_highest_role: bool,
|
||||||
|
game_offer_notification_chat_id: int,
|
||||||
feature_flags: dict[FeatureFlagsEnum],
|
feature_flags: dict[FeatureFlagsEnum],
|
||||||
server: Server,
|
server: Server,
|
||||||
afk_channel_ids: List[int],
|
afk_channel_ids: List[int],
|
||||||
@@ -48,12 +50,14 @@ class ServerConfig(TableABC, ConfigurationModelABC):
|
|||||||
self._xp_per_ontime_hour = xp_per_ontime_hour
|
self._xp_per_ontime_hour = xp_per_ontime_hour
|
||||||
self._xp_per_event_participation = xp_per_event_participation
|
self._xp_per_event_participation = xp_per_event_participation
|
||||||
self._xp_per_achievement = xp_per_achievement
|
self._xp_per_achievement = xp_per_achievement
|
||||||
|
self._xp_for_birthday = xp_for_birthday
|
||||||
self._afk_command_channel_id = afk_command_channel_id
|
self._afk_command_channel_id = afk_command_channel_id
|
||||||
self._help_voice_channel_id = help_voice_channel_id
|
self._help_voice_channel_id = help_voice_channel_id
|
||||||
self._team_channel_id = team_channel_id
|
self._team_channel_id = team_channel_id
|
||||||
self._login_message_channel_id = login_message_channel_id
|
self._login_message_channel_id = login_message_channel_id
|
||||||
self._default_role_id = default_role_id
|
self._default_role_id = default_role_id
|
||||||
self._short_role_name_only_set_highest_role = short_role_name_only_set_highest_role
|
self._short_role_name_only_set_highest_role = short_role_name_only_set_highest_role
|
||||||
|
self._game_offer_notification_chat_id = game_offer_notification_chat_id
|
||||||
|
|
||||||
self._feature_flags = feature_flags
|
self._feature_flags = feature_flags
|
||||||
self._server = server
|
self._server = server
|
||||||
@@ -76,12 +80,14 @@ class ServerConfig(TableABC, ConfigurationModelABC):
|
|||||||
10,
|
10,
|
||||||
10,
|
10,
|
||||||
10,
|
10,
|
||||||
|
10,
|
||||||
guild.system_channel.id,
|
guild.system_channel.id,
|
||||||
guild.system_channel.id,
|
guild.system_channel.id,
|
||||||
guild.system_channel.id,
|
guild.system_channel.id,
|
||||||
guild.system_channel.id,
|
guild.system_channel.id,
|
||||||
None,
|
None,
|
||||||
False,
|
False,
|
||||||
|
guild.system_channel.id,
|
||||||
{},
|
{},
|
||||||
server,
|
server,
|
||||||
List(int),
|
List(int),
|
||||||
@@ -164,6 +170,14 @@ class ServerConfig(TableABC, ConfigurationModelABC):
|
|||||||
def xp_per_achievement(self, value: int):
|
def xp_per_achievement(self, value: int):
|
||||||
self._xp_per_achievement = value
|
self._xp_per_achievement = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def xp_for_birthday(self) -> int:
|
||||||
|
return self._xp_for_birthday
|
||||||
|
|
||||||
|
@xp_for_birthday.setter
|
||||||
|
def xp_for_birthday(self, value: int):
|
||||||
|
self._xp_for_birthday = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def afk_command_channel_id(self) -> int:
|
def afk_command_channel_id(self) -> int:
|
||||||
return self._afk_command_channel_id
|
return self._afk_command_channel_id
|
||||||
@@ -212,6 +226,14 @@ class ServerConfig(TableABC, ConfigurationModelABC):
|
|||||||
def short_role_name_only_set_highest_role(self, value: bool):
|
def short_role_name_only_set_highest_role(self, value: bool):
|
||||||
self._short_role_name_only_set_highest_role = value
|
self._short_role_name_only_set_highest_role = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def game_offer_notification_chat_id(self) -> int:
|
||||||
|
return self._game_offer_notification_chat_id
|
||||||
|
|
||||||
|
@game_offer_notification_chat_id.setter
|
||||||
|
def game_offer_notification_chat_id(self, value: int):
|
||||||
|
self._game_offer_notification_chat_id = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def feature_flags(self) -> dict[FeatureFlagsEnum]:
|
def feature_flags(self) -> dict[FeatureFlagsEnum]:
|
||||||
return self._feature_flags
|
return self._feature_flags
|
||||||
@@ -280,12 +302,14 @@ class ServerConfig(TableABC, ConfigurationModelABC):
|
|||||||
`XpPerOntimeHour`,
|
`XpPerOntimeHour`,
|
||||||
`XpPerEventParticipation`,
|
`XpPerEventParticipation`,
|
||||||
`XpPerAchievement`,
|
`XpPerAchievement`,
|
||||||
|
`XpForBirthday`,
|
||||||
`AFKCommandChannelId`,
|
`AFKCommandChannelId`,
|
||||||
`HelpVoiceChannelId`,
|
`HelpVoiceChannelId`,
|
||||||
`TeamChannelId`,
|
`TeamChannelId`,
|
||||||
`LoginMessageChannelId`,
|
`LoginMessageChannelId`,
|
||||||
`DefaultRoleId`,
|
`DefaultRoleId`,
|
||||||
`ShortRoleNameSetOnlyHighest`,
|
`ShortRoleNameSetOnlyHighest`,
|
||||||
|
`GameOfferNotificationChatId`,
|
||||||
`FeatureFlags`,
|
`FeatureFlags`,
|
||||||
`ServerId`
|
`ServerId`
|
||||||
) VALUES (
|
) VALUES (
|
||||||
@@ -298,12 +322,14 @@ class ServerConfig(TableABC, ConfigurationModelABC):
|
|||||||
{self._xp_per_ontime_hour},
|
{self._xp_per_ontime_hour},
|
||||||
{self._xp_per_event_participation},
|
{self._xp_per_event_participation},
|
||||||
{self._xp_per_achievement},
|
{self._xp_per_achievement},
|
||||||
|
'{self._xp_for_birthday}',
|
||||||
{self._afk_command_channel_id},
|
{self._afk_command_channel_id},
|
||||||
{self._help_voice_channel_id},
|
{self._help_voice_channel_id},
|
||||||
{self._team_channel_id},
|
{self._team_channel_id},
|
||||||
{self._login_message_channel_id},
|
{self._login_message_channel_id},
|
||||||
{"NULL" if self._default_role_id is None else self._default_role_id},
|
{"NULL" if self._default_role_id is None else self._default_role_id},
|
||||||
{self._short_role_name_only_set_highest_role},
|
{self._short_role_name_only_set_highest_role},
|
||||||
|
{self._game_offer_notification_chat_id},
|
||||||
'{json.dumps(self._feature_flags)}',
|
'{json.dumps(self._feature_flags)}',
|
||||||
{self._server.id}
|
{self._server.id}
|
||||||
);
|
);
|
||||||
@@ -324,12 +350,14 @@ class ServerConfig(TableABC, ConfigurationModelABC):
|
|||||||
`XpPerOntimeHour` = {self._xp_per_ontime_hour},
|
`XpPerOntimeHour` = {self._xp_per_ontime_hour},
|
||||||
`XpPerEventParticipation` = {self._xp_per_event_participation},
|
`XpPerEventParticipation` = {self._xp_per_event_participation},
|
||||||
`XpPerAchievement` = {self._xp_per_achievement},
|
`XpPerAchievement` = {self._xp_per_achievement},
|
||||||
|
`XpForBirthday` = {self._xp_for_birthday},
|
||||||
`AFKCommandChannelId` = {self._afk_command_channel_id},
|
`AFKCommandChannelId` = {self._afk_command_channel_id},
|
||||||
`HelpVoiceChannelId` = {self._help_voice_channel_id},
|
`HelpVoiceChannelId` = {self._help_voice_channel_id},
|
||||||
`TeamChannelId` = {self._team_channel_id},
|
`TeamChannelId` = {self._team_channel_id},
|
||||||
`LoginMessageChannelId` = {self._login_message_channel_id},
|
`LoginMessageChannelId` = {self._login_message_channel_id},
|
||||||
`DefaultRoleId` = {"NULL" if self._default_role_id is None else self._default_role_id},
|
`DefaultRoleId` = {"NULL" if self._default_role_id is None else self._default_role_id},
|
||||||
`ShortRoleNameSetOnlyHighest` = {self._short_role_name_only_set_highest_role},
|
`ShortRoleNameSetOnlyHighest` = {self._short_role_name_only_set_highest_role},
|
||||||
|
`GameOfferNotificationChatId` = {self._game_offer_notification_chat_id},
|
||||||
`FeatureFlags` = '{json.dumps(self._feature_flags)}',
|
`FeatureFlags` = '{json.dumps(self._feature_flags)}',
|
||||||
`ServerId` = {self._server.id}
|
`ServerId` = {self._server.id}
|
||||||
WHERE `Id` = {self._id};
|
WHERE `Id` = {self._id};
|
||||||
|
115
kdb-bot/src/bot_data/model/steam_special_offer.py
Normal file
115
kdb-bot/src/bot_data/model/steam_special_offer.py
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from cpl_core.database import TableABC
|
||||||
|
|
||||||
|
|
||||||
|
class SteamSpecialOffer(TableABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
original_price: float,
|
||||||
|
discount_price: float,
|
||||||
|
discount_pct: int,
|
||||||
|
created_at: datetime = None,
|
||||||
|
modified_at: datetime = None,
|
||||||
|
id=0,
|
||||||
|
):
|
||||||
|
self._id = id
|
||||||
|
self._name = name
|
||||||
|
self._original_price = original_price
|
||||||
|
self._discount_price = discount_price
|
||||||
|
self._discount_pct = discount_pct
|
||||||
|
|
||||||
|
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 name(self) -> str:
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, value: str):
|
||||||
|
self._name = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def original_price(self) -> float:
|
||||||
|
return self._original_price
|
||||||
|
|
||||||
|
@original_price.setter
|
||||||
|
def original_price(self, value: float):
|
||||||
|
self._original_price = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def discount_price(self) -> float:
|
||||||
|
return self._discount_price
|
||||||
|
|
||||||
|
@discount_price.setter
|
||||||
|
def discount_price(self, value: float):
|
||||||
|
self._discount_price = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def discount_pct(self) -> int:
|
||||||
|
return self._discount_pct
|
||||||
|
|
||||||
|
@discount_pct.setter
|
||||||
|
def discount_pct(self, value: int):
|
||||||
|
self._discount_pct = value
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_select_all_string() -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
SELECT * FROM `SteamSpecialOffers`;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_select_by_name_string(name: str) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
SELECT * FROM `SteamSpecialOffers`
|
||||||
|
WHERE `Game` = '{name}';
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def insert_string(self) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
INSERT INTO `SteamSpecialOffers` (
|
||||||
|
`Game`, `OriginalPrice`, `DiscountPrice`, `DiscountPct`
|
||||||
|
) VALUES (
|
||||||
|
'{self._name}',
|
||||||
|
{self._original_price},
|
||||||
|
{self._discount_price},
|
||||||
|
{self._discount_pct}
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def udpate_string(self) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
UPDATE `SteamSpecialOffers`
|
||||||
|
SET `Game` = '{self._name}',
|
||||||
|
`OriginalPrice` = {self._original_price},
|
||||||
|
`DiscountPrice` = {self._discount_price},
|
||||||
|
`DiscountPct` = {self._discount_pct}
|
||||||
|
WHERE `Id` = {self._id};
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def delete_string(self) -> str:
|
||||||
|
return str(
|
||||||
|
f"""
|
||||||
|
DELETE FROM `SteamSpecialOffers`
|
||||||
|
WHERE `Id` = {self._id};
|
||||||
|
"""
|
||||||
|
)
|
@@ -1,4 +1,4 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime, date
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from cpl_core.database import TableABC
|
from cpl_core.database import TableABC
|
||||||
@@ -17,6 +17,7 @@ class User(TableABC):
|
|||||||
xp: int,
|
xp: int,
|
||||||
reaction_count: int,
|
reaction_count: int,
|
||||||
message_count: int,
|
message_count: int,
|
||||||
|
birthday: Optional[date],
|
||||||
server: Optional[Server],
|
server: Optional[Server],
|
||||||
created_at: datetime = None,
|
created_at: datetime = None,
|
||||||
modified_at: datetime = None,
|
modified_at: datetime = None,
|
||||||
@@ -27,6 +28,7 @@ class User(TableABC):
|
|||||||
self._xp = xp
|
self._xp = xp
|
||||||
self._reaction_count = reaction_count
|
self._reaction_count = reaction_count
|
||||||
self._message_count = message_count
|
self._message_count = message_count
|
||||||
|
self._birthday = birthday
|
||||||
self._server = server
|
self._server = server
|
||||||
|
|
||||||
TableABC.__init__(self)
|
TableABC.__init__(self)
|
||||||
@@ -79,6 +81,14 @@ class User(TableABC):
|
|||||||
def reaction_count(self, value: int):
|
def reaction_count(self, value: int):
|
||||||
self._reaction_count = value
|
self._reaction_count = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def birthday(self) -> Optional[datetime]:
|
||||||
|
return self._birthday
|
||||||
|
|
||||||
|
@birthday.setter
|
||||||
|
def birthday(self, value: Optional[datetime]):
|
||||||
|
self._birthday = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ServiceProviderABC.inject
|
@ServiceProviderABC.inject
|
||||||
def ontime(self, services: ServiceProviderABC) -> float:
|
def ontime(self, services: ServiceProviderABC) -> float:
|
||||||
@@ -171,12 +181,13 @@ class User(TableABC):
|
|||||||
return str(
|
return str(
|
||||||
f"""
|
f"""
|
||||||
INSERT INTO `Users` (
|
INSERT INTO `Users` (
|
||||||
`DiscordId`, `XP`, `MessageCount`, `ReactionCount`, `ServerId`
|
`DiscordId`, `XP`, `MessageCount`, `ReactionCount`, `Birthday`, `ServerId`
|
||||||
) VALUES (
|
) VALUES (
|
||||||
{self._discord_id},
|
{self._discord_id},
|
||||||
{self._xp},
|
{self._xp},
|
||||||
{self._message_count},
|
{self._message_count},
|
||||||
{self._reaction_count},
|
{self._reaction_count},
|
||||||
|
'{self._birthday}',
|
||||||
{self._server.id}
|
{self._server.id}
|
||||||
);
|
);
|
||||||
"""
|
"""
|
||||||
@@ -189,7 +200,8 @@ class User(TableABC):
|
|||||||
UPDATE `Users`
|
UPDATE `Users`
|
||||||
SET `XP` = {self._xp},
|
SET `XP` = {self._xp},
|
||||||
`MessageCount` = {self._message_count},
|
`MessageCount` = {self._message_count},
|
||||||
`ReactionCount` = {self._reaction_count}
|
`ReactionCount` = {self._reaction_count},
|
||||||
|
`Birthday` = '{self._birthday}'
|
||||||
WHERE `UserId` = {self._user_id};
|
WHERE `UserId` = {self._user_id};
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
43
kdb-bot/src/bot_data/model/user_warnings_history.py
Normal file
43
kdb-bot/src/bot_data/model/user_warnings_history.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from bot_data.abc.history_table_abc import HistoryTableABC
|
||||||
|
|
||||||
|
|
||||||
|
# had to name it UserWarnings instead of UserWarning because UserWarning is a builtin class
|
||||||
|
class UserWarningsHistory(HistoryTableABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
description: str,
|
||||||
|
user: int,
|
||||||
|
author: Optional[int],
|
||||||
|
deleted: bool,
|
||||||
|
date_from: str,
|
||||||
|
date_to: str,
|
||||||
|
id=0,
|
||||||
|
):
|
||||||
|
HistoryTableABC.__init__(self)
|
||||||
|
|
||||||
|
self._id = id
|
||||||
|
self._description = description
|
||||||
|
self._user = user
|
||||||
|
self._author = author
|
||||||
|
|
||||||
|
self._deleted = deleted
|
||||||
|
self._date_from = date_from
|
||||||
|
self._date_to = date_to
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self) -> int:
|
||||||
|
return self._id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self) -> str:
|
||||||
|
return self._description
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user(self) -> int:
|
||||||
|
return self._user
|
||||||
|
|
||||||
|
@property
|
||||||
|
def author(self) -> Optional[int]:
|
||||||
|
return self._author
|
@@ -66,12 +66,14 @@ class ServerConfigRepositoryService(ServerConfigRepositoryABC):
|
|||||||
result[13],
|
result[13],
|
||||||
result[14],
|
result[14],
|
||||||
result[15],
|
result[15],
|
||||||
json.loads(result[16]),
|
result[16],
|
||||||
self._servers.get_server_by_id(result[17]),
|
result[17],
|
||||||
self._get_afk_channel_ids(result[17]),
|
json.loads(result[18]),
|
||||||
self._get_team_role_ids(result[17]),
|
self._servers.get_server_by_id(result[19]),
|
||||||
result[18],
|
self._get_afk_channel_ids(result[19]),
|
||||||
result[19],
|
self._get_team_role_ids(result[19]),
|
||||||
|
result[20],
|
||||||
|
result[21],
|
||||||
id=result[0],
|
id=result[0],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -0,0 +1,68 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
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.server_repository_abc import ServerRepositoryABC
|
||||||
|
from bot_data.abc.steam_special_offer_repository_abc import SteamSpecialOfferRepositoryABC
|
||||||
|
from bot_data.model.steam_special_offer import SteamSpecialOffer
|
||||||
|
|
||||||
|
|
||||||
|
class SteamSpecialOfferRepositoryService(SteamSpecialOfferRepositoryABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
logger: DatabaseLogger,
|
||||||
|
db_context: DatabaseContextABC,
|
||||||
|
servers: ServerRepositoryABC,
|
||||||
|
):
|
||||||
|
self._logger = logger
|
||||||
|
self._context = db_context
|
||||||
|
|
||||||
|
self._servers = servers
|
||||||
|
|
||||||
|
SteamSpecialOfferRepositoryABC.__init__(self)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_value_from_result(value: any) -> Optional[any]:
|
||||||
|
if isinstance(value, str) and "NULL" in value:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
def _steam_special_offer_from_result(self, sql_result: tuple) -> SteamSpecialOffer:
|
||||||
|
return SteamSpecialOffer(
|
||||||
|
self._get_value_from_result(sql_result[1]), # name
|
||||||
|
float(self._get_value_from_result(sql_result[2])), # original_price
|
||||||
|
float(self._get_value_from_result(sql_result[3])), # discount_price
|
||||||
|
int(self._get_value_from_result(sql_result[4])), # discount_pct
|
||||||
|
id=self._get_value_from_result(sql_result[0]), # id
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_steam_special_offers(self) -> List[SteamSpecialOffer]:
|
||||||
|
steam_special_offers = List(SteamSpecialOffer)
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {SteamSpecialOffer.get_select_all_string()}")
|
||||||
|
results = self._context.select(SteamSpecialOffer.get_select_all_string())
|
||||||
|
for result in results:
|
||||||
|
self._logger.trace(__name__, f"Get steam_special_offer with id {result[0]}")
|
||||||
|
steam_special_offers.append(self._steam_special_offer_from_result(result))
|
||||||
|
|
||||||
|
return steam_special_offers
|
||||||
|
|
||||||
|
def get_steam_special_offer_by_name(self, name: str) -> SteamSpecialOffer:
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {SteamSpecialOffer.get_select_by_name_string(name)}")
|
||||||
|
result = self._context.select(SteamSpecialOffer.get_select_by_name_string(name))[0]
|
||||||
|
|
||||||
|
return self._steam_special_offer_from_result(result)
|
||||||
|
|
||||||
|
def add_steam_special_offer(self, steam_special_offer: SteamSpecialOffer):
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {steam_special_offer.insert_string}")
|
||||||
|
self._context.cursor.execute(steam_special_offer.insert_string)
|
||||||
|
|
||||||
|
def update_steam_special_offer(self, steam_special_offer: SteamSpecialOffer):
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {steam_special_offer.udpate_string}")
|
||||||
|
self._context.cursor.execute(steam_special_offer.udpate_string)
|
||||||
|
|
||||||
|
def delete_steam_special_offer(self, steam_special_offer: SteamSpecialOffer):
|
||||||
|
self._logger.trace(__name__, f"Send SQL command: {steam_special_offer.delete_string}")
|
||||||
|
self._context.cursor.execute(steam_special_offer.delete_string)
|
@@ -29,9 +29,10 @@ class UserRepositoryService(UserRepositoryABC):
|
|||||||
result[2],
|
result[2],
|
||||||
result[3],
|
result[3],
|
||||||
result[4],
|
result[4],
|
||||||
self._servers.get_server_by_id(result[5]),
|
result[5].strftime("%d.%m.%Y") if result[5] is not None else None,
|
||||||
result[6],
|
self._servers.get_server_by_id(result[6]),
|
||||||
result[7],
|
result[7],
|
||||||
|
result[8],
|
||||||
id=result[0],
|
id=result[0],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -32,7 +32,7 @@ class UserWarningsRepositoryService(UserWarningsRepositoryABC):
|
|||||||
def _from_result(self, sql_result: tuple) -> UserWarnings:
|
def _from_result(self, sql_result: tuple) -> UserWarnings:
|
||||||
user = self._users.get_user_by_id(self._get_value_from_result(sql_result[2]))
|
user = self._users.get_user_by_id(self._get_value_from_result(sql_result[2]))
|
||||||
author = None
|
author = None
|
||||||
author_id = self._get_value_from_result(sql_result[2])
|
author_id = self._get_value_from_result(sql_result[3])
|
||||||
if author_id is not None:
|
if author_id is not None:
|
||||||
author = self._users.get_user_by_id(author_id)
|
author = self._users.get_user_by_id(author_id)
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
from cpl_core.dependency_injection import ServiceProviderABC
|
||||||
from cpl_query.extension import List
|
from cpl_query.extension import List
|
||||||
|
|
||||||
from bot_data.model.user import User
|
from bot_data.model.user import User
|
||||||
@@ -5,9 +6,14 @@ from bot_graphql.abc.filter_abc import FilterABC
|
|||||||
|
|
||||||
|
|
||||||
class AchievementFilter(FilterABC):
|
class AchievementFilter(FilterABC):
|
||||||
def __init__(self):
|
def __init__(
|
||||||
|
self,
|
||||||
|
services: ServiceProviderABC,
|
||||||
|
):
|
||||||
FilterABC.__init__(self)
|
FilterABC.__init__(self)
|
||||||
|
|
||||||
|
self._services = services
|
||||||
|
|
||||||
self._id = None
|
self._id = None
|
||||||
self._name = None
|
self._name = None
|
||||||
self._description = None
|
self._description = None
|
||||||
|
56
kdb-bot/src/bot_graphql/filter/user_warning_filter.py
Normal file
56
kdb-bot/src/bot_graphql/filter/user_warning_filter.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
from cpl_core.dependency_injection import ServiceProviderABC
|
||||||
|
from cpl_query.extension import List
|
||||||
|
|
||||||
|
from bot_data.model.user_warnings import UserWarnings
|
||||||
|
from bot_graphql.abc.filter_abc import FilterABC
|
||||||
|
|
||||||
|
|
||||||
|
class UserWarningFilter(FilterABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
services: ServiceProviderABC,
|
||||||
|
):
|
||||||
|
FilterABC.__init__(self)
|
||||||
|
|
||||||
|
self._services = services
|
||||||
|
|
||||||
|
self._id = None
|
||||||
|
self._user = None
|
||||||
|
self._description = None
|
||||||
|
self._author = None
|
||||||
|
|
||||||
|
def from_dict(self, values: dict):
|
||||||
|
if "id" in values:
|
||||||
|
self._id = int(values["id"])
|
||||||
|
|
||||||
|
if "user" in values:
|
||||||
|
from bot_graphql.filter.user_filter import UserFilter
|
||||||
|
|
||||||
|
self._user: UserFilter = self._services.get_service(UserFilter)
|
||||||
|
self._user.from_dict(values["user"])
|
||||||
|
|
||||||
|
if "description" in values:
|
||||||
|
self._description = values["description"]
|
||||||
|
|
||||||
|
if "author" in values:
|
||||||
|
from bot_graphql.filter.user_filter import UserFilter
|
||||||
|
|
||||||
|
self._author: UserFilter = self._services.get_service(UserFilter)
|
||||||
|
self._author.from_dict(values["author"])
|
||||||
|
|
||||||
|
def filter(self, query: List[UserWarnings]) -> List[UserWarnings]:
|
||||||
|
if self._id is not None:
|
||||||
|
query = query.where(lambda x: x.id == self._id)
|
||||||
|
|
||||||
|
if self._user is not None:
|
||||||
|
users = self._user.filter(query.select(lambda x: x.user)).select(lambda x: x.id)
|
||||||
|
query = query.where(lambda x: x.id in users)
|
||||||
|
|
||||||
|
if self._description is not None:
|
||||||
|
query = query.where(lambda x: x.description == self._description or self._description in x.description)
|
||||||
|
|
||||||
|
if self._author is not None:
|
||||||
|
users = self._author.filter(query.select(lambda x: x.author)).select(lambda x: x.id)
|
||||||
|
query = query.where(lambda x: x.id in users)
|
||||||
|
|
||||||
|
return query
|
@@ -41,6 +41,9 @@ type Query {
|
|||||||
shortRoleNames(filter: ShortRoleNameFilter, page: Page, sort: Sort): [ShortRoleName]
|
shortRoleNames(filter: ShortRoleNameFilter, page: Page, sort: Sort): [ShortRoleName]
|
||||||
shortRoleNamePositions: [String]
|
shortRoleNamePositions: [String]
|
||||||
|
|
||||||
|
userWarningCount: Int
|
||||||
|
userWarnings(filter: UserWarningFilter, page: Page, sort: Sort): [UserWarning]
|
||||||
|
|
||||||
technicianConfig: TechnicianConfig
|
technicianConfig: TechnicianConfig
|
||||||
possibleFeatureFlags: [String]
|
possibleFeatureFlags: [String]
|
||||||
discord: Discord
|
discord: Discord
|
||||||
|
@@ -9,12 +9,14 @@ type ServerConfig implements TableWithHistoryQuery {
|
|||||||
xpPerOntimeHour: Int
|
xpPerOntimeHour: Int
|
||||||
xpPerEventParticipation: Int
|
xpPerEventParticipation: Int
|
||||||
xpPerAchievement: Int
|
xpPerAchievement: Int
|
||||||
|
xpForBirthday: Int
|
||||||
afkCommandChannelId: String
|
afkCommandChannelId: String
|
||||||
helpVoiceChannelId: String
|
helpVoiceChannelId: String
|
||||||
teamChannelId: String
|
teamChannelId: String
|
||||||
loginMessageChannelId: String
|
loginMessageChannelId: String
|
||||||
defaultRoleId: String
|
defaultRoleId: String
|
||||||
shortRoleNameOnlySetHighestRole: Boolean
|
shortRoleNameOnlySetHighestRole: Boolean
|
||||||
|
gameOfferNotificationChatId: String
|
||||||
featureFlagCount: Int
|
featureFlagCount: Int
|
||||||
featureFlags: [FeatureFlag]
|
featureFlags: [FeatureFlag]
|
||||||
|
|
||||||
@@ -41,12 +43,14 @@ type ServerConfigHistory implements HistoryTableQuery {
|
|||||||
xpPerOntimeHour: Int
|
xpPerOntimeHour: Int
|
||||||
xpPerEventParticipation: Int
|
xpPerEventParticipation: Int
|
||||||
xpPerAchievement: Int
|
xpPerAchievement: Int
|
||||||
|
xpForBirthday: Int
|
||||||
afkCommandChannelId: String
|
afkCommandChannelId: String
|
||||||
helpVoiceChannelId: String
|
helpVoiceChannelId: String
|
||||||
teamChannelId: String
|
teamChannelId: String
|
||||||
loginMessageChannelId: String
|
loginMessageChannelId: String
|
||||||
defaultRoleId: String
|
defaultRoleId: String
|
||||||
shortRoleNameOnlySetHighestRole: Boolean
|
shortRoleNameOnlySetHighestRole: Boolean
|
||||||
|
gameOfferNotificationChatId: String
|
||||||
featureFlagCount: Int
|
featureFlagCount: Int
|
||||||
featureFlags: [FeatureFlag]
|
featureFlags: [FeatureFlag]
|
||||||
|
|
||||||
@@ -91,12 +95,14 @@ input ServerConfigInput {
|
|||||||
xpPerOntimeHour: Int
|
xpPerOntimeHour: Int
|
||||||
xpPerEventParticipation: Int
|
xpPerEventParticipation: Int
|
||||||
xpPerAchievement: Int
|
xpPerAchievement: Int
|
||||||
|
xpForBirthday: Int
|
||||||
afkCommandChannelId: String
|
afkCommandChannelId: String
|
||||||
helpVoiceChannelId: String
|
helpVoiceChannelId: String
|
||||||
teamChannelId: String
|
teamChannelId: String
|
||||||
loginMessageChannelId: String
|
loginMessageChannelId: String
|
||||||
defaultRoleId: String
|
defaultRoleId: String
|
||||||
shortRoleNameOnlySetHighestRole: Boolean
|
shortRoleNameOnlySetHighestRole: Boolean
|
||||||
|
gameOfferNotificationChatId: String
|
||||||
featureFlags: [FeatureFlagInput]
|
featureFlags: [FeatureFlagInput]
|
||||||
|
|
||||||
afkChannelIds: [String]
|
afkChannelIds: [String]
|
||||||
|
@@ -5,6 +5,7 @@ type User implements TableWithHistoryQuery {
|
|||||||
xp: Int
|
xp: Int
|
||||||
messageCount: Int
|
messageCount: Int
|
||||||
reactionCount: Int
|
reactionCount: Int
|
||||||
|
birthday: String
|
||||||
ontime: Float
|
ontime: Float
|
||||||
level: Level
|
level: Level
|
||||||
|
|
||||||
@@ -20,6 +21,9 @@ type User implements TableWithHistoryQuery {
|
|||||||
achievementCount: Int
|
achievementCount: Int
|
||||||
achievements(filter: AchievementFilter, page: Page, sort: Sort): [Achievement]
|
achievements(filter: AchievementFilter, page: Page, sort: Sort): [Achievement]
|
||||||
|
|
||||||
|
userWarningCount: Int
|
||||||
|
userWarnings(filter: UserWarningFilter, page: Page, sort: Sort): [UserWarning]
|
||||||
|
|
||||||
server: Server
|
server: Server
|
||||||
leftServer: Boolean
|
leftServer: Boolean
|
||||||
|
|
||||||
@@ -59,5 +63,7 @@ type UserMutation {
|
|||||||
input UserInput {
|
input UserInput {
|
||||||
id: ID
|
id: ID
|
||||||
xp: Int
|
xp: Int
|
||||||
|
birthday: String
|
||||||
levelId: ID
|
levelId: ID
|
||||||
|
userWarnings: [UserWarningInput]
|
||||||
}
|
}
|
34
kdb-bot/src/bot_graphql/graphql/userWarning.gql
Normal file
34
kdb-bot/src/bot_graphql/graphql/userWarning.gql
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
type UserWarning implements TableWithHistoryQuery {
|
||||||
|
id: ID
|
||||||
|
user: User
|
||||||
|
description: String
|
||||||
|
author: User
|
||||||
|
|
||||||
|
createdAt: String
|
||||||
|
modifiedAt: String
|
||||||
|
|
||||||
|
history: [UserWarningHistory]
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserWarningHistory implements HistoryTableQuery {
|
||||||
|
id: ID
|
||||||
|
user: ID
|
||||||
|
description: String
|
||||||
|
author: ID
|
||||||
|
|
||||||
|
deleted: Boolean
|
||||||
|
dateFrom: String
|
||||||
|
dateTo: String
|
||||||
|
}
|
||||||
|
|
||||||
|
input UserWarningFilter {
|
||||||
|
id: ID
|
||||||
|
user: UserFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
input UserWarningInput {
|
||||||
|
id: ID
|
||||||
|
user: ID
|
||||||
|
description: String
|
||||||
|
author: ID
|
||||||
|
}
|
@@ -18,6 +18,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 bot_graphql.filter.user_warning_filter import UserWarningFilter
|
||||||
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.achievement_mutation import AchievementMutation
|
||||||
@@ -66,6 +67,8 @@ from bot_graphql.queries.user_joined_server_query import UserJoinedServerQuery
|
|||||||
from bot_graphql.queries.user_joined_voice_channel_history_query import UserJoinedVoiceChannelHistoryQuery
|
from bot_graphql.queries.user_joined_voice_channel_history_query import UserJoinedVoiceChannelHistoryQuery
|
||||||
from bot_graphql.queries.user_joined_voice_channel_query import UserJoinedVoiceChannelQuery
|
from bot_graphql.queries.user_joined_voice_channel_query import UserJoinedVoiceChannelQuery
|
||||||
from bot_graphql.queries.user_query import UserQuery
|
from bot_graphql.queries.user_query import UserQuery
|
||||||
|
from bot_graphql.queries.user_warning_history_query import UserWarningHistoryQuery
|
||||||
|
from bot_graphql.queries.user_warning_query import UserWarningQuery
|
||||||
from bot_graphql.query import Query
|
from bot_graphql.query import Query
|
||||||
from bot_graphql.schema import Schema
|
from bot_graphql.schema import Schema
|
||||||
|
|
||||||
@@ -115,6 +118,8 @@ class GraphQLModule(ModuleABC):
|
|||||||
services.add_transient(QueryABC, UserJoinedGameServerQuery)
|
services.add_transient(QueryABC, UserJoinedGameServerQuery)
|
||||||
services.add_transient(QueryABC, ShortRoleNameHistoryQuery)
|
services.add_transient(QueryABC, ShortRoleNameHistoryQuery)
|
||||||
services.add_transient(QueryABC, ShortRoleNameQuery)
|
services.add_transient(QueryABC, ShortRoleNameQuery)
|
||||||
|
services.add_transient(QueryABC, UserWarningHistoryQuery)
|
||||||
|
services.add_transient(QueryABC, UserWarningQuery)
|
||||||
|
|
||||||
services.add_transient(QueryABC, DiscordQuery)
|
services.add_transient(QueryABC, DiscordQuery)
|
||||||
services.add_transient(QueryABC, GuildQuery)
|
services.add_transient(QueryABC, GuildQuery)
|
||||||
@@ -135,6 +140,7 @@ class GraphQLModule(ModuleABC):
|
|||||||
services.add_transient(FilterABC, UserJoinedVoiceChannelFilter)
|
services.add_transient(FilterABC, UserJoinedVoiceChannelFilter)
|
||||||
services.add_transient(FilterABC, UserJoinedGameServerFilter)
|
services.add_transient(FilterABC, UserJoinedGameServerFilter)
|
||||||
services.add_transient(FilterABC, ShortRoleNameFilter)
|
services.add_transient(FilterABC, ShortRoleNameFilter)
|
||||||
|
services.add_transient(FilterABC, UserWarningFilter)
|
||||||
|
|
||||||
# mutations
|
# mutations
|
||||||
services.add_transient(QueryABC, AutoRoleMutation)
|
services.add_transient(QueryABC, AutoRoleMutation)
|
||||||
|
@@ -94,6 +94,11 @@ class ServerConfigMutation(QueryABC):
|
|||||||
if "shortRoleNameOnlySetHighestRole" in input
|
if "shortRoleNameOnlySetHighestRole" in input
|
||||||
else server_config.short_role_name_only_set_highest_role
|
else server_config.short_role_name_only_set_highest_role
|
||||||
)
|
)
|
||||||
|
server_config.game_offer_notification_chat_id = (
|
||||||
|
input["gameOfferNotificationChatId"]
|
||||||
|
if "gameOfferNotificationChatId" in input
|
||||||
|
else server_config.game_offer_notification_chat_id
|
||||||
|
)
|
||||||
server_config.feature_flags = (
|
server_config.feature_flags = (
|
||||||
dict(zip([x["key"] for x in input["featureFlags"]], [x["value"] for x in input["featureFlags"]]))
|
dict(zip([x["key"] for x in input["featureFlags"]], [x["value"] for x in input["featureFlags"]]))
|
||||||
if "featureFlags" in input
|
if "featureFlags" in input
|
||||||
@@ -139,6 +144,7 @@ class ServerConfigMutation(QueryABC):
|
|||||||
self._update_team_role_ids(server_config)
|
self._update_team_role_ids(server_config)
|
||||||
|
|
||||||
self._db.save_changes()
|
self._db.save_changes()
|
||||||
|
self._bot.loop.create_task(self._config_service.reload_server_config(server_config.server))
|
||||||
return server_config
|
return server_config
|
||||||
|
|
||||||
def _update_afk_channel_ids(self, new_config: ServerConfig):
|
def _update_afk_channel_ids(self, new_config: ServerConfig):
|
||||||
@@ -178,5 +184,3 @@ class ServerConfigMutation(QueryABC):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
self._server_configs.add_server_team_role_id_config(role_id)
|
self._server_configs.add_server_team_role_id_config(role_id)
|
||||||
|
|
||||||
self._bot.loop.create_task(self._config_service.reload_server_config(new_config.server))
|
|
||||||
|
@@ -1,11 +1,17 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
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_api.route.route import Route
|
||||||
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
|
||||||
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.model.user import User
|
||||||
from bot_data.model.user_role_enum import UserRoleEnum
|
from bot_data.model.user_role_enum import UserRoleEnum
|
||||||
from bot_graphql.abc.query_abc import QueryABC
|
from bot_graphql.abc.query_abc import QueryABC
|
||||||
|
from modules.base.service.user_warnings_service import UserWarningsService
|
||||||
from modules.level.service.level_service import LevelService
|
from modules.level.service.level_service import LevelService
|
||||||
from modules.permission.service.permission_service import PermissionService
|
from modules.permission.service.permission_service import PermissionService
|
||||||
|
|
||||||
@@ -20,6 +26,8 @@ class UserMutation(QueryABC):
|
|||||||
permissions: PermissionService,
|
permissions: PermissionService,
|
||||||
levels: LevelRepositoryABC,
|
levels: LevelRepositoryABC,
|
||||||
level_service: LevelService,
|
level_service: LevelService,
|
||||||
|
user_warnings: UserWarningsRepositoryABC,
|
||||||
|
user_warning_service: UserWarningsService,
|
||||||
):
|
):
|
||||||
QueryABC.__init__(self, "UserMutation")
|
QueryABC.__init__(self, "UserMutation")
|
||||||
|
|
||||||
@@ -30,20 +38,33 @@ class UserMutation(QueryABC):
|
|||||||
self._permissions = permissions
|
self._permissions = permissions
|
||||||
self._levels = levels
|
self._levels = levels
|
||||||
self._level_service = level_service
|
self._level_service = level_service
|
||||||
|
self._user_warnings = user_warnings
|
||||||
|
self._user_warning_service = user_warning_service
|
||||||
|
|
||||||
self.set_field("updateUser", self.resolve_update_user)
|
self.set_field("updateUser", self.resolve_update_user)
|
||||||
|
|
||||||
def resolve_update_user(self, *_, input: dict):
|
def resolve_update_user(self, *_, input: dict):
|
||||||
user = self._users.get_user_by_id(input["id"])
|
user = self._users.get_user_by_id(input["id"])
|
||||||
self._can_user_mutate_data(user.server, UserRoleEnum.moderator)
|
|
||||||
|
|
||||||
new_xp = None
|
auth_user = Route.get_user()
|
||||||
if "levelId" in input:
|
member = self._bot.get_guild(user.server.discord_id).get_member(
|
||||||
level = self._levels.get_level_by_id(input["levelId"])
|
auth_user.users.where(lambda x: x.server.id == user.server.id).single().discord_id
|
||||||
if user.level.id != level.id:
|
)
|
||||||
new_xp = level.min_xp
|
if member.id != user.discord_id:
|
||||||
|
self._can_user_mutate_data(user.server, UserRoleEnum.moderator)
|
||||||
|
|
||||||
user.xp = new_xp if new_xp is not None else input["xp"] if "xp" in input else user.xp
|
new_xp = None
|
||||||
|
if "levelId" in input:
|
||||||
|
level = self._levels.get_level_by_id(input["levelId"])
|
||||||
|
if user.level.id != level.id:
|
||||||
|
new_xp = level.min_xp
|
||||||
|
|
||||||
|
if "userWarnings" in input:
|
||||||
|
self._update_user_warning(user, input["userWarnings"])
|
||||||
|
|
||||||
|
user.xp = new_xp if new_xp is not None else input["xp"] if "xp" in input else user.xp
|
||||||
|
|
||||||
|
user.birthday = datetime.strptime(input["birthday"], "%d.%m.%Y") if "birthday" in input else user.birthday
|
||||||
|
|
||||||
self._users.update_user(user)
|
self._users.update_user(user)
|
||||||
self._db.save_changes()
|
self._db.save_changes()
|
||||||
@@ -51,3 +72,19 @@ class UserMutation(QueryABC):
|
|||||||
|
|
||||||
user = self._users.get_user_by_id(input["id"])
|
user = self._users.get_user_by_id(input["id"])
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
def _update_user_warning(self, user: User, new_warnings: dict):
|
||||||
|
old_warnings = self._user_warnings.get_user_warnings_by_user_id(user.id)
|
||||||
|
for warning in old_warnings:
|
||||||
|
if warning.id in [int(x["id"]) if "id" in x else None for x in new_warnings]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._user_warning_service.remove_warnings(warning.id)
|
||||||
|
|
||||||
|
for warning in new_warnings:
|
||||||
|
if "id" in warning and int(warning["id"]) in old_warnings.select(lambda x: x.id):
|
||||||
|
continue
|
||||||
|
|
||||||
|
member = self._bot.get_guild(user.server.discord_id).get_member(user.discord_id)
|
||||||
|
author = self._users.get_user_by_id(int(warning["author"]))
|
||||||
|
self._user_warning_service.add_warnings(member, warning["description"], author.discord_id)
|
||||||
|
@@ -20,6 +20,7 @@ class ServerConfigQuery(DataQueryWithHistoryABC):
|
|||||||
self.set_field("xpPerOntimeHour", lambda config, *_: config.xp_per_ontime_hour)
|
self.set_field("xpPerOntimeHour", lambda config, *_: config.xp_per_ontime_hour)
|
||||||
self.set_field("xpPerEventParticipation", lambda config, *_: config.xp_per_event_participation)
|
self.set_field("xpPerEventParticipation", lambda config, *_: config.xp_per_event_participation)
|
||||||
self.set_field("xpPerAchievement", lambda config, *_: config.xp_per_achievement)
|
self.set_field("xpPerAchievement", lambda config, *_: config.xp_per_achievement)
|
||||||
|
self.set_field("xpForBirthday", lambda config, *_: config.xp_for_birthday)
|
||||||
self.set_field("afkCommandChannelId", lambda config, *_: config.afk_command_channel_id)
|
self.set_field("afkCommandChannelId", lambda config, *_: config.afk_command_channel_id)
|
||||||
self.set_field("helpVoiceChannelId", lambda config, *_: config.help_voice_channel_id)
|
self.set_field("helpVoiceChannelId", lambda config, *_: config.help_voice_channel_id)
|
||||||
self.set_field("teamChannelId", lambda config, *_: config.team_channel_id)
|
self.set_field("teamChannelId", lambda config, *_: config.team_channel_id)
|
||||||
@@ -28,6 +29,7 @@ class ServerConfigQuery(DataQueryWithHistoryABC):
|
|||||||
self.set_field(
|
self.set_field(
|
||||||
"shortRoleNameOnlySetHighestRole", lambda config, *_: config.short_role_name_only_set_highest_role
|
"shortRoleNameOnlySetHighestRole", lambda config, *_: config.short_role_name_only_set_highest_role
|
||||||
)
|
)
|
||||||
|
self.set_field("gameOfferNotificationChatId", lambda config, *_: config.game_offer_notification_chat_id)
|
||||||
self.add_collection(
|
self.add_collection(
|
||||||
"featureFlag",
|
"featureFlag",
|
||||||
lambda config, *_: List(any, [{"key": x, "value": config.feature_flags[x]} for x in config.feature_flags]),
|
lambda config, *_: List(any, [{"key": x, "value": config.feature_flags[x]} for x in config.feature_flags]),
|
||||||
|
@@ -6,6 +6,7 @@ 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.abc.user_warnings_repository_abc import UserWarningsRepositoryABC
|
||||||
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
|
||||||
@@ -13,6 +14,7 @@ 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
|
||||||
|
from bot_graphql.filter.user_warning_filter import UserWarningFilter
|
||||||
from modules.level.service.level_service import LevelService
|
from modules.level.service.level_service import LevelService
|
||||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
||||||
|
|
||||||
@@ -29,6 +31,7 @@ class UserQuery(DataQueryWithHistoryABC):
|
|||||||
user_joined_game_server: UserJoinedGameServerRepositoryABC,
|
user_joined_game_server: UserJoinedGameServerRepositoryABC,
|
||||||
permissions: PermissionServiceABC,
|
permissions: PermissionServiceABC,
|
||||||
achievements: AchievementRepositoryABC,
|
achievements: AchievementRepositoryABC,
|
||||||
|
user_warnings: UserWarningsRepositoryABC,
|
||||||
):
|
):
|
||||||
DataQueryWithHistoryABC.__init__(self, "User", "UsersHistory", UserHistory, db)
|
DataQueryWithHistoryABC.__init__(self, "User", "UsersHistory", UserHistory, db)
|
||||||
|
|
||||||
@@ -47,6 +50,7 @@ class UserQuery(DataQueryWithHistoryABC):
|
|||||||
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("messageCount", lambda x, *_: x.message_count)
|
||||||
self.set_field("reactionCount", lambda x, *_: x.reaction_count)
|
self.set_field("reactionCount", lambda x, *_: x.reaction_count)
|
||||||
|
self.set_field("birthday", lambda x, *_: x.birthday)
|
||||||
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(
|
||||||
@@ -67,6 +71,9 @@ class UserQuery(DataQueryWithHistoryABC):
|
|||||||
self.add_collection(
|
self.add_collection(
|
||||||
"achievement", lambda user, *_: achievements.get_achievements_by_user_id(user.id), AchievementFilter
|
"achievement", lambda user, *_: achievements.get_achievements_by_user_id(user.id), AchievementFilter
|
||||||
)
|
)
|
||||||
|
self.add_collection(
|
||||||
|
"userWarning", lambda user, *_: user_warnings.get_user_warnings_by_user_id(user.id), UserWarningFilter
|
||||||
|
)
|
||||||
|
|
||||||
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)
|
||||||
|
@@ -0,0 +1,11 @@
|
|||||||
|
from bot_graphql.abc.history_query_abc import HistoryQueryABC
|
||||||
|
|
||||||
|
|
||||||
|
class UserWarningHistoryQuery(HistoryQueryABC):
|
||||||
|
def __init__(self):
|
||||||
|
HistoryQueryABC.__init__(self, "UserWarning")
|
||||||
|
|
||||||
|
self.set_field("id", lambda x, *_: x.id)
|
||||||
|
self.set_field("user", lambda x, *_: x.user)
|
||||||
|
self.set_field("description", lambda x, *_: x.description)
|
||||||
|
self.set_field("author", lambda x, *_: x.author)
|
17
kdb-bot/src/bot_graphql/queries/user_warning_query.py
Normal file
17
kdb-bot/src/bot_graphql/queries/user_warning_query.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from cpl_core.database.context import DatabaseContextABC
|
||||||
|
|
||||||
|
from bot_data.model.user_warnings_history import UserWarningsHistory
|
||||||
|
from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC
|
||||||
|
|
||||||
|
|
||||||
|
class UserWarningQuery(DataQueryWithHistoryABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
db: DatabaseContextABC,
|
||||||
|
):
|
||||||
|
DataQueryWithHistoryABC.__init__(self, "UserWarning", "UserWarningsHistory", UserWarningsHistory, db)
|
||||||
|
|
||||||
|
self.set_field("id", lambda x, *_: x.id)
|
||||||
|
self.set_field("user", lambda x, *_: x.user)
|
||||||
|
self.set_field("description", lambda x, *_: x.description)
|
||||||
|
self.set_field("author", lambda x, *_: x.author)
|
@@ -15,6 +15,7 @@ from bot_data.abc.user_joined_game_server_repository_abc import UserJoinedGameSe
|
|||||||
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.abc.user_warnings_repository_abc import UserWarningsRepositoryABC
|
||||||
from bot_data.model.short_role_name_position_enum import ShortRoleNamePositionEnum
|
from bot_data.model.short_role_name_position_enum import ShortRoleNamePositionEnum
|
||||||
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.achievement_filter import AchievementFilter
|
||||||
@@ -28,6 +29,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 bot_graphql.filter.user_warning_filter import UserWarningFilter
|
||||||
from bot_graphql.model.discord import Discord
|
from bot_graphql.model.discord import Discord
|
||||||
from modules.achievements.achievement_service import AchievementService
|
from modules.achievements.achievement_service import AchievementService
|
||||||
|
|
||||||
@@ -48,6 +50,7 @@ class Query(QueryABC):
|
|||||||
users: UserRepositoryABC,
|
users: UserRepositoryABC,
|
||||||
achievements: AchievementRepositoryABC,
|
achievements: AchievementRepositoryABC,
|
||||||
short_role_names: ShortRoleNameRepositoryABC,
|
short_role_names: ShortRoleNameRepositoryABC,
|
||||||
|
user_warnings: UserWarningsRepositoryABC,
|
||||||
achievement_service: AchievementService,
|
achievement_service: AchievementService,
|
||||||
technician_config: TechnicianConfigRepositoryABC,
|
technician_config: TechnicianConfigRepositoryABC,
|
||||||
):
|
):
|
||||||
@@ -76,11 +79,13 @@ class Query(QueryABC):
|
|||||||
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.add_collection("achievement", lambda *_: achievements.get_achievements(), AchievementFilter)
|
||||||
self.add_collection("shortRoleName", lambda *_: short_role_names.get_short_role_names(), ShortRoleNameFilter)
|
self.add_collection("shortRoleName", lambda *_: short_role_names.get_short_role_names(), ShortRoleNameFilter)
|
||||||
|
self.add_collection("userWarning", lambda *_: user_warnings.get_user_warnings(), UserWarningFilter)
|
||||||
|
|
||||||
self.set_field("technicianConfig", lambda *_: technician_config.get_technician_config())
|
self.set_field("technicianConfig", lambda *_: technician_config.get_technician_config())
|
||||||
|
|
||||||
self.set_field("achievementAttributes", lambda *_: achievement_service.get_attributes())
|
self.set_field("achievementAttributes", lambda *_: achievement_service.get_attributes())
|
||||||
self.set_field("achievementOperators", lambda *_: achievement_service.get_operators())
|
self.set_field("achievementOperators", lambda *_: achievement_service.get_operators())
|
||||||
self.set_field("shortRoleNamePositions", lambda *_: [x.value for x in ShortRoleNamePositionEnum])
|
self.set_field("shortRoleNamePositions", lambda *_: [x.value for x in ShortRoleNamePositionEnum])
|
||||||
|
|
||||||
self.set_field("possibleFeatureFlags", lambda *_: [e.value for e in FeatureFlagsEnum])
|
self.set_field("possibleFeatureFlags", lambda *_: [e.value for e in FeatureFlagsEnum])
|
||||||
self.set_field("discord", lambda *_: Discord(bot.guilds, List(any).extend(bot.users)))
|
self.set_field("discord", lambda *_: Discord(bot.guilds, List(any).extend(bot.users)))
|
||||||
|
@@ -61,7 +61,7 @@ class AutoRoleGroup(DiscordCommandABC):
|
|||||||
auto_roles = self._auto_roles.get_auto_roles_by_server_id(server.id).select(lambda x: x.id)
|
auto_roles = self._auto_roles.get_auto_roles_by_server_id(server.id).select(lambda x: x.id)
|
||||||
return [
|
return [
|
||||||
app_commands.Choice(name=auto_role, value=auto_role)
|
app_commands.Choice(name=auto_role, value=auto_role)
|
||||||
for auto_role in self._client_utils.get_auto_complete_list(auto_roles, current)
|
for auto_role in self._client_utils.get_auto_complete_list(auto_roles, current, lambda x: x.name)
|
||||||
]
|
]
|
||||||
|
|
||||||
@commands.hybrid_group(name="auto-role")
|
@commands.hybrid_group(name="auto-role")
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
from typing import Optional, List
|
import datetime
|
||||||
|
from typing import Optional, List as TList
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from cpl_core.configuration import ConfigurationABC
|
from cpl_core.configuration import ConfigurationABC
|
||||||
from cpl_core.database.context import DatabaseContextABC
|
from cpl_core.database.context import DatabaseContextABC
|
||||||
from cpl_discord.command import DiscordCommandABC
|
from cpl_discord.command import DiscordCommandABC
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
|
from cpl_query.extension import List
|
||||||
from cpl_translation import TranslatePipe
|
from cpl_translation import TranslatePipe
|
||||||
from discord import app_commands
|
from discord import app_commands
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
@@ -22,6 +24,7 @@ from bot_data.abc.user_joined_voice_channel_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.model.server_config import ServerConfig
|
||||||
from modules.base.service.user_warnings_service import UserWarningsService
|
from modules.base.service.user_warnings_service import UserWarningsService
|
||||||
from modules.level.service.level_service import LevelService
|
from modules.level.service.level_service import LevelService
|
||||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
||||||
@@ -73,7 +76,7 @@ class UserGroup(DiscordCommandABC):
|
|||||||
"ontime": self._t.transform("modules.base.user.atr.ontime"),
|
"ontime": self._t.transform("modules.base.user.atr.ontime"),
|
||||||
}
|
}
|
||||||
|
|
||||||
self._atr_list = [(key, self._atr_dict[key]) for key in self._atr_dict]
|
self._atr_TList = [(key, self._atr_dict[key]) for key in self._atr_dict]
|
||||||
|
|
||||||
async def _handle_atr_calc(
|
async def _handle_atr_calc(
|
||||||
self,
|
self,
|
||||||
@@ -116,6 +119,61 @@ class UserGroup(DiscordCommandABC):
|
|||||||
async def user(self, ctx: Context):
|
async def user(self, ctx: Context):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@user.command()
|
||||||
|
@commands.guild_only()
|
||||||
|
@CommandChecks.check_is_ready()
|
||||||
|
async def birthday(self, ctx: Context, day: int, month: int, year: int):
|
||||||
|
self._logger.debug(__name__, f"Received command user birthday {ctx}:{ctx.author},{day}:{month}:{year}")
|
||||||
|
date = datetime.date(year, month, day)
|
||||||
|
server = self._servers.get_server_by_discord_id(ctx.guild.id)
|
||||||
|
user = self._users.get_user_by_discord_id_and_server_id(ctx.author.id, server.id)
|
||||||
|
user.birthday = date
|
||||||
|
self._users.update_user(user)
|
||||||
|
self._db.save_changes()
|
||||||
|
await self._message_service.send_interaction_msg(
|
||||||
|
ctx.interaction, self._t.transform("modules.base.user.birthday.success")
|
||||||
|
)
|
||||||
|
# notify team to prevent multiple entries every day
|
||||||
|
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild.id}")
|
||||||
|
channel = ctx.guild.get_channel(settings.team_channel_id)
|
||||||
|
await self._message_service.send_channel_message(
|
||||||
|
channel,
|
||||||
|
self._t.transform("modules.base.user.birthday.success_team").format(ctx.author.mention, date),
|
||||||
|
is_persistent=True,
|
||||||
|
)
|
||||||
|
self._logger.trace(__name__, f"Finished user-info command")
|
||||||
|
|
||||||
|
@birthday.autocomplete("day")
|
||||||
|
async def birthday_autocomplete(
|
||||||
|
self, interaction: discord.Interaction, current: str
|
||||||
|
) -> TList[app_commands.Choice[int]]:
|
||||||
|
days = List(int, range(0, 32)).select(lambda x: str(x))
|
||||||
|
return [
|
||||||
|
app_commands.Choice(name=date, value=date)
|
||||||
|
for date in self._client_utils.get_auto_complete_list(days, current)
|
||||||
|
]
|
||||||
|
|
||||||
|
@birthday.autocomplete("month")
|
||||||
|
async def birthday_autocomplete(
|
||||||
|
self, interaction: discord.Interaction, current: str
|
||||||
|
) -> TList[app_commands.Choice[int]]:
|
||||||
|
days = List(int, range(0, 13)).select(lambda x: str(x))
|
||||||
|
return [
|
||||||
|
app_commands.Choice(name=date, value=date)
|
||||||
|
for date in self._client_utils.get_auto_complete_list(days, current)
|
||||||
|
]
|
||||||
|
|
||||||
|
@birthday.autocomplete("year")
|
||||||
|
async def birthday_autocomplete(
|
||||||
|
self, interaction: discord.Interaction, current: str
|
||||||
|
) -> TList[app_commands.Choice[int]]:
|
||||||
|
today = datetime.date.today()
|
||||||
|
days = List(int, range(today.year - 75, today.year)).select(lambda x: str(x))
|
||||||
|
return [
|
||||||
|
app_commands.Choice(name=date, value=date)
|
||||||
|
for date in self._client_utils.get_auto_complete_list(days, current)
|
||||||
|
]
|
||||||
|
|
||||||
@user.command()
|
@user.command()
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@CommandChecks.check_is_ready()
|
@CommandChecks.check_is_ready()
|
||||||
@@ -237,8 +295,8 @@ class UserGroup(DiscordCommandABC):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@get.autocomplete("atr")
|
@get.autocomplete("atr")
|
||||||
async def get_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]:
|
async def get_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]:
|
||||||
return [app_commands.Choice(name=value, value=key) for key, value in self._atr_list]
|
return [app_commands.Choice(name=value, value=key) for key, value in self._atr_TList]
|
||||||
|
|
||||||
@user.command()
|
@user.command()
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@@ -281,9 +339,9 @@ class UserGroup(DiscordCommandABC):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@set.autocomplete("atr")
|
@set.autocomplete("atr")
|
||||||
async def set_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]:
|
async def set_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]:
|
||||||
atr_list = [("xp", self._atr_dict["xp"])]
|
atr_TList = [("xp", self._atr_dict["xp"])]
|
||||||
return [app_commands.Choice(name=value, value=key) for key, value in atr_list]
|
return [app_commands.Choice(name=value, value=key) for key, value in atr_TList]
|
||||||
|
|
||||||
@user.command()
|
@user.command()
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@@ -294,9 +352,9 @@ class UserGroup(DiscordCommandABC):
|
|||||||
await self._handle_atr_calc(ctx, atr, value, member)
|
await self._handle_atr_calc(ctx, atr, value, member)
|
||||||
|
|
||||||
@add.autocomplete("atr")
|
@add.autocomplete("atr")
|
||||||
async def set_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]:
|
async def set_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]:
|
||||||
atr_list = [("xp", self._atr_dict["xp"])]
|
atr_TList = [("xp", self._atr_dict["xp"])]
|
||||||
return [app_commands.Choice(name=value, value=key) for key, value in atr_list]
|
return [app_commands.Choice(name=value, value=key) for key, value in atr_TList]
|
||||||
|
|
||||||
@user.command()
|
@user.command()
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@@ -307,9 +365,9 @@ class UserGroup(DiscordCommandABC):
|
|||||||
await self._handle_atr_calc(ctx, atr, value, member, is_remove=True)
|
await self._handle_atr_calc(ctx, atr, value, member, is_remove=True)
|
||||||
|
|
||||||
@remove.autocomplete("atr")
|
@remove.autocomplete("atr")
|
||||||
async def set_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]:
|
async def set_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]:
|
||||||
atr_list = [("xp", self._atr_dict["xp"])]
|
atr_TList = [("xp", self._atr_dict["xp"])]
|
||||||
return [app_commands.Choice(name=value, value=key) for key, value in atr_list]
|
return [app_commands.Choice(name=value, value=key) for key, value in atr_TList]
|
||||||
|
|
||||||
@user.command()
|
@user.command()
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@@ -349,8 +407,8 @@ class UserGroup(DiscordCommandABC):
|
|||||||
@reset.autocomplete("atr")
|
@reset.autocomplete("atr")
|
||||||
async def reset_autocomplete(
|
async def reset_autocomplete(
|
||||||
self, interaction: discord.Interaction, current: str
|
self, interaction: discord.Interaction, current: str
|
||||||
) -> List[app_commands.Choice[str]]:
|
) -> TList[app_commands.Choice[str]]:
|
||||||
return [app_commands.Choice(name=value, value=key) for key, value in self._atr_list]
|
return [app_commands.Choice(name=value, value=key) for key, value in self._atr_TList]
|
||||||
|
|
||||||
@user.group()
|
@user.group()
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@@ -400,7 +458,7 @@ class UserGroup(DiscordCommandABC):
|
|||||||
async def add(self, ctx: Context, member: discord.Member, description: str):
|
async def add(self, ctx: Context, member: discord.Member, description: str):
|
||||||
self._logger.debug(__name__, f"Received command user warning add {ctx}:{member},{description}")
|
self._logger.debug(__name__, f"Received command user warning add {ctx}:{member},{description}")
|
||||||
try:
|
try:
|
||||||
await self._user_warnings_service.add_warnings(member, description, ctx.author.id)
|
await self._user_warnings_service.add_warnings_async(member, description, ctx.author.id)
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform("modules.base.warnings.add.success"))
|
await self._message_service.send_ctx_msg(ctx, self._t.transform("modules.base.warnings.add.success"))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._logger.error(__name__, f"Adding user warning failed", e)
|
self._logger.error(__name__, f"Adding user warning failed", e)
|
||||||
@@ -414,7 +472,7 @@ class UserGroup(DiscordCommandABC):
|
|||||||
async def remove(self, ctx: Context, warning_id: int):
|
async def remove(self, ctx: Context, warning_id: int):
|
||||||
self._logger.debug(__name__, f"Received command user warning remove {ctx}:{warning_id}")
|
self._logger.debug(__name__, f"Received command user warning remove {ctx}:{warning_id}")
|
||||||
try:
|
try:
|
||||||
await self._user_warnings_service.remove_warnings(warning_id)
|
await self._user_warnings_service.remove_warnings_async(warning_id)
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform("modules.base.warnings.remove.success"))
|
await self._message_service.send_ctx_msg(ctx, self._t.transform("modules.base.warnings.remove.success"))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._logger.error(__name__, f"Removing user warning failed", e)
|
self._logger.error(__name__, f"Removing user warning failed", e)
|
||||||
|
@@ -108,7 +108,15 @@ class UserWarningsService:
|
|||||||
await self.notify_team(member, self._t.transform("modules.base.warnings.kick").format(member.mention))
|
await self.notify_team(member, self._t.transform("modules.base.warnings.kick").format(member.mention))
|
||||||
await member.kick()
|
await member.kick()
|
||||||
|
|
||||||
async def add_warnings(self, member: discord.Member, description: str, author_id: int = None):
|
async def _notify_after_add(self, member: discord.Member, warning: UserWarnings):
|
||||||
|
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.notify_user(member, self._t.transform("modules.base.warnings.warned").format(warning.description))
|
||||||
|
await self.notify_team(member, warning.description)
|
||||||
|
await self.check_for_warnings(member, user)
|
||||||
|
|
||||||
|
def _add_warnings(self, member: discord.Member, description: str, author_id: int = None):
|
||||||
server = self._servers.get_server_by_discord_id(member.guild.id)
|
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)
|
user = self._users.get_user_by_discord_id_and_server_id(member.id, server.id)
|
||||||
|
|
||||||
@@ -119,17 +127,32 @@ class UserWarningsService:
|
|||||||
warning = UserWarnings(description, user, author)
|
warning = UserWarnings(description, user, author)
|
||||||
self._warnings.add_user_warnings(warning)
|
self._warnings.add_user_warnings(warning)
|
||||||
self._db.save_changes()
|
self._db.save_changes()
|
||||||
await self.notify_user(member, self._t.transform("modules.base.warnings.warned").format(warning.description))
|
return warning
|
||||||
await self.notify_team(member, warning.description)
|
|
||||||
await self.check_for_warnings(member, user)
|
|
||||||
|
|
||||||
async def remove_warnings(self, id: int):
|
def add_warnings(self, member: discord.Member, description: str, author_id: int = None):
|
||||||
|
warning = self._add_warnings(member, description, author_id)
|
||||||
|
self._bot.loop.create_task(self._notify_after_add(member, warning))
|
||||||
|
|
||||||
|
async def add_warnings_async(self, member: discord.Member, description: str, author_id: int = None):
|
||||||
|
warning = self._add_warnings(member, description, author_id)
|
||||||
|
await self._notify_after_add(member, warning)
|
||||||
|
|
||||||
|
async def _notify_after_remove(self, warning: UserWarnings):
|
||||||
|
guild = self._bot.get_guild(warning.user.server.discord_id)
|
||||||
|
member = guild.get_member(warning.user.discord_id)
|
||||||
|
await self.notify_user(member, self._t.transform("modules.base.warnings.removed").format(warning.description))
|
||||||
|
await self.notify_team(member, warning.description, removed=True)
|
||||||
|
|
||||||
|
def _remove_warnings(self, id: int):
|
||||||
warning = self._warnings.get_user_warnings_by_id(id)
|
warning = self._warnings.get_user_warnings_by_id(id)
|
||||||
self._warnings.delete_user_warnings(warning)
|
self._warnings.delete_user_warnings(warning)
|
||||||
self._db.save_changes()
|
self._db.save_changes()
|
||||||
|
return warning
|
||||||
|
|
||||||
guild = self._bot.get_guild(warning.user.server.discord_id)
|
def remove_warnings(self, id: int):
|
||||||
member = guild.get_member(warning.user.discord_id)
|
warning = self._remove_warnings(id)
|
||||||
|
self._bot.loop.create_task(self._notify_after_remove(warning))
|
||||||
|
|
||||||
await self.notify_user(member, self._t.transform("modules.base.warnings.removed").format(warning.description))
|
async def remove_warnings_async(self, id: int):
|
||||||
await self.notify_team(member, warning.description, removed=True)
|
warning = self._remove_warnings(id)
|
||||||
|
await self._notify_after_remove(warning)
|
||||||
|
1
kdb-bot/src/modules/special_offers/__init__.py
Normal file
1
kdb-bot/src/modules/special_offers/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# imports
|
1
kdb-bot/src/modules/special_offers/base/__init__.py
Normal file
1
kdb-bot/src/modules/special_offers/base/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# imports
|
@@ -0,0 +1,13 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
|
||||||
|
class SpecialOfferWatcherABC(commands.Cog):
|
||||||
|
@abstractmethod
|
||||||
|
def __init__(self):
|
||||||
|
commands.Cog.__init__(self)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def start(self):
|
||||||
|
pass
|
1
kdb-bot/src/modules/special_offers/events/__init__.py
Normal file
1
kdb-bot/src/modules/special_offers/events/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# imports
|
@@ -0,0 +1,25 @@
|
|||||||
|
from cpl_core.logging import LoggerABC
|
||||||
|
from cpl_discord.events import OnReadyABC
|
||||||
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
|
|
||||||
|
from bot_core.logging.task_logger import TaskLogger
|
||||||
|
from modules.special_offers.base.special_offer_watcher_abc import SpecialOfferWatcherABC
|
||||||
|
|
||||||
|
|
||||||
|
class SpecialOfferOnReadyEvent(OnReadyABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
logger: TaskLogger,
|
||||||
|
bot: DiscordBotServiceABC,
|
||||||
|
watchers: list[SpecialOfferWatcherABC],
|
||||||
|
):
|
||||||
|
OnReadyABC.__init__(self)
|
||||||
|
|
||||||
|
self._logger = logger
|
||||||
|
self._bot = bot
|
||||||
|
self._watchers = watchers
|
||||||
|
|
||||||
|
async def on_ready(self):
|
||||||
|
for watcher in self._watchers:
|
||||||
|
self._logger.info(__name__, f"Starting watcher {type(watcher).__name__}")
|
||||||
|
watcher.start()
|
46
kdb-bot/src/modules/special_offers/special-offers.json
Normal file
46
kdb-bot/src/modules/special_offers/special-offers.json
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"ProjectSettings": {
|
||||||
|
"Name": "steam-special-offers",
|
||||||
|
"Version": {
|
||||||
|
"Major": "0",
|
||||||
|
"Minor": "0",
|
||||||
|
"Micro": "0"
|
||||||
|
},
|
||||||
|
"Author": "",
|
||||||
|
"AuthorEmail": "",
|
||||||
|
"Description": "",
|
||||||
|
"LongDescription": "",
|
||||||
|
"URL": "",
|
||||||
|
"CopyrightDate": "",
|
||||||
|
"CopyrightName": "",
|
||||||
|
"LicenseName": "",
|
||||||
|
"LicenseDescription": "",
|
||||||
|
"Dependencies": [
|
||||||
|
"cpl-core>=2023.4.0.post5"
|
||||||
|
],
|
||||||
|
"DevDependencies": [
|
||||||
|
"cpl-cli>=2023.4.0.post3"
|
||||||
|
],
|
||||||
|
"PythonVersion": ">=3.10.4",
|
||||||
|
"PythonPath": {
|
||||||
|
"linux": ""
|
||||||
|
},
|
||||||
|
"Classifiers": []
|
||||||
|
},
|
||||||
|
"BuildSettings": {
|
||||||
|
"ProjectType": "library",
|
||||||
|
"SourcePath": "",
|
||||||
|
"OutputPath": "../../dist",
|
||||||
|
"Main": "steam_special_offers.main",
|
||||||
|
"EntryPoint": "steam-special-offers",
|
||||||
|
"IncludePackageData": false,
|
||||||
|
"Included": [],
|
||||||
|
"Excluded": [
|
||||||
|
"*/__pycache__",
|
||||||
|
"*/logs",
|
||||||
|
"*/tests"
|
||||||
|
],
|
||||||
|
"PackageData": {},
|
||||||
|
"ProjectReferences": []
|
||||||
|
}
|
||||||
|
}
|
25
kdb-bot/src/modules/special_offers/special_offers_module.py
Normal file
25
kdb-bot/src/modules/special_offers/special_offers_module.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
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.special_offers.base.special_offer_watcher_abc import SpecialOfferWatcherABC
|
||||||
|
from modules.special_offers.events.special_offer_on_ready_event import SpecialOfferOnReadyEvent
|
||||||
|
from modules.special_offers.steam_offer_watcher import SteamOfferWatcher
|
||||||
|
|
||||||
|
|
||||||
|
class SteamSpecialOffersModule(ModuleABC):
|
||||||
|
def __init__(self, dc: DiscordCollectionABC):
|
||||||
|
ModuleABC.__init__(self, dc, FeatureFlagsEnum.steam_special_offers_module)
|
||||||
|
|
||||||
|
def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
|
||||||
|
services.add_singleton(SpecialOfferWatcherABC, SteamOfferWatcher)
|
||||||
|
# commands
|
||||||
|
# events
|
||||||
|
self._dc.add_event(DiscordEventTypesEnum.on_ready.value, SpecialOfferOnReadyEvent)
|
210
kdb-bot/src/modules/special_offers/steam_offer_watcher.py
Normal file
210
kdb-bot/src/modules/special_offers/steam_offer_watcher.py
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import bs4
|
||||||
|
import discord
|
||||||
|
import requests
|
||||||
|
from cpl_core.configuration import ConfigurationABC
|
||||||
|
from cpl_core.database.context import DatabaseContextABC
|
||||||
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
|
from cpl_query.extension import List
|
||||||
|
from cpl_translation import TranslatePipe
|
||||||
|
from discord.ext import tasks
|
||||||
|
|
||||||
|
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||||
|
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||||
|
from bot_core.logging.task_logger import TaskLogger
|
||||||
|
from bot_core.service.message_service import MessageService
|
||||||
|
from bot_data.abc.steam_special_offer_repository_abc import SteamSpecialOfferRepositoryABC
|
||||||
|
from bot_data.model.server_config import ServerConfig
|
||||||
|
from bot_data.model.steam_special_offer import SteamSpecialOffer
|
||||||
|
from modules.special_offers.base.special_offer_watcher_abc import SpecialOfferWatcherABC
|
||||||
|
|
||||||
|
|
||||||
|
class SteamOfferWatcher(SpecialOfferWatcherABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: ConfigurationABC,
|
||||||
|
bot: DiscordBotServiceABC,
|
||||||
|
logger: TaskLogger,
|
||||||
|
db: DatabaseContextABC,
|
||||||
|
offers: SteamSpecialOfferRepositoryABC,
|
||||||
|
message_service: MessageService,
|
||||||
|
t: TranslatePipe,
|
||||||
|
):
|
||||||
|
SpecialOfferWatcherABC.__init__(self)
|
||||||
|
|
||||||
|
self._config = config
|
||||||
|
self._logger = logger
|
||||||
|
self._db = db
|
||||||
|
self._offers = offers
|
||||||
|
self._bot = bot
|
||||||
|
self._message_service = message_service
|
||||||
|
self._t = t
|
||||||
|
|
||||||
|
self._is_new = False
|
||||||
|
self._urls = {}
|
||||||
|
self._image_urls = {}
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.watch.start()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_max_count() -> int:
|
||||||
|
count = 0
|
||||||
|
result = requests.get(f"https://store.steampowered.com/search/results?specials=1")
|
||||||
|
soup = bs4.BeautifulSoup(result.text, "lxml")
|
||||||
|
element = soup.find_all("div", {"class": "search_results_count"})
|
||||||
|
if len(element) < 1:
|
||||||
|
return count
|
||||||
|
|
||||||
|
count = int(element[0].contents[0].split(" ")[0].replace(",", ""))
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
||||||
|
def _get_games_from_page(self, start: int, count: int) -> List[SteamSpecialOffer]:
|
||||||
|
games = List(SteamSpecialOffer)
|
||||||
|
result = requests.get(
|
||||||
|
f"https://store.steampowered.com/search/results?query&start={start}&count={count}&force_infinite=1&specials=1"
|
||||||
|
)
|
||||||
|
soup = bs4.BeautifulSoup(result.text, "lxml")
|
||||||
|
elements = soup.find_all("a", {"class": "search_result_row"})
|
||||||
|
if len(elements) < 1:
|
||||||
|
return games
|
||||||
|
|
||||||
|
for element in elements:
|
||||||
|
name_element = element.find("span", {"class": "title"})
|
||||||
|
original_price_element = element.find("div", {"class": "discount_original_price"})
|
||||||
|
discount_element = element.find("div", {"class": "discount_pct"})
|
||||||
|
discount_price_element = element.find("div", {"class": "discount_final_price"})
|
||||||
|
|
||||||
|
if (
|
||||||
|
name_element is None
|
||||||
|
or len(name_element.contents) < 1
|
||||||
|
or original_price_element is None
|
||||||
|
or len(original_price_element.contents) < 1
|
||||||
|
or discount_element is None
|
||||||
|
or len(discount_element.contents) < 1
|
||||||
|
or discount_price_element is None
|
||||||
|
or len(discount_price_element.contents) < 1
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
name = name_element.contents[0].replace("'", "`").replace('"', "`")
|
||||||
|
original_price = float(
|
||||||
|
original_price_element.contents[0].replace(" ", "").replace("€", "").replace(",", ".")
|
||||||
|
)
|
||||||
|
discount = int(discount_element.contents[0].replace("%", ""))
|
||||||
|
discount_price = float(
|
||||||
|
discount_price_element.contents[0].replace(" ", "").replace("€", "").replace(",", ".")
|
||||||
|
)
|
||||||
|
games.add(SteamSpecialOffer(name, original_price, discount_price, discount))
|
||||||
|
self._urls[name] = element.attrs["href"]
|
||||||
|
self._image_urls[name] = element.find("div", {"class": "search_capsule"}).find("img").attrs["src"]
|
||||||
|
|
||||||
|
return games
|
||||||
|
|
||||||
|
def _get_new_game_offers(self) -> List[SteamSpecialOffer]:
|
||||||
|
new_offers = List(SteamSpecialOffer)
|
||||||
|
|
||||||
|
sale_count = self._get_max_count() + 100
|
||||||
|
sale_count = 300
|
||||||
|
self._logger.debug(__name__, f"Get special offers from 0 to {sale_count}")
|
||||||
|
for i in range(0, sale_count, 100):
|
||||||
|
new_offers.extend(self._get_games_from_page(i, 100))
|
||||||
|
|
||||||
|
self._logger.debug(__name__, f"Got {new_offers.count()} offers")
|
||||||
|
|
||||||
|
return new_offers
|
||||||
|
|
||||||
|
def _build_embed_for_offer(self, offer: SteamSpecialOffer) -> discord.Embed:
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=offer.name,
|
||||||
|
url=self._urls[offer.name],
|
||||||
|
color=int("ef9d0d", 16),
|
||||||
|
timestamp=datetime.now(),
|
||||||
|
)
|
||||||
|
|
||||||
|
embed.add_field(
|
||||||
|
name=self._t.transform("modules.special_offers.price"),
|
||||||
|
value=f"~~{offer.original_price}€~~",
|
||||||
|
inline=True,
|
||||||
|
)
|
||||||
|
embed.add_field(
|
||||||
|
name=self._t.transform("modules.special_offers.discount"), value=f"{offer.discount_pct}%", inline=True
|
||||||
|
)
|
||||||
|
embed.add_field(
|
||||||
|
name=self._t.transform("modules.special_offers.discount_price"),
|
||||||
|
value=f"{offer.discount_price}€",
|
||||||
|
inline=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
embed.set_image(url=self._image_urls[offer.name])
|
||||||
|
return embed
|
||||||
|
|
||||||
|
async def _watch(self):
|
||||||
|
self._is_new = self._offers.get_steam_special_offers().count() == 0
|
||||||
|
new_offers = self._get_new_game_offers()
|
||||||
|
new_offers_names = new_offers.select(lambda x: x.name).to_list()
|
||||||
|
|
||||||
|
old_offers = self._offers.get_steam_special_offers()
|
||||||
|
old_offers_names = old_offers.select(lambda x: x.name).to_list()
|
||||||
|
|
||||||
|
offers_for_notifications = List(SteamSpecialOffer)
|
||||||
|
|
||||||
|
for offer in old_offers:
|
||||||
|
offer: SteamSpecialOffer = offer
|
||||||
|
if offer.name in new_offers_names:
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._offers.delete_steam_special_offer(offer)
|
||||||
|
self._db.save_changes()
|
||||||
|
|
||||||
|
for offer in new_offers:
|
||||||
|
if offer.name in old_offers_names:
|
||||||
|
self._offers.update_steam_special_offer(offer)
|
||||||
|
self._db.save_changes()
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._offers.add_steam_special_offer(offer)
|
||||||
|
self._db.save_changes()
|
||||||
|
offers_for_notifications.add(offer)
|
||||||
|
|
||||||
|
self._logger.trace(__name__, "Finished watching")
|
||||||
|
# if self._is_new:
|
||||||
|
# return
|
||||||
|
|
||||||
|
self._logger.debug(__name__, f"Sending offer notifications for {offers_for_notifications.count()} offers")
|
||||||
|
for guild in self._bot.guilds:
|
||||||
|
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{guild.id}")
|
||||||
|
if (
|
||||||
|
not FeatureFlagsSettings.get_flag_from_dict(
|
||||||
|
settings.feature_flags, FeatureFlagsEnum.steam_special_offers
|
||||||
|
)
|
||||||
|
and settings.game_offer_notification_chat_id is None
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
embeds = []
|
||||||
|
|
||||||
|
for offer in offers_for_notifications:
|
||||||
|
embed = self._build_embed_for_offer(offer)
|
||||||
|
if embed is None:
|
||||||
|
continue
|
||||||
|
embeds.append(embed)
|
||||||
|
|
||||||
|
print(embeds)
|
||||||
|
# await self._message_service.send_channel_message(
|
||||||
|
# self._bot.get_channel(settings.game_offer_notification_chat_id),
|
||||||
|
# embeds,
|
||||||
|
# is_persistent=True,
|
||||||
|
# )
|
||||||
|
|
||||||
|
@tasks.loop(minutes=60)
|
||||||
|
async def watch(self):
|
||||||
|
self._logger.info(__name__, "Watching steam special offers")
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
# await self._watch()
|
||||||
|
except Exception as e:
|
||||||
|
self._logger.error(__name__, f"Steam offer watcher failed", e)
|
19
kdb-web/package-lock.json
generated
19
kdb-web/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "kdb-web",
|
"name": "kdb-web",
|
||||||
"version": "1.0.dev127_config_in_wi",
|
"version": "1.2.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "kdb-web",
|
"name": "kdb-web",
|
||||||
"version": "1.0.dev127_config_in_wi",
|
"version": "1.2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^15.1.4",
|
"@angular/animations": "^15.1.4",
|
||||||
"@angular/common": "^15.1.4",
|
"@angular/common": "^15.1.4",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"@ngx-translate/core": "^14.0.0",
|
"@ngx-translate/core": "^14.0.0",
|
||||||
"@ngx-translate/http-loader": "^7.0.0",
|
"@ngx-translate/http-loader": "^7.0.0",
|
||||||
"@types/socket.io-client": "^3.0.0",
|
"@types/socket.io-client": "^3.0.0",
|
||||||
"primeflex": "^3.3.1",
|
"moment": "^2.29.4",
|
||||||
"primeicons": "^6.0.1",
|
"primeicons": "^6.0.1",
|
||||||
"primeng": "^15.2.0",
|
"primeng": "^15.2.0",
|
||||||
"rxjs": "~7.5.0",
|
"rxjs": "~7.5.0",
|
||||||
@@ -8157,6 +8157,14 @@
|
|||||||
"mkdirp": "bin/cmd.js"
|
"mkdirp": "bin/cmd.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/moment": {
|
||||||
|
"version": "2.29.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
|
||||||
|
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
@@ -9303,11 +9311,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/primeflex": {
|
|
||||||
"version": "3.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/primeflex/-/primeflex-3.3.1.tgz",
|
|
||||||
"integrity": "sha512-zaOq3YvcOYytbAmKv3zYc+0VNS9Wg5d37dfxZnveKBFPr7vEIwfV5ydrpiouTft8MVW6qNjfkaQphHSnvgQbpQ=="
|
|
||||||
},
|
|
||||||
"node_modules/primeicons": {
|
"node_modules/primeicons": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/primeicons/-/primeicons-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/primeicons/-/primeicons-6.0.1.tgz",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "kdb-web",
|
"name": "kdb-web",
|
||||||
"version": "1.1.10",
|
"version": "1.2.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"update-version": "ts-node update-version.ts",
|
"update-version": "ts-node update-version.ts",
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
"@ngx-translate/core": "^14.0.0",
|
"@ngx-translate/core": "^14.0.0",
|
||||||
"@ngx-translate/http-loader": "^7.0.0",
|
"@ngx-translate/http-loader": "^7.0.0",
|
||||||
"@types/socket.io-client": "^3.0.0",
|
"@types/socket.io-client": "^3.0.0",
|
||||||
|
"moment": "^2.29.4",
|
||||||
"primeicons": "^6.0.1",
|
"primeicons": "^6.0.1",
|
||||||
"primeng": "^15.2.0",
|
"primeng": "^15.2.0",
|
||||||
"rxjs": "~7.5.0",
|
"rxjs": "~7.5.0",
|
||||||
@@ -51,4 +52,4 @@
|
|||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
"typescript": "~4.9.5"
|
"typescript": "~4.9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,23 +1,22 @@
|
|||||||
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
import { HttpClient, HttpClientModule } from "@angular/common/http";
|
||||||
import { APP_INITIALIZER, ErrorHandler, NgModule } from '@angular/core';
|
import { APP_INITIALIZER, ErrorHandler, NgModule } from "@angular/core";
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from "@angular/platform-browser";
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
||||||
import { JwtModule } from '@auth0/angular-jwt';
|
import { JwtModule } from "@auth0/angular-jwt";
|
||||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
import { TranslateLoader, TranslateModule } from "@ngx-translate/core";
|
||||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
import { TranslateHttpLoader } from "@ngx-translate/http-loader";
|
||||||
import { ConfirmationService, MessageService } from 'primeng/api';
|
import { ConfirmationService, MessageService } from "primeng/api";
|
||||||
import { DialogService } from 'primeng/dynamicdialog';
|
import { DialogService } from "primeng/dynamicdialog";
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from "./app-routing.module";
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from "./app.component";
|
||||||
import { NotFoundComponent } from './components/error/not-found/not-found.component';
|
import { NotFoundComponent } from "./components/error/not-found/not-found.component";
|
||||||
import { FooterComponent } from './components/footer/footer.component';
|
import { FooterComponent } from "./components/footer/footer.component";
|
||||||
import { HeaderComponent } from './components/header/header.component';
|
import { HeaderComponent } from "./components/header/header.component";
|
||||||
import { SidebarComponent } from './components/sidebar/sidebar.component';
|
import { SidebarComponent } from "./components/sidebar/sidebar.component";
|
||||||
import { SpinnerComponent } from './components/spinner/spinner.component';
|
import { SpinnerComponent } from "./components/spinner/spinner.component";
|
||||||
import { SharedModule } from './modules/shared/shared.module';
|
import { SharedModule } from "./modules/shared/shared.module";
|
||||||
import { ErrorHandlerService } from './services/error-handler/error-handler.service';
|
import { ErrorHandlerService } from "./services/error-handler/error-handler.service";
|
||||||
import { SettingsService } from './services/settings/settings.service';
|
import { SettingsService } from "./services/settings/settings.service";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -63,7 +62,7 @@ import { SettingsService } from './services/settings/settings.service';
|
|||||||
},
|
},
|
||||||
MessageService,
|
MessageService,
|
||||||
ConfirmationService,
|
ConfirmationService,
|
||||||
DialogService
|
DialogService,
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
|
@@ -18,6 +18,7 @@ export interface ServerConfig extends DataWithHistory {
|
|||||||
loginMessageChannelId?: string;
|
loginMessageChannelId?: string;
|
||||||
defaultRoleId?: string;
|
defaultRoleId?: string;
|
||||||
shortRoleNameOnlySetHighestRole?: boolean;
|
shortRoleNameOnlySetHighestRole?: boolean;
|
||||||
|
gameOfferNotificationChatId?: string;
|
||||||
featureFlags: FeatureFlag[];
|
featureFlags: FeatureFlag[];
|
||||||
afkChannelIds: string[];
|
afkChannelIds: string[];
|
||||||
moderatorRoleIds: string[];
|
moderatorRoleIds: string[];
|
||||||
|
@@ -5,14 +5,16 @@ 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";
|
import { Achievement } from "./achievement.model";
|
||||||
|
import { UserWarning } from "./user_warning.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;
|
messageCount?: number;
|
||||||
reaction_count?: number;
|
reactionCount?: number;
|
||||||
|
birthday?: string;
|
||||||
ontime?: number;
|
ontime?: number;
|
||||||
level?: Level;
|
level?: Level;
|
||||||
server?: Server;
|
server?: Server;
|
||||||
@@ -29,6 +31,9 @@ export interface User extends DataWithHistory {
|
|||||||
|
|
||||||
achievementCount?: number;
|
achievementCount?: number;
|
||||||
achievements?: Achievement[];
|
achievements?: Achievement[];
|
||||||
|
|
||||||
|
userWarningCount?: number;
|
||||||
|
userWarnings?: UserWarning[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserFilter {
|
export interface UserFilter {
|
||||||
|
16
kdb-web/src/app/models/data/user_warning.model.ts
Normal file
16
kdb-web/src/app/models/data/user_warning.model.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { DataWithHistory } from "./data.model";
|
||||||
|
import { User, UserFilter } from "./user.model";
|
||||||
|
|
||||||
|
export interface UserWarning extends DataWithHistory {
|
||||||
|
id?: number;
|
||||||
|
user?: User;
|
||||||
|
description?: string;
|
||||||
|
author?: User;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserWarningFilter {
|
||||||
|
id?: number;
|
||||||
|
user?: UserFilter;
|
||||||
|
description?: string;
|
||||||
|
author?: UserFilter;
|
||||||
|
}
|
@@ -1,15 +1,22 @@
|
|||||||
export class Mutations {
|
export class Mutations {
|
||||||
static updateUser = `
|
static updateUser = `
|
||||||
mutation updateUser($id: ID, $xp: Int, $levelId: ID) {
|
mutation updateUser($id: ID, $xp: Int $birthday: String, $levelId: ID, $userWarnings: [UserWarningInput]) {
|
||||||
user {
|
user {
|
||||||
updateUser(input: { id: $id, xp: $xp, levelId: $levelId }) {
|
updateUser(input: { id: $id, xp: $xp, birthday: $birthday, levelId: $levelId, userWarnings: $userWarnings }) {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
xp
|
xp
|
||||||
|
messageCount
|
||||||
|
reactionCount
|
||||||
|
birthday
|
||||||
level {
|
level {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
userWarnings {
|
||||||
|
id
|
||||||
|
description
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,7 +261,8 @@ export class Mutations {
|
|||||||
$teamChannelId: String,
|
$teamChannelId: String,
|
||||||
$loginMessageChannelId: String,
|
$loginMessageChannelId: String,
|
||||||
$defaultRoleId: String,
|
$defaultRoleId: String,
|
||||||
$shortRoleNameOnlySetHighestRole: Boolean
|
$shortRoleNameOnlySetHighestRole: Boolean,
|
||||||
|
$gameOfferNotificationChatId: String,
|
||||||
$featureFlags: [FeatureFlagInput],
|
$featureFlags: [FeatureFlagInput],
|
||||||
$afkChannelIds: [String],
|
$afkChannelIds: [String],
|
||||||
$moderatorRoleIds: [String],
|
$moderatorRoleIds: [String],
|
||||||
@@ -278,6 +286,7 @@ export class Mutations {
|
|||||||
loginMessageChannelId: $loginMessageChannelId,
|
loginMessageChannelId: $loginMessageChannelId,
|
||||||
defaultRoleId: $defaultRoleId,
|
defaultRoleId: $defaultRoleId,
|
||||||
shortRoleNameOnlySetHighestRole: $shortRoleNameOnlySetHighestRole,
|
shortRoleNameOnlySetHighestRole: $shortRoleNameOnlySetHighestRole,
|
||||||
|
gameOfferNotificationChatId: $gameOfferNotificationChatId,
|
||||||
featureFlags: $featureFlags,
|
featureFlags: $featureFlags,
|
||||||
afkChannelIds: $afkChannelIds,
|
afkChannelIds: $afkChannelIds,
|
||||||
moderatorRoleIds: $moderatorRoleIds,
|
moderatorRoleIds: $moderatorRoleIds,
|
||||||
@@ -299,6 +308,7 @@ export class Mutations {
|
|||||||
loginMessageChannelId
|
loginMessageChannelId
|
||||||
defaultRoleId
|
defaultRoleId
|
||||||
shortRoleNameOnlySetHighestRole
|
shortRoleNameOnlySetHighestRole
|
||||||
|
gameOfferNotificationChatId
|
||||||
featureFlags {
|
featureFlags {
|
||||||
key
|
key
|
||||||
value
|
value
|
||||||
@@ -314,4 +324,50 @@ export class Mutations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static createUserWarning = `
|
||||||
|
mutation createUserWarning($name: String, $description: String, $attribute: String, $operator: String, $value: String, $serverId: ID) {
|
||||||
|
userWarning {
|
||||||
|
createUserWarning(input: { name: $name, description: $description, attribute: $attribute, operator: $operator, value: $value, serverId: $serverId}) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
attribute
|
||||||
|
operator
|
||||||
|
value
|
||||||
|
server {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
static updateUserWarning = `
|
||||||
|
mutation updateUserWarning($id: ID, $name: String, $description: String, $attribute: String, $operator: String, $value: String) {
|
||||||
|
userWarning {
|
||||||
|
updateUserWarning(input: { id: $id, name: $name, description: $description, attribute: $attribute, operator: $operator, value: $value}) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
attribute
|
||||||
|
operator
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
static deleteUserWarning = `
|
||||||
|
mutation deleteUserWarning($id: ID) {
|
||||||
|
userWarning {
|
||||||
|
deleteUserWarning(id: $id) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
@@ -208,7 +208,7 @@ export class Queries {
|
|||||||
query {
|
query {
|
||||||
shortRoleNamePositions
|
shortRoleNamePositions
|
||||||
}
|
}
|
||||||
`
|
`;
|
||||||
|
|
||||||
static shortRoleNameQuery = `
|
static shortRoleNameQuery = `
|
||||||
query ShortRoleNameList($serverId: ID, $filter: ShortRoleNameFilter, $page: Page, $sort: Sort) {
|
query ShortRoleNameList($serverId: ID, $filter: ShortRoleNameFilter, $page: Page, $sort: Sort) {
|
||||||
@@ -279,58 +279,101 @@ export class Queries {
|
|||||||
|
|
||||||
static userProfile = `
|
static userProfile = `
|
||||||
query UserProfile($serverId: ID, $userId: ID, $page: Page, $sort: Sort) {
|
query UserProfile($serverId: ID, $userId: ID, $page: Page, $sort: Sort) {
|
||||||
servers(filter: {id: $serverId}) {
|
userCount
|
||||||
userCount
|
users(filter: {server: {id: $serverId}, id: $userId}, page: $page, sort: $sort) {
|
||||||
users(filter: {id: $userId}, page: $page, sort: $sort) {
|
id
|
||||||
|
discordId
|
||||||
|
name
|
||||||
|
xp
|
||||||
|
messageCount
|
||||||
|
reactionCount
|
||||||
|
birthday
|
||||||
|
ontime
|
||||||
|
level {
|
||||||
id
|
id
|
||||||
discordId
|
|
||||||
name
|
name
|
||||||
xp
|
}
|
||||||
ontime
|
leftServer
|
||||||
level {
|
server {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
|
||||||
|
joinedServerCount
|
||||||
|
joinedServers {
|
||||||
|
id
|
||||||
|
joinedOn
|
||||||
|
leavedOn
|
||||||
|
}
|
||||||
|
|
||||||
|
createdAt
|
||||||
|
modifiedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
static userProfileAchievements = `
|
||||||
|
query UserProfile($serverId: ID, $userId: ID, $page: Page, $sort: Sort) {
|
||||||
|
users(filter: {server: {id: $serverId}, id: $userId}, page: $page, sort: $sort) {
|
||||||
|
achievementCount
|
||||||
|
achievements {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
createdAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
static userProfileVoiceChannelJoins = `
|
||||||
|
query UserProfile($serverId: ID, $userId: ID, $page: Page, $sort: Sort) {
|
||||||
|
users(filter: {server: {id: $serverId}, id: $userId}, page: $page, sort: $sort) {
|
||||||
|
joinedVoiceChannelCount
|
||||||
|
joinedVoiceChannels {
|
||||||
|
id
|
||||||
|
channelId
|
||||||
|
channelName
|
||||||
|
time
|
||||||
|
joinedOn
|
||||||
|
leavedOn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
static userProfileGameserverJoins = `
|
||||||
|
query UserProfile($serverId: ID, $userId: ID, $page: Page, $sort: Sort) {
|
||||||
|
users(filter: {server: {id: $serverId}, id: $userId}, page: $page, sort: $sort) {
|
||||||
|
userJoinedGameServerCount
|
||||||
|
userJoinedGameServers {
|
||||||
|
id
|
||||||
|
gameServer
|
||||||
|
time
|
||||||
|
joinedOn
|
||||||
|
leavedOn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
static userProfileWarnings = `
|
||||||
|
query UserProfile($serverId: ID, $userId: ID, $page: Page, $sort: Sort) {
|
||||||
|
users(filter: {server: {id: $serverId}, id: $userId}, page: $page, sort: $sort) {
|
||||||
|
userWarningCount
|
||||||
|
userWarnings {
|
||||||
|
id
|
||||||
|
user {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
leftServer
|
description
|
||||||
server {
|
author {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
|
||||||
joinedServerCount
|
|
||||||
joinedServers {
|
|
||||||
id
|
|
||||||
joinedOn
|
|
||||||
leavedOn
|
|
||||||
}
|
|
||||||
|
|
||||||
joinedVoiceChannelCount
|
|
||||||
joinedVoiceChannels {
|
|
||||||
id
|
|
||||||
channelId
|
|
||||||
channelName
|
|
||||||
time
|
|
||||||
joinedOn
|
|
||||||
leavedOn
|
|
||||||
}
|
|
||||||
|
|
||||||
userJoinedGameServerCount
|
|
||||||
userJoinedGameServers {
|
|
||||||
id
|
|
||||||
gameServer
|
|
||||||
time
|
|
||||||
joinedOn
|
|
||||||
leavedOn
|
|
||||||
}
|
|
||||||
|
|
||||||
achievements {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
createdAt
|
|
||||||
}
|
|
||||||
|
|
||||||
createdAt
|
createdAt
|
||||||
modifiedAt
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@ import { TechnicianConfig } from "../config/technician-config.model";
|
|||||||
import { ServerConfig } from "../config/server-config.model";
|
import { ServerConfig } from "../config/server-config.model";
|
||||||
import { ShortRoleName } from "../data/short_role_name.model";
|
import { ShortRoleName } from "../data/short_role_name.model";
|
||||||
import { FeatureFlag } from "../config/feature-flags.model";
|
import { FeatureFlag } from "../config/feature-flags.model";
|
||||||
|
import { UserWarning } from "../data/user_warning.model";
|
||||||
|
|
||||||
export interface Query {
|
export interface Query {
|
||||||
serverCount: number;
|
serverCount: number;
|
||||||
@@ -31,6 +32,11 @@ export interface UserListQuery {
|
|||||||
users: User[];
|
users: User[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UserWarningQuery {
|
||||||
|
userWarningCount: number;
|
||||||
|
userWarnings: UserWarning[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface GameServerListQuery {
|
export interface GameServerListQuery {
|
||||||
gameServerCount: number;
|
gameServerCount: number;
|
||||||
gameServers: GameServer[];
|
gameServers: GameServer[];
|
||||||
|
@@ -6,6 +6,7 @@ import { Achievement } from "../data/achievement.model";
|
|||||||
import { TechnicianConfig } from "../config/technician-config.model";
|
import { TechnicianConfig } from "../config/technician-config.model";
|
||||||
import { ServerConfig } from "../config/server-config.model";
|
import { ServerConfig } from "../config/server-config.model";
|
||||||
import { ShortRoleName } from "../data/short_role_name.model";
|
import { ShortRoleName } from "../data/short_role_name.model";
|
||||||
|
import { UserWarning } from "../data/user_warning.model";
|
||||||
|
|
||||||
export interface GraphQLResult {
|
export interface GraphQLResult {
|
||||||
data: {
|
data: {
|
||||||
@@ -77,3 +78,11 @@ export interface ShortRoleNameMutationResult {
|
|||||||
deleteShortRoleName?: ShortRoleName
|
deleteShortRoleName?: ShortRoleName
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UserWarningMutationResult {
|
||||||
|
userWarning: {
|
||||||
|
createUserWarning?: UserWarning
|
||||||
|
updateUserWarning?: UserWarning
|
||||||
|
deleteUserWarning?: UserWarning
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@@ -32,8 +32,37 @@ import { HideableHeaderComponent } from './components/hideable-header/hideable-h
|
|||||||
import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-select-columns.component';
|
import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-select-columns.component';
|
||||||
import { FeatureFlagListComponent } from './components/feature-flag-list/feature-flag-list.component';
|
import { FeatureFlagListComponent } from './components/feature-flag-list/feature-flag-list.component';
|
||||||
import { InputSwitchModule } from "primeng/inputswitch";
|
import { InputSwitchModule } from "primeng/inputswitch";
|
||||||
|
import { CalendarModule } from "primeng/calendar";
|
||||||
|
|
||||||
|
|
||||||
|
const PrimeNGModules = [
|
||||||
|
ButtonModule,
|
||||||
|
PasswordModule,
|
||||||
|
MenuModule,
|
||||||
|
DialogModule,
|
||||||
|
ProgressSpinnerModule,
|
||||||
|
HttpClientModule,
|
||||||
|
FormsModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
ToastModule,
|
||||||
|
ConfirmDialogModule,
|
||||||
|
TableModule,
|
||||||
|
InputTextModule,
|
||||||
|
CheckboxModule,
|
||||||
|
DropdownModule,
|
||||||
|
TranslateModule,
|
||||||
|
DynamicDialogModule,
|
||||||
|
PanelMenuModule,
|
||||||
|
PanelModule,
|
||||||
|
InputNumberModule,
|
||||||
|
ImageModule,
|
||||||
|
SidebarModule,
|
||||||
|
DataViewModule,
|
||||||
|
MultiSelectModule,
|
||||||
|
InputSwitchModule,
|
||||||
|
CalendarModule,
|
||||||
|
]
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AuthRolePipe,
|
AuthRolePipe,
|
||||||
@@ -48,66 +77,20 @@ import { InputSwitchModule } from "primeng/inputswitch";
|
|||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
ButtonModule,
|
...PrimeNGModules
|
||||||
PasswordModule,
|
|
||||||
MenuModule,
|
|
||||||
DialogModule,
|
|
||||||
ProgressSpinnerModule,
|
|
||||||
HttpClientModule,
|
|
||||||
FormsModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
ToastModule,
|
|
||||||
ConfirmDialogModule,
|
|
||||||
TableModule,
|
|
||||||
InputTextModule,
|
|
||||||
CheckboxModule,
|
|
||||||
DropdownModule,
|
|
||||||
TranslateModule,
|
|
||||||
DynamicDialogModule,
|
|
||||||
PanelMenuModule,
|
|
||||||
PanelModule,
|
|
||||||
InputNumberModule,
|
|
||||||
ImageModule,
|
|
||||||
SidebarModule,
|
|
||||||
DataViewModule,
|
|
||||||
MultiSelectModule,
|
|
||||||
InputSwitchModule,
|
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
ButtonModule,
|
...PrimeNGModules,
|
||||||
PasswordModule,
|
|
||||||
MenuModule,
|
|
||||||
DialogModule,
|
|
||||||
ProgressSpinnerModule,
|
|
||||||
HttpClientModule,
|
|
||||||
FormsModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
ToastModule,
|
|
||||||
ConfirmDialogModule,
|
|
||||||
TableModule,
|
|
||||||
InputTextModule,
|
|
||||||
CheckboxModule,
|
|
||||||
DropdownModule,
|
|
||||||
TranslateModule,
|
|
||||||
DynamicDialogModule,
|
|
||||||
PanelMenuModule,
|
|
||||||
PanelModule,
|
|
||||||
AuthRolePipe,
|
AuthRolePipe,
|
||||||
IpAddressPipe,
|
IpAddressPipe,
|
||||||
BoolPipe,
|
BoolPipe,
|
||||||
InputNumberModule,
|
|
||||||
ImageModule,
|
|
||||||
SidebarModule,
|
|
||||||
HistoryBtnComponent,
|
HistoryBtnComponent,
|
||||||
DataViewModule,
|
|
||||||
DataViewLayoutOptions,
|
DataViewLayoutOptions,
|
||||||
ConfigListComponent,
|
ConfigListComponent,
|
||||||
MultiSelectModule,
|
|
||||||
HideableColumnComponent,
|
HideableColumnComponent,
|
||||||
HideableHeaderComponent,
|
HideableHeaderComponent,
|
||||||
MultiSelectColumnsComponent,
|
MultiSelectColumnsComponent,
|
||||||
FeatureFlagListComponent,
|
FeatureFlagListComponent,
|
||||||
InputSwitchModule,
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class SharedModule {
|
export class SharedModule {
|
||||||
|
@@ -130,6 +130,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="content-row">
|
||||||
|
<div class="content-column">
|
||||||
|
<div class="content-data-name">{{'view.server.config.bot.game_offer_notification_chat_id' | translate}}:</div>
|
||||||
|
<p-dropdown class="content-data-value" [options]="textChannels" optionLabel="name" optionValue="id" [(ngModel)]="config.gameOfferNotificationChatId"
|
||||||
|
placeholder="{{'view.server.config.bot.game_offer_notification_chat_id' | translate}}"></p-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="content-divider"></div>
|
<div class="content-divider"></div>
|
||||||
<app-config-list [options]="voiceChannels" optionLabel="name" optionValue="id" translationKey="view.server.config.bot.afk_channels"
|
<app-config-list [options]="voiceChannels" optionLabel="name" optionValue="id" translationKey="view.server.config.bot.afk_channels"
|
||||||
[(data)]="config.afkChannelIds"></app-config-list>
|
[(data)]="config.afkChannelIds"></app-config-list>
|
||||||
|
@@ -124,6 +124,7 @@ export class ConfigComponent implements OnInit {
|
|||||||
loginMessageChannelId: this.config.loginMessageChannelId,
|
loginMessageChannelId: this.config.loginMessageChannelId,
|
||||||
defaultRoleId: this.config.defaultRoleId,
|
defaultRoleId: this.config.defaultRoleId,
|
||||||
shortRoleNameOnlySetHighestRole: this.config.shortRoleNameOnlySetHighestRole,
|
shortRoleNameOnlySetHighestRole: this.config.shortRoleNameOnlySetHighestRole,
|
||||||
|
gameOfferNotificationChatId: this.config.gameOfferNotificationChatId,
|
||||||
featureFlags: this.config.featureFlags,
|
featureFlags: this.config.featureFlags,
|
||||||
afkChannelIds: this.config.afkChannelIds,
|
afkChannelIds: this.config.afkChannelIds,
|
||||||
moderatorRoleIds: this.config.moderatorRoleIds,
|
moderatorRoleIds: this.config.moderatorRoleIds,
|
||||||
|
@@ -204,7 +204,7 @@
|
|||||||
<span class="p-column-title">{{'common.level' | translate}}:</span>
|
<span class="p-column-title">{{'common.level' | translate}}:</span>
|
||||||
<p-cellEditor>
|
<p-cellEditor>
|
||||||
<ng-template pTemplate="input">
|
<ng-template pTemplate="input">
|
||||||
<p-dropdown [options]="levels" [(ngModel)]="member.level" placeholder="{{'common.level' | translate}}"></p-dropdown>
|
<p-dropdown [options]="levels" [(ngModel)]="member.level" dataKey="id" placeholder="{{'common.level' | translate}}"></p-dropdown>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template pTemplate="output">
|
<ng-template pTemplate="output">
|
||||||
{{member.level.name}}
|
{{member.level.name}}
|
||||||
|
@@ -30,7 +30,32 @@
|
|||||||
<div class="content-row">
|
<div class="content-row">
|
||||||
<div class="content-column">
|
<div class="content-column">
|
||||||
<div class="content-data-name">{{'view.server.profile.xp' | translate}}:</div>
|
<div class="content-data-name">{{'view.server.profile.xp' | translate}}:</div>
|
||||||
<div class="content-data-value">{{user.xp}}</div>
|
<div *ngIf="!isEditing" class="content-data-value">{{user.xp}}</div>
|
||||||
|
<div *ngIf="isModerator && isEditing" class="content-data-value"><input class="table-edit-input" pInputText min="0" type="number" [(ngModel)]="user.xp"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content-row">
|
||||||
|
<div class="content-column">
|
||||||
|
<div class="content-data-name">{{'view.server.profile.message_count' | translate}}:</div>
|
||||||
|
<div class="content-data-value">{{user.messageCount}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content-row">
|
||||||
|
<div class="content-column">
|
||||||
|
<div class="content-data-name">{{'view.server.profile.reaction_count' | translate}}:</div>
|
||||||
|
<div class="content-data-value">{{user.reactionCount}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content-row">
|
||||||
|
<div class="content-column">
|
||||||
|
<div class="content-data-name">{{'view.server.profile.birthday' | translate}}:</div>
|
||||||
|
<div *ngIf="!isEditing" class="content-data-value">{{user.birthday}}</div>
|
||||||
|
<div *ngIf="isEditing" class="content-data-value">
|
||||||
|
<p-calendar [(ngModel)]="user.birthday" dateFormat="dd.mm.yy" [showIcon]="true"></p-calendar>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -41,17 +66,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="content-row">-->
|
|
||||||
<!-- <div class="content-column">-->
|
|
||||||
<!-- <div class="content-data-name">{{'view.server.profile.minecraft_id' | translate}}:</div>-->
|
|
||||||
<!-- <div class="content-data-value">{{user.minecraftId}}</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.level' | translate}}:</div>
|
<div class="content-data-name">{{'view.server.profile.level' | translate}}:</div>
|
||||||
<div class="content-data-value">{{user.level?.name}}</div>
|
<div *ngIf="!isEditing" class="content-data-value">{{user.level?.name}}</div>
|
||||||
|
<div *ngIf="isModerator && isEditing" class="content-data-value">
|
||||||
|
<p-dropdown [options]="levels" [(ngModel)]="user.level" dataKey="id" placeholder="{{'common.level' | translate}}">
|
||||||
|
</p-dropdown>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -76,9 +98,103 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="content-divider"></div>
|
||||||
|
<p-table #dt [value]="(user.userWarnings ?? [])" [responsive]="true" responsiveLayout="stack" [breakpoint]="'720px'" dataKey="id" editMode="row">
|
||||||
|
<ng-template pTemplate="caption">
|
||||||
|
<div class="table-caption">
|
||||||
|
<div class="table-caption-table-info">
|
||||||
|
<div class="table-caption-text">
|
||||||
|
<h3>{{'common.user_warnings' | translate}}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-caption-btn-wrapper btn-wrapper">
|
||||||
|
<button pButton label="{{'common.add' | translate}}" class="icon-btn btn"
|
||||||
|
icon="pi pi-plus" (click)="addNewUserWarning(dt)">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="header">
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'common.description' | translate}}</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th>
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'common.author' | translate}}</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th>
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'common.created_at' | translate}}</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th class="table-header-actions">
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'common.actions' | translate}}</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="body" let-value let-editing="editing" let-ri="rowIndex">
|
||||||
|
<tr [pEditableRow]="value">
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
<input class="table-edit-input" pInputText type="text" [(ngModel)]="value.description">
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{value.description}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
{{value.author?.name}}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{value.author?.name}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<span class="p-column-title">{{'common.created_at' | translate}}:</span>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
{{value.createdAt | date:'dd.MM.yy HH:mm'}}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{value.createdAt | date:'dd.MM.yy HH:mm'}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="btn-wrapper">
|
||||||
|
<button *ngIf="!editing" pButton type="button" class="btn danger-icon-btn" icon="pi pi-trash" (click)="deleteUserWarning(ri)"></button>
|
||||||
|
|
||||||
|
<button *ngIf="editing" pButton type="button" pSaveEditableRow class="btn icon-btn" icon="pi pi-check" (click)="editSaveUserWarning(value, ri)"></button>
|
||||||
|
<button *ngIf="editing" pButton type="button" pCancelEditableRow class="btn danger-icon-btn" icon="pi pi-times"
|
||||||
|
(click)="editCancelUserWarning(ri)"></button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</ng-template>
|
||||||
|
</p-table>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="content-divider"></div>
|
<div class="content-divider"></div>
|
||||||
|
|
||||||
<p-panel header="{{'view.server.profile.achievements.header' | translate}}" [toggleable]="true">
|
<p-panel header="{{'view.server.profile.achievements.header' | translate}}" [toggleable]="true" [collapsed]="true"
|
||||||
|
(onBeforeToggle)="onBeforeToggle($event.event, $event.collapsed)">
|
||||||
<div *ngFor="let achievement of user.achievements;">
|
<div *ngFor="let achievement of user.achievements;">
|
||||||
<div class="content-row">
|
<div class="content-row">
|
||||||
<div class="content-column">
|
<div class="content-column">
|
||||||
@@ -86,6 +202,11 @@
|
|||||||
<div class="content-data-value">{{achievement.name}}</div>
|
<div class="content-data-value">{{achievement.name}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="content-column">
|
||||||
|
<div class="content-data-name">{{'common.description' | translate}}:</div>
|
||||||
|
<div class="content-data-value">{{achievement.description}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="content-column">
|
<div class="content-column">
|
||||||
<div class="content-data-name">{{'view.server.profile.achievements.time' | translate}}:</div>
|
<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 class="content-data-value">{{achievement.createdAt | date:'dd.MM.yyyy HH:mm:ss'}}</div>
|
||||||
@@ -94,7 +215,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</p-panel>
|
</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" [collapsed]="true"
|
||||||
|
(onBeforeToggle)="onBeforeToggle($event.event, $event.collapsed)">
|
||||||
<div *ngFor="let join of user.joinedVoiceChannels;">
|
<div *ngFor="let join of user.joinedVoiceChannels;">
|
||||||
<div class="content-row">
|
<div class="content-row">
|
||||||
<div class="content-column">
|
<div class="content-column">
|
||||||
@@ -120,7 +242,8 @@
|
|||||||
</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" [collapsed]="true"
|
||||||
|
(onBeforeToggle)="onBeforeToggle($event.event, $event.collapsed)">
|
||||||
<div *ngFor="let join of user.userJoinedGameServers;">
|
<div *ngFor="let join of user.userJoinedGameServers;">
|
||||||
<div class="content-row">
|
<div class="content-row">
|
||||||
<div class="content-column">
|
<div class="content-column">
|
||||||
@@ -161,5 +284,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</p-panel>
|
</p-panel>
|
||||||
|
|
||||||
|
<div class="content-divider"></div>
|
||||||
|
|
||||||
|
<div class="content-row">
|
||||||
|
<div style="width: 100%; display: flex; gap: 10px; justify-content: end;">
|
||||||
|
<button pButton icon="pi pi-edit" label="{{'common.edit' | translate}}" class="btn login-form-submit-btn"
|
||||||
|
(click)="toogleEditUser()"></button>
|
||||||
|
<button pButton icon="pi pi-save" label="{{'common.save' | translate}}" class="btn login-form-submit-btn"
|
||||||
|
(click)="updateUser()" [disabled]="!isEditing"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import { Queries } from "../../../../models/graphql/queries.model";
|
import { Queries } from "../../../../models/graphql/queries.model";
|
||||||
import { UserListQuery } from "../../../../models/graphql/query.model";
|
import { LevelListQuery, Query, UserListQuery, UserWarningQuery } from "../../../../models/graphql/query.model";
|
||||||
import { SpinnerService } from "../../../../services/spinner/spinner.service";
|
import { SpinnerService } from "../../../../services/spinner/spinner.service";
|
||||||
import { DataService } from "../../../../services/data/data.service";
|
import { DataService } from "../../../../services/data/data.service";
|
||||||
import { User } from "../../../../models/data/user.model";
|
import { User } from "../../../../models/data/user.model";
|
||||||
@@ -10,8 +10,14 @@ import { AuthService } from "src/app/services/auth/auth.service";
|
|||||||
import { ToastService } from "src/app/services/toast/toast.service";
|
import { ToastService } from "src/app/services/toast/toast.service";
|
||||||
import { TranslateService } from "@ngx-translate/core";
|
import { TranslateService } from "@ngx-translate/core";
|
||||||
import { Server } from "../../../../models/data/server.model";
|
import { Server } from "../../../../models/data/server.model";
|
||||||
import { Subject } from "rxjs";
|
import { forkJoin, Subject, throwError } from "rxjs";
|
||||||
import { takeUntil } from "rxjs/operators";
|
import { catchError, takeUntil } from "rxjs/operators";
|
||||||
|
import { Table } from "primeng/table";
|
||||||
|
import { UpdateUserMutationResult } from "../../../../models/graphql/result.model";
|
||||||
|
import { Mutations } from "../../../../models/graphql/mutations.model";
|
||||||
|
import { MenuItem } from "primeng/api";
|
||||||
|
import { UserWarning } from "../../../../models/data/user_warning.model";
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-profile",
|
selector: "app-profile",
|
||||||
@@ -21,7 +27,13 @@ import { takeUntil } from "rxjs/operators";
|
|||||||
export class ProfileComponent implements OnInit, OnDestroy {
|
export class ProfileComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
user: User = { createdAt: "", modifiedAt: "" };
|
user: User = { createdAt: "", modifiedAt: "" };
|
||||||
|
levels!: MenuItem[];
|
||||||
private server: Server = {};
|
private server: Server = {};
|
||||||
|
private author?: UserDTO;
|
||||||
|
private clonedUserWarnings: UserWarning[] = [];
|
||||||
|
public isEditingNewUserWarning: boolean = false;
|
||||||
|
public isEditing: boolean = false;
|
||||||
|
public isModerator: boolean = false;
|
||||||
|
|
||||||
private unsubscriber = new Subject<void>();
|
private unsubscriber = new Subject<void>();
|
||||||
|
|
||||||
@@ -32,11 +44,17 @@ export class ProfileComponent implements OnInit, OnDestroy {
|
|||||||
private data: DataService,
|
private data: DataService,
|
||||||
private auth: AuthService,
|
private auth: AuthService,
|
||||||
private toast: ToastService,
|
private toast: ToastService,
|
||||||
private translate: TranslateService
|
private translate: TranslateService,
|
||||||
|
private toastService: ToastService
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
|
this.isEditing = false;
|
||||||
|
this.loadProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadProfile() {
|
||||||
this.route.params.pipe(takeUntil(this.unsubscriber)).subscribe(params => {
|
this.route.params.pipe(takeUntil(this.unsubscriber)).subscribe(params => {
|
||||||
this.data.getServerFromRoute(this.route).then(async (server) => {
|
this.data.getServerFromRoute(this.route).then(async (server) => {
|
||||||
if (!params["memberId"] || params["memberId"] == "undefined") {
|
if (!params["memberId"] || params["memberId"] == "undefined") {
|
||||||
@@ -45,6 +63,18 @@ export class ProfileComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
|
||||||
|
this.data.query<LevelListQuery>(Queries.levelQuery, {
|
||||||
|
serverId: server.id
|
||||||
|
},
|
||||||
|
(data: Query) => {
|
||||||
|
return data.servers[0];
|
||||||
|
}
|
||||||
|
).subscribe(data => {
|
||||||
|
this.levels = data.levels.map(level => {
|
||||||
|
return { label: level.name, value: level };
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
let authUser = await this.auth.getLoggedInUser();
|
let authUser = await this.auth.getLoggedInUser();
|
||||||
this.spinner.showSpinner();
|
this.spinner.showSpinner();
|
||||||
let user: UserDTO | null = authUser?.users?.find(u => u.server == server.id) ?? null;
|
let user: UserDTO | null = authUser?.users?.find(u => u.server == server.id) ?? null;
|
||||||
@@ -54,27 +84,161 @@ export class ProfileComponent implements OnInit, OnDestroy {
|
|||||||
await this.router.navigate(["/server", server.id]);
|
await this.router.navigate(["/server", server.id]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.author = user;
|
||||||
|
this.isModerator = user?.isModerator;
|
||||||
|
|
||||||
this.data.query<UserListQuery>(Queries.userProfile, {
|
this.data.query<UserListQuery>(Queries.userProfile, {
|
||||||
serverId: this.server.id,
|
serverId: this.server.id,
|
||||||
userId: params["memberId"]
|
userId: params["memberId"]
|
||||||
},
|
|
||||||
(x: { servers: Server[] }) => {
|
|
||||||
return x.servers[0];
|
|
||||||
}
|
}
|
||||||
).subscribe(users => {
|
).subscribe(users => {
|
||||||
if (!users.users[0]) {
|
if (!users.users[0]) {
|
||||||
this.router.navigate([`/server/${server.id}`]);
|
this.router.navigate([`/server/${server.id}`]);
|
||||||
}
|
}
|
||||||
this.user = users.users[0];
|
this.user = users.users[0];
|
||||||
this.spinner.hideSpinner();
|
|
||||||
|
this.data.query<UserWarningQuery>(Queries.userProfileWarnings, {
|
||||||
|
serverId: this.server.id,
|
||||||
|
userId: this.user.id
|
||||||
|
},
|
||||||
|
(data: UserListQuery) => {
|
||||||
|
return data.users[0];
|
||||||
|
}
|
||||||
|
).subscribe(result => {
|
||||||
|
this.user.userWarningCount = result.userWarningCount;
|
||||||
|
this.user.userWarnings = result.userWarnings;
|
||||||
|
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public toogleEditUser() {
|
||||||
|
this.isEditing = !this.isEditing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateUser() {
|
||||||
|
this.spinner.showSpinner();
|
||||||
|
this.data.mutation<UpdateUserMutationResult>(Mutations.updateUser, {
|
||||||
|
id: this.user.id,
|
||||||
|
xp: this.user.xp,
|
||||||
|
birthday: moment(this.user.birthday).format("DD.MM.YYYY"),
|
||||||
|
levelId: this.user.level?.id,
|
||||||
|
userWarnings: this.user.userWarnings?.map(userWarning => {
|
||||||
|
return {
|
||||||
|
id: userWarning.id,
|
||||||
|
user: userWarning.user?.id ?? this.user.id,
|
||||||
|
description: userWarning.description,
|
||||||
|
author: userWarning.author?.id ?? this.author?.id
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
).pipe(catchError(err => {
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.isEditing = false;
|
||||||
|
return throwError(err);
|
||||||
|
})).subscribe(_ => {
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.toastService.success(this.translate.instant("view.server.members.message.user_changed"), this.translate.instant("view.server.members.message.user_changed_d", { name: this.user.name }));
|
||||||
|
this.isEditing = false;
|
||||||
|
this.loadProfile();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public ngOnDestroy(): void {
|
public ngOnDestroy(): void {
|
||||||
this.unsubscriber.next();
|
this.unsubscriber.next();
|
||||||
this.unsubscriber.complete();
|
this.unsubscriber.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onBeforeToggle(event: Event, collapsed: boolean) {
|
||||||
|
const filterUser = (x: { users: User[] }) => {
|
||||||
|
const users = x.users ?? [];
|
||||||
|
return users[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (collapsed) {
|
||||||
|
this.spinner.showSpinner();
|
||||||
|
forkJoin([
|
||||||
|
this.data.query<User>(Queries.userProfileAchievements, {
|
||||||
|
serverId: this.server.id,
|
||||||
|
userId: this.user.id
|
||||||
|
},
|
||||||
|
filterUser
|
||||||
|
),
|
||||||
|
this.data.query<User>(Queries.userProfileVoiceChannelJoins, {
|
||||||
|
serverId: this.server.id,
|
||||||
|
userId: this.user.id
|
||||||
|
},
|
||||||
|
filterUser
|
||||||
|
),
|
||||||
|
this.data.query<User>(Queries.userProfileGameserverJoins, {
|
||||||
|
serverId: this.server.id,
|
||||||
|
userId: this.user.id
|
||||||
|
},
|
||||||
|
filterUser
|
||||||
|
)
|
||||||
|
]).subscribe(data => {
|
||||||
|
this.user.achievementCount = data[0].achievementCount;
|
||||||
|
this.user.achievements = data[0].achievements;
|
||||||
|
|
||||||
|
this.user.joinedVoiceChannelCount = data[1].joinedVoiceChannelCount;
|
||||||
|
this.user.joinedVoiceChannels = data[1].joinedVoiceChannels;
|
||||||
|
|
||||||
|
this.user.userJoinedGameServerCount = data[2].userJoinedGameServerCount;
|
||||||
|
this.user.userJoinedGameServers = data[2].userJoinedGameServers;
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.user.achievementCount = 0;
|
||||||
|
this.user.achievements = [];
|
||||||
|
|
||||||
|
this.user.userJoinedGameServerCount = 0;
|
||||||
|
this.user.userJoinedGameServers = [];
|
||||||
|
|
||||||
|
this.user.joinedVoiceChannelCount = 0;
|
||||||
|
this.user.joinedVoiceChannels = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public addNewUserWarning(table: Table) {
|
||||||
|
const newWarning: UserWarning = {
|
||||||
|
description: "",
|
||||||
|
user: this.user
|
||||||
|
};
|
||||||
|
|
||||||
|
this.user.userWarnings = [newWarning, ...this.user.userWarnings ?? []];
|
||||||
|
|
||||||
|
table.initRowEdit(newWarning);
|
||||||
|
|
||||||
|
const index = this.user.userWarnings.findIndex(l => l.id == newWarning.id);
|
||||||
|
this.onRowEditInit(table, newWarning, index);
|
||||||
|
|
||||||
|
this.isEditingNewUserWarning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onRowEditInit(table: Table, user: User, index: number): void {
|
||||||
|
this.clonedUserWarnings[index] = { ...user };
|
||||||
|
}
|
||||||
|
|
||||||
|
public deleteUserWarning(index: number) {
|
||||||
|
this.user.userWarnings?.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public editSaveUserWarning(value: any, index: number) {
|
||||||
|
this.isEditingNewUserWarning = false;
|
||||||
|
if (!value.value || !this.user.userWarnings || this.user.userWarnings[index] == this.clonedUserWarnings[index]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete this.clonedUserWarnings[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public editCancelUserWarning(index: number) {
|
||||||
|
if (this.user.userWarnings) {
|
||||||
|
this.user.userWarnings[index] = this.clonedUserWarnings[index];
|
||||||
|
}
|
||||||
|
delete this.clonedUserWarnings[index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,11 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from "@angular/core";
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from "@angular/common";
|
||||||
import { ServerDashboardComponent } from './server-dashboard/server-dashboard.component';
|
import { ServerDashboardComponent } from "./server-dashboard/server-dashboard.component";
|
||||||
import { ServerRoutingModule } from './server-routing.module';
|
import { ServerRoutingModule } from "./server-routing.module";
|
||||||
import { SharedModule } from '../../shared/shared.module';
|
import { SharedModule } from "../../shared/shared.module";
|
||||||
import { ProfileComponent } from './profile/profile.component';
|
import { ProfileComponent } from "./profile/profile.component";
|
||||||
import { MembersComponent } from './members/members.component';
|
import { MembersComponent } from "./members/members.component";
|
||||||
import { ClientComponent } from './server-dashboard/components/client/client.component';
|
import { ClientComponent } from "./server-dashboard/components/client/client.component";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@@ -194,7 +194,6 @@ export class SidebarService {
|
|||||||
let user: UserDTO | null = authUser?.users?.find(u => u.server == this.server?.id) ?? null;
|
let user: UserDTO | null = authUser?.users?.find(u => u.server == this.server?.id) ?? null;
|
||||||
let isTechnician = (authUser?.users?.map(u => u.isTechnician).filter(u => u) ?? []).length > 0;
|
let isTechnician = (authUser?.users?.map(u => u.isTechnician).filter(u => u) ?? []).length > 0;
|
||||||
let isTechnicianAndFullAccessActive = this.hasFeature("TechnicianFullAccess") && isTechnician;
|
let isTechnicianAndFullAccessActive = this.hasFeature("TechnicianFullAccess") && isTechnician;
|
||||||
console.log(this.hasFeature("TechnicianFullAccess"))
|
|
||||||
|
|
||||||
if (build || this.menuItems$.value.length == 0) {
|
if (build || this.menuItems$.value.length == 0) {
|
||||||
await this.buildMenu(user, hasPermission, isTechnician);
|
await this.buildMenu(user, hasPermission, isTechnician);
|
||||||
|
@@ -128,6 +128,7 @@
|
|||||||
"add": "Hinzufügen",
|
"add": "Hinzufügen",
|
||||||
"attribute": "Attribut",
|
"attribute": "Attribut",
|
||||||
"auth_role": "Rolle",
|
"auth_role": "Rolle",
|
||||||
|
"author": "Autor",
|
||||||
"bool_as_string": {
|
"bool_as_string": {
|
||||||
"false": "Nein",
|
"false": "Nein",
|
||||||
"true": "Ja"
|
"true": "Ja"
|
||||||
@@ -138,6 +139,7 @@
|
|||||||
"created_at": "Erstellt am",
|
"created_at": "Erstellt am",
|
||||||
"description": "Beschreibung",
|
"description": "Beschreibung",
|
||||||
"discord_id": "Discord Id",
|
"discord_id": "Discord Id",
|
||||||
|
"edit": "Bearbeiten",
|
||||||
"email": "E-Mail",
|
"email": "E-Mail",
|
||||||
"emoji": "Emoji",
|
"emoji": "Emoji",
|
||||||
"error": "Fehler",
|
"error": "Fehler",
|
||||||
@@ -192,6 +194,7 @@
|
|||||||
"role": "Rolle",
|
"role": "Rolle",
|
||||||
"rule_count": "Regeln",
|
"rule_count": "Regeln",
|
||||||
"save": "Speichern",
|
"save": "Speichern",
|
||||||
|
"user_warnings": "Verwarnungen",
|
||||||
"users": "Benutzer",
|
"users": "Benutzer",
|
||||||
"value": "Wert",
|
"value": "Wert",
|
||||||
"xp": "XP"
|
"xp": "XP"
|
||||||
@@ -419,7 +422,7 @@
|
|||||||
"afk_channels": "AFK Sprachkanäle",
|
"afk_channels": "AFK Sprachkanäle",
|
||||||
"afk_command_channel_id": "AFK Kanal für den Befehl /afk",
|
"afk_command_channel_id": "AFK Kanal für den Befehl /afk",
|
||||||
"default_role_id": "Standardrolle des Servers",
|
"default_role_id": "Standardrolle des Servers",
|
||||||
"short_role_name_only_set_highest_role": "Bei Rollen Kürzeln nur die höchste Rolle verwenden",
|
"game_offer_notification_chat_id": "Benachrichtungskanal für Spiel Angebote",
|
||||||
"header": "Bot Konfiguration",
|
"header": "Bot Konfiguration",
|
||||||
"help_voice_channel_id": "Sprachkanal für Hilfsbenachrichtung",
|
"help_voice_channel_id": "Sprachkanal für Hilfsbenachrichtung",
|
||||||
"login_message_channel_id": "Kanal für die Nachricht vom Bot nach Start",
|
"login_message_channel_id": "Kanal für die Nachricht vom Bot nach Start",
|
||||||
@@ -428,6 +431,7 @@
|
|||||||
"message_delete_timer": "Zeit bis zum löschen einer Botnachricht in sekunden",
|
"message_delete_timer": "Zeit bis zum löschen einer Botnachricht in sekunden",
|
||||||
"moderator_roles": "Moderator Rollen",
|
"moderator_roles": "Moderator Rollen",
|
||||||
"notification_chat_id": "Benachrichtungskanal",
|
"notification_chat_id": "Benachrichtungskanal",
|
||||||
|
"short_role_name_only_set_highest_role": "Bei Rollen Kürzeln nur die höchste Rolle verwenden",
|
||||||
"team_channel_id": "Team chat",
|
"team_channel_id": "Team chat",
|
||||||
"xp_per_achievement": "XP für Errungenschaft",
|
"xp_per_achievement": "XP für Errungenschaft",
|
||||||
"xp_per_event_participation": "XP für Event Teilnahme",
|
"xp_per_event_participation": "XP für Event Teilnahme",
|
||||||
@@ -486,6 +490,7 @@
|
|||||||
"header": "Errungeschaften",
|
"header": "Errungeschaften",
|
||||||
"time": "Erreicht am"
|
"time": "Erreicht am"
|
||||||
},
|
},
|
||||||
|
"birthday": "Geburtstag",
|
||||||
"header": "Dein Profil",
|
"header": "Dein Profil",
|
||||||
"joined_game_server": {
|
"joined_game_server": {
|
||||||
"header": "Gameserver-beitritte",
|
"header": "Gameserver-beitritte",
|
||||||
@@ -503,11 +508,13 @@
|
|||||||
},
|
},
|
||||||
"left_server": "Hat Server verlassen",
|
"left_server": "Hat Server verlassen",
|
||||||
"level": "Level",
|
"level": "Level",
|
||||||
|
"message_count": "Anzahl Nachrichten",
|
||||||
"minecraft_id": "Minecraft Id",
|
"minecraft_id": "Minecraft Id",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"ontime": "Ontime",
|
"ontime": "Ontime",
|
||||||
"permission_denied": "Zugriff verweigert!",
|
"permission_denied": "Zugriff verweigert!",
|
||||||
"permission_denied_d": "Du musst Moderator sein, um andere Profile sehen zu können!",
|
"permission_denied_d": "Du musst Moderator sein, um andere Profile sehen zu können!",
|
||||||
|
"reaction_count": "Anzahl Reaktionen",
|
||||||
"xp": "XP"
|
"xp": "XP"
|
||||||
},
|
},
|
||||||
"short_role_names": {
|
"short_role_names": {
|
||||||
|
@@ -128,6 +128,7 @@
|
|||||||
"add": "Add",
|
"add": "Add",
|
||||||
"attribute": "Attribute",
|
"attribute": "Attribute",
|
||||||
"auth_role": "Role",
|
"auth_role": "Role",
|
||||||
|
"author": "Author",
|
||||||
"bool_as_string": {
|
"bool_as_string": {
|
||||||
"false": "No",
|
"false": "No",
|
||||||
"true": "Yes"
|
"true": "Yes"
|
||||||
@@ -138,6 +139,7 @@
|
|||||||
"created_at": "Created at",
|
"created_at": "Created at",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
"discord_id": "Discord Id",
|
"discord_id": "Discord Id",
|
||||||
|
"edit": "Edit",
|
||||||
"email": "E-Mail",
|
"email": "E-Mail",
|
||||||
"emoji": "Emoji",
|
"emoji": "Emoji",
|
||||||
"error": "Error",
|
"error": "Error",
|
||||||
@@ -192,6 +194,7 @@
|
|||||||
"role": "Role",
|
"role": "Role",
|
||||||
"rule_count": "Rules",
|
"rule_count": "Rules",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
|
"user_warnings": "User warnings",
|
||||||
"users": "User",
|
"users": "User",
|
||||||
"value": "Value",
|
"value": "Value",
|
||||||
"xp": "XP"
|
"xp": "XP"
|
||||||
@@ -419,7 +422,7 @@
|
|||||||
"afk_channels": "AFK Voicechannel",
|
"afk_channels": "AFK Voicechannel",
|
||||||
"afk_command_channel_id": "AFK Channel for the command /afk",
|
"afk_command_channel_id": "AFK Channel for the command /afk",
|
||||||
"default_role_id": "Default role",
|
"default_role_id": "Default role",
|
||||||
"short_role_name_only_set_highest_role": "For role abbreviations use only the highest role",
|
"game_offer_notification_chat_id": "Notification channel for game sales",
|
||||||
"header": "Bot configuration",
|
"header": "Bot configuration",
|
||||||
"help_voice_channel_id": "Voicechannel für help notifications",
|
"help_voice_channel_id": "Voicechannel für help notifications",
|
||||||
"login_message_channel_id": "Channel for bot message after start",
|
"login_message_channel_id": "Channel for bot message after start",
|
||||||
@@ -428,6 +431,7 @@
|
|||||||
"message_delete_timer": "Time to wait before delete bot messages",
|
"message_delete_timer": "Time to wait before delete bot messages",
|
||||||
"moderator_roles": "Moderator roles",
|
"moderator_roles": "Moderator roles",
|
||||||
"notification_chat_id": "Notification channel",
|
"notification_chat_id": "Notification channel",
|
||||||
|
"short_role_name_only_set_highest_role": "For role abbreviations use only the highest role",
|
||||||
"team_channel_id": "Team chat",
|
"team_channel_id": "Team chat",
|
||||||
"xp_per_achievement": "XP for achievement",
|
"xp_per_achievement": "XP for achievement",
|
||||||
"xp_per_event_participation": "XP for event participation",
|
"xp_per_event_participation": "XP for event participation",
|
||||||
@@ -486,6 +490,7 @@
|
|||||||
"header": "Achievements",
|
"header": "Achievements",
|
||||||
"time": "Reached at"
|
"time": "Reached at"
|
||||||
},
|
},
|
||||||
|
"birthday": "Birthday",
|
||||||
"header": "Profile",
|
"header": "Profile",
|
||||||
"joined_game_server": {
|
"joined_game_server": {
|
||||||
"header": "Game server accessions",
|
"header": "Game server accessions",
|
||||||
@@ -503,11 +508,13 @@
|
|||||||
},
|
},
|
||||||
"left_server": "Leaved server",
|
"left_server": "Leaved server",
|
||||||
"level": "Level",
|
"level": "Level",
|
||||||
|
"message_count": "Message count",
|
||||||
"minecraft_id": "Minecraft Id",
|
"minecraft_id": "Minecraft Id",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"ontime": "Ontime",
|
"ontime": "Ontime",
|
||||||
"permission_denied": "Access denied!",
|
"permission_denied": "Access denied!",
|
||||||
"permission_denied_d": "You have to be moderator to see other profiles!",
|
"permission_denied_d": "You have to be moderator to see other profiles!",
|
||||||
|
"reaction_count": "Reaction count",
|
||||||
"xp": "XP"
|
"xp": "XP"
|
||||||
},
|
},
|
||||||
"short_role_names": {
|
"short_role_names": {
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"WebVersion": {
|
"WebVersion": {
|
||||||
"Major": "1",
|
"Major": "1",
|
||||||
"Minor": "1",
|
"Minor": "2",
|
||||||
"Micro": "10"
|
"Micro": "0"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -201,10 +201,10 @@ header {
|
|||||||
|
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.content-divider {
|
.content-divider {
|
||||||
margin: 5px 0;
|
margin: 10px 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p-panel {
|
p-panel {
|
||||||
@@ -493,7 +493,7 @@ header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content-divider {
|
.content-divider {
|
||||||
margin: 5px 0;
|
margin: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-input-field {
|
.content-input-field {
|
||||||
|
@@ -94,8 +94,13 @@ p-table {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-dropdown {
|
.content-row {
|
||||||
width: 100% !important;
|
p-dropdown,
|
||||||
|
.p-dropdown,
|
||||||
|
p-calendar,
|
||||||
|
.p-calendar, {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.pi-sort-alt:before {
|
.pi-sort-alt:before {
|
||||||
|
@@ -20,7 +20,8 @@
|
|||||||
background-color: $primaryBackgroundColor;
|
background-color: $primaryBackgroundColor;
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
h2 {
|
h2,
|
||||||
|
h3 {
|
||||||
color: $primaryHeaderColor;
|
color: $primaryHeaderColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,7 +20,8 @@
|
|||||||
background-color: $primaryBackgroundColor;
|
background-color: $primaryBackgroundColor;
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
h2 {
|
h2,
|
||||||
|
h3 {
|
||||||
color: $primaryHeaderColor;
|
color: $primaryHeaderColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,7 +21,8 @@
|
|||||||
|
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
h2 {
|
h2,
|
||||||
|
h3 {
|
||||||
color: $primaryHeaderColor;
|
color: $primaryHeaderColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,4 +683,77 @@
|
|||||||
p-inputNumber {
|
p-inputNumber {
|
||||||
background-color: $primaryBackgroundColor !important;
|
background-color: $primaryBackgroundColor !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p-calendar > span > button {
|
||||||
|
background-color: $primaryHeaderColor !important;
|
||||||
|
border: 1px solid $primaryHeaderColor !important;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-calendar {
|
||||||
|
.p-datepicker:not(.p-datepicker-inline) {
|
||||||
|
background-color: $secondaryBackgroundColor !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-datepicker {
|
||||||
|
.p-datepicker-header {
|
||||||
|
color: $primaryHeaderColor !important;
|
||||||
|
background-color: $primaryBackgroundColor !important;
|
||||||
|
|
||||||
|
.p-datepicker-title .p-datepicker-year,
|
||||||
|
.p-datepicker-title .p-datepicker-month,
|
||||||
|
.p-datepicker .p-datepicker-header .p-datepicker-title .p-datepicker-month {
|
||||||
|
color: $primaryTextColor !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $primaryHeaderColor !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table td > span {
|
||||||
|
color: $primaryTextColor !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $primaryHeaderColor !important;
|
||||||
|
background-color: $primaryBackgroundColor !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table td.p-datepicker-today > span {
|
||||||
|
color: $primaryHeaderColor !important;
|
||||||
|
background-color: $primaryBackgroundColor !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
table td > span.p-highlight {
|
||||||
|
color: $primaryHeaderColor !important;
|
||||||
|
background-color: $primaryBackgroundColor !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-yearpicker .p-yearpicker-year,
|
||||||
|
.p-monthpicker .p-monthpicker-month:not(.p-disabled):not(.p-highlight) {
|
||||||
|
color: $primaryTextColor !important;
|
||||||
|
background-color: $secondaryBackgroundColor !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $primaryHeaderColor !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,8 @@
|
|||||||
background-color: $primaryBackgroundColor;
|
background-color: $primaryBackgroundColor;
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
h2 {
|
h2,
|
||||||
|
h3 {
|
||||||
color: $primaryHeaderColor;
|
color: $primaryHeaderColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user