18 Commits

129 changed files with 409 additions and 1540 deletions

View File

@@ -8,24 +8,36 @@ on:
jobs:
on-push-deploy_sh-edraft:
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: sh-edraft.de/act-runner:latest
container: catthehacker/ubuntu:act-latest
steps:
- name: Setup Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10.12"
- run: python -v
- name: Setup docker
uses: https://github.com/papodaca/install-docker-action@main
- run: docker -v
- name: Clone Repository
uses: https://github.com/actions/checkout@v3
with:
token: ${{ secrets.CI_ACCESS_TOKEN }}
submodules: true
- name: Shutdown stack
run: docker stack rm sdb_staging
- name: Prepare bot build
run: |
cd bot
python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
cpl i
- name: Build docker bot
run: |
cd bot
docker image prune -f
cpl docker-build
- name: Setup node
uses: https://github.com/actions/setup-node@v3
@@ -33,31 +45,13 @@ jobs:
run: |
cd web
npm install -g ts-node
npm ci
- name: Shutdown stack
run: docker stack rm sdb_dev
- name: Build docker bot
run: |
cd bot
docker image prune -f
cpl build
docker build -t sh-edraft.de/sdb-bot:$(cpl gv)-dev .
npm i
- name: Build docker web
run: |
cd web
docker image prune -f
cp src/favicon.dev.ico src/favicon.ico
npm run build
docker build -t sh-edraft.de/sdb-web:$(npm run -s gv)-dev .
- name: Set version
run: |
cd bot/docker
chmod +x ./set-docker-compose-image-version.sh
./set-docker-compose-image-version.sh sh-edraft.de/sdb-bot:$(cd ../; cpl gv)-dev sh-edraft.de/sdb-web:$(cd ../../web; npm run -s gv;)-dev
npm run docker-build
- name: Deploy Stack to sh-edraft.de
uses: https://github.com/kgierke/portainer-stack-deployment@v1
@@ -66,6 +60,6 @@ jobs:
portainer-username: "gitea_job"
portainer-password: "${{ secrets.docker_job }}"
portainer-endpoint: 2
name: sdb_dev
file: bot/docker/docker-compose.dev.yml
name: sdb_staging
file: ./docker-compose.staging.yml
variables: '{}'

View File

@@ -1,5 +1,5 @@
name: Deploy prod on push
run-name: Deploy prod on push
name: Deploy dev on push
run-name: Deploy dev on push
on:
push:
branches:
@@ -8,24 +8,36 @@ on:
jobs:
on-push-deploy_sh-edraft:
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: sh-edraft.de/act-runner:latest
container: catthehacker/ubuntu:act-latest
steps:
- name: Setup Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10.12"
- run: python -v
- name: Setup docker
uses: https://github.com/papodaca/install-docker-action@main
- run: docker -v
- name: Clone Repository
uses: https://github.com/actions/checkout@v3
with:
token: ${{ secrets.CI_ACCESS_TOKEN }}
submodules: true
- name: Shutdown stack
run: docker stack rm sdb_prod
- name: Prepare bot build
run: |
cd bot
python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
cpl i
- name: Build docker bot
run: |
cd bot
docker image prune -f
cpl docker-build
- name: Setup node
uses: https://github.com/actions/setup-node@v3
@@ -33,30 +45,13 @@ jobs:
run: |
cd web
npm install -g ts-node
npm ci
- name: Shutdown stack
run: docker stack rm sdb_prod
- name: Build docker bot
run: |
cd bot
docker image prune -f
cpl build
docker build -t sh-edraft.de/sdb-bot:$(cpl gv) .
npm i
- name: Build docker web
run: |
cd web
docker image prune -f
npm run build
docker build -t sh-edraft.de/sdb-web:$(npm run -s gv) .
- name: Set version
run: |
cd bot/docker
chmod +x ./set-docker-compose-image-version.sh
./set-docker-compose-image-version.sh sh-edraft.de/sdb-bot:$(cd ../; cpl gv) sh-edraft.de/sdb-web:$(cd ../../web; npm run -s gv;)
npm run docker-build
- name: Deploy Stack to sh-edraft.de
uses: https://github.com/kgierke/portainer-stack-deployment@v1
@@ -66,5 +61,5 @@ jobs:
portainer-password: "${{ secrets.docker_job }}"
portainer-endpoint: 2
name: sdb_prod
file: bot/docker/docker-compose.yml
file: ./docker-compose.yml
variables: '{}'

View File

@@ -1,71 +0,0 @@
name: Deploy staging on push
run-name: Deploy staging on push
on:
push:
branches:
- staging
jobs:
on-push-deploy_sh-edraft:
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: sh-edraft.de/act-runner:latest
steps:
- name: Setup docker
uses: https://github.com/papodaca/install-docker-action@main
- run: docker -v
- name: Clone Repository
uses: https://github.com/actions/checkout@v3
with:
token: ${{ secrets.CI_ACCESS_TOKEN }}
submodules: true
- name: Prepare bot build
run: |
cd bot
python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
cpl i
- name: Setup node
uses: https://github.com/actions/setup-node@v3
- name: Prepare web build
run: |
cd web
npm install -g ts-node
npm ci
- name: Shutdown stack
run: docker stack rm sdb_staging
- name: Build docker bot
run: |
cd bot
docker image prune -f
cpl build
docker build -t sh-edraft.de/sdb-bot:$(cpl gv)-staging .
- name: Build docker web
run: |
cd web
docker image prune -f
cp src/favicon.staging.ico src/favicon.ico
npm run build
docker build -t sh-edraft.de/sdb-web:$(npm run -s gv)-staging .
- name: Set version
run: |
cd bot/docker
chmod +x ./set-docker-compose-image-version.sh
./set-docker-compose-image-version.sh sh-edraft.de/sdb-bot:$(cd ../; cpl gv)-staging sh-edraft.de/sdb-web:$(cd ../../web; npm run -s gv;)-staging
- name: Deploy Stack to sh-edraft.de
uses: https://github.com/kgierke/portainer-stack-deployment@v1
with:
portainer-url: "https://docker.sh-edraft.de"
portainer-username: "gitea_job"
portainer-password: "${{ secrets.docker_job }}"
portainer-endpoint: 2
name: sdb_staging
file: bot/docker/docker-compose.staging.yml
variables: '{}'

Submodule bot/docker deleted from 9c0dc59534

View File

@@ -11,7 +11,6 @@ from bot_api.api_thread import ApiThread
from bot_core.abc.task_abc import TaskABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_core.environment_variables import MAINTENANCE
from bot_core.service.data_integrity_service import DataIntegrityService
@@ -59,9 +58,8 @@ class Application(DiscordBotApplicationABC):
return
self._logger.info(__name__, f"Try to start {DiscordBotService.__name__}")
if not self._config.get_configuration(MAINTENANCE):
for task in self._tasks:
await self._bot.add_cog(task)
for task in self._tasks:
await self._bot.add_cog(task)
await self._bot.start_async()
await self._bot.stop_async()

View File

@@ -31,9 +31,7 @@
"icmplib==3.0.4",
"ariadne==0.20.1",
"cryptography==41.0.4",
"discord==2.3.2",
"bs4==0.0.1",
"lxml==4.9.3"
"discord==2.3.2"
],
"DevDependencies": [
"cpl-cli==2023.4.0.post3",

View File

@@ -9,7 +9,7 @@ from bot.application import Application
from bot.extension.init_bot_extension import InitBotExtension
from bot.startup import Startup
from bot.startup_discord_extension import StartupDiscordExtension
from bot_data.startup_migration_extension import StartupMigrationExtension
from bot.startup_migration_extension import StartupMigrationExtension
from bot.startup_module_extension import StartupModuleExtension
from bot.startup_settings_extension import StartupSettingsExtension
from bot_api.app_api_extension import AppApiExtension

View File

@@ -20,8 +20,6 @@ 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.level_migration import LevelMigration
from bot_data.migration.maintenance_mode_migration import MaintenanceModeMigration
from bot_data.migration.max_steam_offer_count_migration import MaxSteamOfferCountMigration
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_only_highest_migration import (
@@ -70,5 +68,3 @@ class StartupMigrationExtension(StartupExtensionABC):
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
services.add_transient(MigrationABC, MaxSteamOfferCountMigration) # 04.11.2023 #188 - 1.2.0
services.add_transient(MigrationABC, MaintenanceModeMigration) # 06.11.2023 #424 - 1.2.0

View File

@@ -8,7 +8,6 @@ from cpl_core.dependency_injection import ServiceCollectionABC
from cpl_core.environment import ApplicationEnvironmentABC
from bot_core.configuration.bot_logging_settings import BotLoggingSettings
from bot_core.environment_variables import MAINTENANCE, MIGRATION_ONLY
class StartupSettingsExtension(StartupExtensionABC):
@@ -18,14 +17,8 @@ class StartupSettingsExtension(StartupExtensionABC):
def configure_configuration(self, configuration: ConfigurationABC, environment: ApplicationEnvironmentABC):
# this shit has to be done here because we need settings in subsequent startup extensions
environment.set_working_directory(os.path.dirname(os.path.realpath(__file__)))
configuration.add_environment_variables("SDB_")
configuration.add_environment_variables("KDB_")
configuration.add_environment_variables("DISCORD_")
configuration.add_configuration(
MAINTENANCE, configuration.get_configuration(MAINTENANCE) in [True, "true", "True"]
)
configuration.add_configuration(
MIGRATION_ONLY, configuration.get_configuration(MIGRATION_ONLY) in [True, "true", "True"]
)
configuration.add_json_file(f"config/appsettings.json", optional=False)
configuration.add_json_file(f"config/appsettings.{environment.environment_name}.json", optional=True)

View File

@@ -90,8 +90,7 @@
"booting": "Ich fahre gerade hoch...",
"restart": "Muss neue Kekse holen...",
"running": "Ich esse Kekse :D",
"shutdown": "Ich werde bestimmt wieder kommen...",
"maintenance": "In Wartung!"
"shutdown": "Ich werde bestimmt wieder kommen..."
}
},
"modules": {

View File

@@ -75,7 +75,3 @@ class ClientUtilsABC(ABC):
@abstractmethod
async def check_default_role(self, member: Union[discord.User, discord.Member]):
pass
@abstractmethod
async def set_maintenance_mode(self, state: bool):
pass

View File

@@ -6,7 +6,6 @@ from cpl_core.dependency_injection import ServiceProviderABC
from cpl_discord.service import DiscordBotServiceABC
from discord.ext import commands
from bot_core.environment_variables import MAINTENANCE
from bot_core.logging.task_logger import TaskLogger
@@ -15,18 +14,14 @@ class TaskABC(commands.Cog):
def __init__(self):
commands.Cog.__init__(self)
@ServiceProviderABC.inject
def _is_maintenance(self, config: ConfigurationABC) -> bool:
return config.get_configuration(MAINTENANCE) is True
@ServiceProviderABC.inject
async def _wait_until_ready(self, config: ConfigurationABC, logger: TaskLogger, bot: DiscordBotServiceABC):
logger.debug(__name__, f"Waiting before {type(self).__name__}")
await bot.wait_until_ready()
async def wait():
is_ready = config.get_configuration("IS_READY") is True
if not is_ready:
is_ready = config.get_configuration("IS_READY")
if is_ready != "true":
await asyncio.sleep(1)
await wait()

View File

@@ -1,19 +1,16 @@
import asyncio
from cpl_core.configuration import ConfigurationABC
from cpl_core.logging import LoggerABC
from cpl_discord.events import OnReadyABC
from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe
from bot_core.abc.client_utils_abc import ClientUtilsABC
from bot_core.environment_variables import MAINTENANCE
class CoreExtensionOnReadyEvent(OnReadyABC):
def __init__(
self,
config: ConfigurationABC,
logger: LoggerABC,
bot: DiscordBotServiceABC,
client_utils: ClientUtilsABC,
@@ -21,7 +18,6 @@ class CoreExtensionOnReadyEvent(OnReadyABC):
):
OnReadyABC.__init__(self)
self._config = config
self._logger = logger
self._bot = bot
self._client_utils = client_utils
@@ -31,5 +27,5 @@ class CoreExtensionOnReadyEvent(OnReadyABC):
async def on_ready(self):
self._logger.debug(__name__, f"Module {type(self)} started")
await self._client_utils.set_maintenance_mode(self._config.get_configuration(MAINTENANCE))
await self._client_utils.presence_game("common.presence.running")
self._logger.trace(__name__, f"Module {type(self)} stopped")

View File

@@ -1,2 +0,0 @@
MIGRATION_ONLY = "MIGRATION_ONLY"
MAINTENANCE = "MAINTENANCE"

View File

@@ -1,4 +1,3 @@
import inspect
from typing import Optional
from discord.ext import commands
@@ -18,18 +17,11 @@ class EventChecks:
cls._client_utils = client_utils
@classmethod
def check_is_ready(cls, func):
async def check_if_bot_is_ready(*args, **kwargs):
def check_is_ready(cls):
async def check_if_bot_is_ready() -> bool:
result = await cls._client_utils.check_if_bot_is_ready_yet()
if not result:
raise CheckError(f"Bot is not ready")
return result
def empty(*args, **kwargs):
return
return empty
return await func(*args, **kwargs)
check_if_bot_is_ready.__name__ = func.__name__
sig = inspect.signature(func)
check_if_bot_is_ready.__signature__ = sig.replace(parameters=tuple(sig.parameters.values())[1:])
return check_if_bot_is_ready
return commands.check(check_if_bot_is_ready)

View File

@@ -16,7 +16,6 @@ from bot_core.abc.client_utils_abc import ClientUtilsABC
from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_core.environment_variables import MAINTENANCE
from bot_data.abc.client_repository_abc import ClientRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.user_joined_voice_channel_repository_abc import (
@@ -88,14 +87,7 @@ class ClientUtilsService(ClientUtilsABC):
return client
async def check_if_bot_is_ready_yet(self) -> bool:
if self._config.get_configuration(MAINTENANCE):
self._logger.warn(
__name__,
f"Bot is in maintenance mode",
)
return False
if self._config.get_configuration("IS_READY") is True:
if self._config.get_configuration("IS_READY") == "true":
return True
self._logger.debug(
@@ -247,10 +239,3 @@ class ClientUtilsService(ClientUtilsABC):
except Exception as e:
self._logger.error(__name__, f"Cannot check for default role for member {member.id}", e)
async def set_maintenance_mode(self, state: bool):
self._config.add_configuration(MAINTENANCE, state)
if state:
await self.presence_game("common.presence.maintenance")
else:
await self.presence_game("common.presence.running")

View File

@@ -7,7 +7,6 @@ from bot_data.abc.technician_config_repository_abc import TechnicianConfigReposi
from bot_data.model.server import Server
from bot_data.model.technician_config import TechnicianConfig
from bot_data.service.server_config_seeder import ServerConfigSeeder
from bot_data.service.technician_config_seeder import TechnicianConfigSeeder
class ConfigService:
@@ -17,24 +16,17 @@ class ConfigService:
services: ServiceProviderABC,
technician_config_repo: TechnicianConfigRepositoryABC,
server_config_repo: ServerConfigRepositoryABC,
technician_seeder: TechnicianConfigSeeder,
server_seeder: ServerConfigSeeder,
):
self._config = config
self._services = services
self._technician_config_repo = technician_config_repo
self._technician_seeder = technician_seeder
self._server_config_repo = server_config_repo
self._server_seeder = server_seeder
async def reload_technician_config(self):
try:
technician_config = self._technician_config_repo.get_technician_config()
except Exception as e:
await self._technician_seeder.seed()
technician_config = self._technician_config_repo.get_technician_config()
def reload_technician_config(self):
technician_config = self._technician_config_repo.get_technician_config()
self._config.add_configuration(TechnicianConfig, technician_config)
self._config.add_configuration(
FeatureFlagsSettings,

View File

@@ -176,7 +176,7 @@ class DataIntegrityService:
self._logger.warn(__name__, f"User not found in database: {u.id}")
self._logger.debug(__name__, f"Add user: {u.id}")
self._users.add_user(User(u.id, 0, 0, 0, None, server))
self._users.add_user(User(u.id, 0, 0, 0, server))
self._db_context.save_changes()
self._logger.debug(__name__, f"Added User: {u.id}")
@@ -389,22 +389,6 @@ class DataIntegrityService:
for member in guild.members:
await self._client_utils.check_default_role(member)
def _check_for_bots(self):
for guild in self._bot.guilds:
server = self._servers.get_server_by_discord_id(guild.id)
for member in guild.members.where(lambda x: x.bot):
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
if user is None:
continue
for join in self._user_joins.get_user_joined_servers_by_user_id(user.id):
self._user_joins.delete_user_joined_server(join)
self._user_joins_vc.delete_user_joined_voice_channel_by_user_id(user.id)
self._users.delete_user(user)
self._db_context.save_changes()
async def check_data_integrity(self, is_for_shutdown=False):
if is_for_shutdown != self._is_for_shutdown:
self._is_for_shutdown = is_for_shutdown
@@ -418,4 +402,3 @@ class DataIntegrityService:
self._check_user_joins_vc()
self._check_user_joined_gs()
await self._check_for_user_achievements()
self._check_for_bots()

View File

@@ -5,8 +5,6 @@ CREATE TABLE IF NOT EXISTS `CFG_TechnicianHistory`
`WaitForRestart` BIGINT NOT NULL DEFAULT 8,
`WaitForShutdown` BIGINT NOT NULL DEFAULT 8,
`CacheMaxMessages` BIGINT NOT NULL DEFAULT 1000000,
`MaxSteamOfferCount` BIGINT NOT NULL DEFAULT 250,
`Maintenance` BOOLEAN DEFAULT FALSE,
`FeatureFlags` JSON NULL DEFAULT ('{}'),
`Deleted` BOOL DEFAULT FALSE,
`DateFrom` DATETIME(6) NOT NULL,
@@ -25,8 +23,6 @@ BEGIN
`WaitForRestart`,
`WaitForShutdown`,
`CacheMaxMessages`,
`MaxSteamOfferCount`,
`Maintenance`,
`FeatureFlags`,
`DateFrom`,
`DateTo`)
@@ -35,8 +31,6 @@ BEGIN
OLD.WaitForRestart,
OLD.WaitForShutdown,
OLD.CacheMaxMessages,
OLD.MaxSteamOfferCount,
OLD.Maintenance,
OLD.FeatureFlags,
OLD.LastModifiedAt,
CURRENT_TIMESTAMP(6));
@@ -54,8 +48,6 @@ BEGIN
`WaitForRestart`,
`WaitForShutdown`,
`CacheMaxMessages`,
`MaxSteamOfferCount`,
`Maintenance`,
`FeatureFlags`,
`Deleted`,
`DateFrom`,
@@ -65,8 +57,6 @@ BEGIN
OLD.WaitForRestart,
OLD.WaitForShutdown,
OLD.CacheMaxMessages,
OLD.MaxSteamOfferCount,
OLD.Maintenance,
OLD.FeatureFlags,
TRUE,
OLD.LastModifiedAt,

View File

@@ -17,10 +17,14 @@ class FixUserHistoryMigration(MigrationABC):
# fix 1.1.0_AchievementsMigration
self._cursor.execute(
str(f"""ALTER TABLE UsersHistory ADD COLUMN ReactionCount BIGINT NOT NULL DEFAULT 0 AFTER XP;""")
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 MessageCount BIGINT NOT NULL DEFAULT 0 AFTER ReactionCount;""")
str(
f"""ALTER TABLE UsersHistory ADD COLUMN IF NOT EXISTS MessageCount BIGINT NOT NULL DEFAULT 0 AFTER ReactionCount;"""
)
)
self._exec(__file__, "users.sql")

View File

@@ -1,51 +0,0 @@
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.abc.migration_abc import MigrationABC
from bot_data.db_context import DBContext
class MaintenanceModeMigration(MigrationABC):
name = "1.2.0_MaintenanceModeMigration"
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 CFG_Technician
ADD Maintenance BOOLEAN DEFAULT FALSE AFTER MaxSteamOfferCount;
"""
)
)
self._cursor.execute(
str(
f"""
ALTER TABLE CFG_TechnicianHistory
ADD Maintenance BOOLEAN DEFAULT FALSE AFTER MaxSteamOfferCount;
"""
)
)
self._exec(__file__, "config/technician.sql")
def downgrade(self):
self._cursor.execute(
str(
f"""
ALTER TABLE CFG_Technician DROP COLUMN Maintenance;
"""
)
)
self._cursor.execute(
str(
f"""
ALTER TABLE CFG_TechnicianHistory DROP COLUMN Maintenance;
"""
)
)

View File

@@ -1,51 +0,0 @@
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.abc.migration_abc import MigrationABC
from bot_data.db_context import DBContext
class MaxSteamOfferCountMigration(MigrationABC):
name = "1.2.0_MaxSteamOfferCountMigration"
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 CFG_Technician
ADD MaxSteamOfferCount BIGINT NOT NULL DEFAULT 250 AFTER CacheMaxMessages;
"""
)
)
self._cursor.execute(
str(
f"""
ALTER TABLE CFG_TechnicianHistory
ADD MaxSteamOfferCount BIGINT NOT NULL DEFAULT 250 AFTER CacheMaxMessages;
"""
)
)
self._exec(__file__, "config/technician.sql")
def downgrade(self):
self._cursor.execute(
str(
f"""
ALTER TABLE CFG_Technician DROP COLUMN MaxSteamOfferCount;
"""
)
)
self._cursor.execute(
str(
f"""
ALTER TABLE CFG_TechnicianHistory DROP COLUMN MaxSteamOfferCount;
"""
)
)

View File

@@ -36,7 +36,7 @@ class SteamSpecialOfferMigration(MigrationABC):
str(
f"""
ALTER TABLE CFG_Server
ADD COLUMN GameOfferNotificationChatId BIGINT NULL AFTER ShortRoleNameSetOnlyHighest;
ADD COLUMN IF NOT EXISTS GameOfferNotificationChatId BIGINT NULL AFTER ShortRoleNameSetOnlyHighest;
"""
)
)
@@ -45,7 +45,7 @@ class SteamSpecialOfferMigration(MigrationABC):
str(
f"""
ALTER TABLE CFG_ServerHistory
ADD COLUMN GameOfferNotificationChatId BIGINT NULL AFTER ShortRoleNameSetOnlyHighest;
ADD COLUMN IF NOT EXISTS GameOfferNotificationChatId BIGINT NULL AFTER ShortRoleNameSetOnlyHighest;
"""
)
)

View File

@@ -15,8 +15,6 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
wait_for_restart: int,
wait_for_shutdown: int,
cache_max_messages: int,
max_steam_offer_count: int,
maintenance: bool,
feature_flags: dict[FeatureFlagsEnum],
technician_ids: List[int],
ping_urls: List[str],
@@ -29,9 +27,6 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
self._wait_for_restart = wait_for_restart
self._wait_for_shutdown = wait_for_shutdown
self._cache_max_messages = cache_max_messages
self._max_steam_offer_count = max_steam_offer_count
self._maintenance = maintenance
self._feature_flags = feature_flags
self._technician_ids = technician_ids
self._ping_urls = ping_urls
@@ -76,14 +71,6 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
def cache_max_messages(self, value: int):
self._cache_max_messages = value
@property
def max_steam_offer_count(self) -> int:
return self._max_steam_offer_count
@max_steam_offer_count.setter
def max_steam_offer_count(self, value: int):
self._max_steam_offer_count = value
@property
def feature_flags(self) -> dict[FeatureFlagsEnum]:
return self._feature_flags
@@ -108,14 +95,6 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
def ping_urls(self, value: List[str]):
self._ping_urls = value
@property
def maintenance(self) -> bool:
return self._maintenance
@maintenance.setter
def maintenance(self, value: bool):
self._maintenance = value
@staticmethod
def get_select_all_string() -> str:
return str(
@@ -138,13 +117,12 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
return str(
f"""
INSERT INTO `CFG_Technician` (
`HelpCommandReferenceUrl`, `WaitForRestart`, `WaitForShutdown`, `CacheMaxMessages`, `MaxSteamOfferCount`, `FeatureFlags`
`HelpCommandReferenceUrl`, `WaitForRestart`, `WaitForShutdown`, `CacheMaxMessages`, `FeatureFlags`
) VALUES (
'{self._help_command_reference_url}',
{self._wait_for_restart},
{self._wait_for_shutdown},
{self._cache_max_messages},
{self._max_steam_offer_count},
'{json.dumps(self._feature_flags)}'
);
"""
@@ -159,7 +137,6 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
`WaitForRestart` = {self._wait_for_restart},
`WaitForShutdown` = {self._wait_for_shutdown},
`CacheMaxMessages` = {self._cache_max_messages},
`MaxSteamOfferCount` = {self._max_steam_offer_count},
`FeatureFlags` = '{json.dumps(self._feature_flags)}'
WHERE `Id` = {self._id};
"""

View File

@@ -191,7 +191,7 @@ class User(TableABC):
{self._xp},
{self._message_count},
{self._reaction_count},
{"NULL" if self._birthday is None else f"'{self._birthday}'"},
'{self._birthday}',
{self._server.id}
);
"""
@@ -205,7 +205,7 @@ class User(TableABC):
SET `XP` = {self._xp},
`MessageCount` = {self._message_count},
`ReactionCount` = {self._reaction_count},
`Birthday` = {"NULL" if self._birthday is None else f"'{self._birthday}'"}
`Birthday` = '{self._birthday}'
WHERE `UserId` = {self._user_id};
"""
)

View File

@@ -124,6 +124,6 @@ class UserJoinedServer(TableABC):
return str(
f"""
DELETE FROM `UserJoinedServers`
WHERE `JoinId` = {self._join_id};
WHERE `Id` = {self._join_id};
"""
)

View File

@@ -21,7 +21,7 @@ class MigrationService:
self._cursor = db.cursor
self._migrations: List[MigrationABC] = (
List(type, MigrationABC.__subclasses__()).order_by(lambda x: x.name.split("_")[0]).then_by(lambda x: x.prio)
List(type, MigrationABC.__subclasses__()).order_by(lambda x: x.name).order_by(lambda x: x.prio)
)
def migrate(self):

View File

@@ -46,13 +46,11 @@ class TechnicianConfigRepositoryService(TechnicianConfigRepositoryABC):
result[2],
result[3],
result[4],
result[5],
bool(result[6]),
json.loads(result[7]),
json.loads(result[5]),
self._get_technician_ids(),
self._get_technician_ping_urls(),
result[8],
result[9],
result[6],
result[7],
id=result[0],
)

View File

@@ -1,7 +1,6 @@
from typing import Callable
from ariadne import ObjectType
from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceProviderABC
from cpl_core.type import T
from cpl_discord.service import DiscordBotServiceABC
@@ -11,7 +10,6 @@ from bot_api.exception.service_error_code_enum import ServiceErrorCode
from bot_api.exception.service_exception import ServiceException
from bot_api.route.route import Route
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.environment_variables import MAINTENANCE
from bot_data.model.achievement import Achievement
from bot_data.model.auth_role_enum import AuthRoleEnum
from bot_data.model.auth_user import AuthUser
@@ -77,14 +75,9 @@ class QueryABC(ObjectType):
def get_services(services: ServiceProviderABC) -> ServiceProviderABC:
return services
@ServiceProviderABC.inject
def get_config(config: ConfigurationABC) -> ConfigurationABC:
return config
services = get_services()
permissions: PermissionService = services.get_service(PermissionService)
bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC)
config = get_config()
if user.auth_role == AuthRoleEnum.admin:
return True
@@ -94,9 +87,6 @@ class QueryABC(ObjectType):
if permissions.is_member_technician(guild.get_member(u.discord_id)):
return True
if config.get_configuration(MAINTENANCE):
return False
access = False
if type(element) == Achievement:
element: Achievement = element
@@ -225,9 +215,7 @@ class QueryABC(ObjectType):
return access
@ServiceProviderABC.inject
def _can_user_mutate_data(
self, server: Server, permission: UserRoleEnum, services: ServiceProviderABC, config: ConfigurationABC
):
def _can_user_mutate_data(self, server: Server, permission: UserRoleEnum, services: ServiceProviderABC):
permissions: PermissionService = services.get_service(PermissionService)
bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC)
@@ -239,20 +227,16 @@ class QueryABC(ObjectType):
auth_user.users.where(lambda x: x.server.id == server.id).single().discord_id
)
can_edit = lambda x: False
check_perm = lambda x: True
match permission:
case UserRoleEnum.moderator:
can_edit = permissions.is_member_moderator
if config.get_configuration(MAINTENANCE):
can_edit = lambda x: False
check_perm = lambda x: permissions.is_member_moderator(x)
case UserRoleEnum.admin:
can_edit = permissions.is_member_admin
if config.get_configuration(MAINTENANCE):
can_edit = lambda x: False
check_perm = lambda x: permissions.is_member_admin(x)
case UserRoleEnum.technician:
can_edit = permissions.is_member_technician
check_perm = lambda x: permissions.is_member_technician(x)
if not can_edit(member):
if not check_perm(member):
ex = ServiceException(ServiceErrorCode.Forbidden, f"User not allowed to mutate data")
raise ex

View File

@@ -26,7 +26,6 @@ type Server implements TableWithHistoryQuery {
gameServers: [GameServer]
userCount: Int
activeUserCount: Int
users(filter: UserFilter, page: Page, sort: Sort): [User]
achievementCount: Int
@@ -38,8 +37,6 @@ type Server implements TableWithHistoryQuery {
config: ServerConfig
hasFeatureFlag(flag: String): FeatureFlag
# statistic(date: String): ServerStatistic
createdAt: String
modifiedAt: String

View File

@@ -1,17 +0,0 @@
type ServerStatistic {
achievementsAchieved: Int
messageCount: Int
userCount: Int
activeUserCount: Int
userJoinedVoiceChannelCount: Int
userJoinedVoiceChannelOntime: Float
userJoinedGameServerCount: Int
userJoinedGameServerOntime: Float
userWarningCount: Int
activityScore: Int
}

View File

@@ -4,8 +4,6 @@ type TechnicianConfig implements TableWithHistoryQuery {
waitForRestart: Int
waitForShutdown: Int
cacheMaxMessages: Int
maxSteamOfferCount: Int
maintenance: Boolean
featureFlagCount: Int
featureFlags: [FeatureFlag]
pingURLs: [String]
@@ -25,8 +23,6 @@ type TechnicianConfigHistory implements HistoryTableQuery {
waitForRestart: Int
waitForShutdown: Int
cacheMaxMessages: Int
maxSteamOfferCount: Int
maintenance: Boolean
featureFlagCount: Int
featureFlags: [FeatureFlag]
@@ -63,8 +59,6 @@ input TechnicianConfigInput {
waitForRestart: Int
waitForShutdown: Int
cacheMaxMessages: Int
maxSteamOfferCount: Int
maintenance: Boolean
featureFlags: [FeatureFlagInput]
pingURLs: [String]
technicianIds: [String]

View File

@@ -57,7 +57,6 @@ from bot_graphql.queries.level_query import LevelQuery
from bot_graphql.queries.server_config_query import ServerConfigQuery
from bot_graphql.queries.server_history_query import ServerHistoryQuery
from bot_graphql.queries.server_query import ServerQuery
from bot_graphql.queries.server_statistic_query import ServerStatisticQuery
from bot_graphql.queries.short_role_name_history_query import ShortRoleNameHistoryQuery
from bot_graphql.queries.short_role_name_query import ShortRoleNameQuery
from bot_graphql.queries.technician_config_history_query import (
@@ -139,7 +138,6 @@ class GraphQLModule(ModuleABC):
services.add_transient(QueryABC, ShortRoleNameQuery)
services.add_transient(QueryABC, UserWarningHistoryQuery)
services.add_transient(QueryABC, UserWarningQuery)
services.add_transient(QueryABC, ServerStatisticQuery)
services.add_transient(QueryABC, DiscordQuery)
services.add_transient(QueryABC, GuildQuery)

View File

@@ -1,7 +0,0 @@
from bot_data.model.server import Server
class ServerStatistics:
def __init__(self, server: Server, kwargs: dict):
self.server = server
self.kwargs = kwargs

View File

@@ -41,9 +41,6 @@ class LevelMutation(QueryABC):
int(input["permissions"]),
server,
)
levels = self._levels.get_levels_by_server_id(server.id)
if levels.where(lambda x: x.name == level.name).count() > 0:
raise ValueError(f"Level with name {level.name} already exists")
self._levels.add_level(level)
self._db.save_changes()

View File

@@ -1,12 +1,9 @@
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 bot_api.logging.api_logger import ApiLogger
from bot_api.route.route import Route
from bot_core.abc.client_utils_abc import ClientUtilsABC
from bot_core.environment_variables import MAINTENANCE
from bot_core.service.config_service import ConfigService
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC
@@ -21,7 +18,6 @@ from bot_graphql.abc.query_abc import QueryABC
class TechnicianConfigMutation(QueryABC):
def __init__(
self,
config: ConfigurationABC,
logger: ApiLogger,
bot: DiscordBotServiceABC,
servers: ServerRepositoryABC,
@@ -29,11 +25,9 @@ class TechnicianConfigMutation(QueryABC):
db: DatabaseContextABC,
config_service: ConfigService,
tech_seeder: TechnicianConfigSeeder,
client_utils: ClientUtilsABC,
):
QueryABC.__init__(self, "TechnicianConfigMutation")
self._config = config
self._logger = logger
self._bot = bot
self._servers = servers
@@ -41,7 +35,6 @@ class TechnicianConfigMutation(QueryABC):
self._db = db
self._config_service = config_service
self._tech_seeder = tech_seeder
self._client_utils = client_utils
self.set_field("updateTechnicianConfig", self.resolve_update_technician_config)
@@ -66,12 +59,6 @@ class TechnicianConfigMutation(QueryABC):
technician_config.cache_max_messages = (
input["cacheMaxMessages"] if "cacheMaxMessages" in input else technician_config.cache_max_messages
)
technician_config.max_steam_offer_count = (
input["maxSteamOfferCount"] if "maxSteamOfferCount" in input else technician_config.max_steam_offer_count
)
technician_config.maintenance = (
input["maintenance"] if "maintenance" in input else technician_config.maintenance
)
old_feature_flags = technician_config.feature_flags
technician_config.feature_flags = (
dict(
@@ -104,10 +91,7 @@ class TechnicianConfigMutation(QueryABC):
self._update_technician_ids(technician_config)
self._db.save_changes()
if technician_config.maintenance != self._config.get_configuration(MAINTENANCE):
self._bot.loop.create_task(self._client_utils.set_maintenance_mode(technician_config.maintenance))
self._bot.loop.create_task(self._config_service.reload_technician_config())
self._config_service.reload_technician_config()
return technician_config
def _update_ping_urls(self, new_config: TechnicianConfig):

View File

@@ -25,7 +25,7 @@ class GuildQuery(QueryABC):
)
def _resolve_channels(self, g: Guild, *_, filter=None):
channels = List(any).extend(g.channels).order_by(lambda x: x.position)
channels = List(any).extend(g.channels)
if filter is None:
return channels
@@ -39,4 +39,4 @@ class GuildQuery(QueryABC):
if "type" in filter:
channels = channels.where(lambda c: type(c).__name__ == filter["type"])
return channels
return channels.order_by(lambda x: x.position)

View File

@@ -26,7 +26,6 @@ from bot_graphql.filter.client_filter import ClientFilter
from bot_graphql.filter.level_filter import LevelFilter
from bot_graphql.filter.short_role_name_filter import ShortRoleNameFilter
from bot_graphql.filter.user_filter import UserFilter
from bot_graphql.model.server_statistics import ServerStatistics
class ServerQuery(DataQueryWithHistoryABC):
@@ -77,10 +76,6 @@ class ServerQuery(DataQueryWithHistoryABC):
lambda server, *_: self._levels.get_levels_by_server_id(server.id),
LevelFilter,
)
self.set_field(
"activeUserCount",
lambda server, *_: self._users.get_users_by_server_id(server.id).where(lambda x: not x.left_server).count(),
)
self.add_collection(
"user",
lambda server, *_: self._users.get_users_by_server_id(server.id),
@@ -108,7 +103,6 @@ class ServerQuery(DataQueryWithHistoryABC):
"hasFeatureFlag",
lambda server, *_, **kwargs: self._resolve_has_feature_flag(server, *_, **kwargs),
)
# self.set_field("statistic", lambda server, *_, **kwargs: ServerStatistics(server, kwargs))
@staticmethod
def resolve_id(server: Server, *_):

View File

@@ -1,157 +0,0 @@
import datetime
from cpl_core.configuration import ConfigurationABC
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_voice_channel_repository_abc import UserJoinedVoiceChannelRepositoryABC
from bot_data.abc.user_message_count_per_hour_repository_abc import UserMessageCountPerHourRepositoryABC
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.abc.user_warnings_repository_abc import UserWarningsRepositoryABC
from bot_data.model.server_config import ServerConfig
from bot_graphql.abc.query_abc import QueryABC
class ServerStatisticQuery(QueryABC):
def __init__(
self,
config: ConfigurationABC,
users: UserRepositoryABC,
user_joined_voice_channels: UserJoinedVoiceChannelRepositoryABC,
user_joined_game_servers: UserJoinedGameServerRepositoryABC,
user_messages: UserMessageCountPerHourRepositoryABC,
user_warnings: UserWarningsRepositoryABC,
achievements: AchievementRepositoryABC,
):
QueryABC.__init__(self, "ServerStatistic")
self._config = config
self._users = users
self._user_joined_voice_channels = user_joined_voice_channels
self._user_joined_game_servers = user_joined_game_servers
self._user_messages = user_messages
self._user_warnings = user_warnings
self._achievements = achievements
self.set_field(
"achievementsAchieved",
self._resolve_achievements,
)
self.set_field(
"messageCount",
self._resolve_message_count,
)
self.set_field("userCount", lambda server, *_: self._users.get_users_by_server_id(server.server.id).count())
self.set_field("activeUserCount", self._resolve_active_count)
self.set_field("userJoinedVoiceChannelCount", self._resolve_voice_channel_count)
self.set_field("userJoinedVoiceChannelOntime", self._resolve_voice_channel_ontime)
self.set_field("userJoinedGameServerCount", self._resolve_game_server_count)
self.set_field("userJoinedGameServerOntime", self._resolve_game_server_ontime)
self.set_field("userWarningCount", self._resolve_user_warning_count)
self.set_field("activityScore", self._resolve_activity_score)
def _resolve_activity_score(self, server, *_):
days = (datetime.date.today() - self._get_date(**server.kwargs)).days
return int(
(
(
self._resolve_achievements(server, *_)
+ self._resolve_message_count(server, *_)
+ self._resolve_voice_channel_count(server, *_)
+ self._resolve_voice_channel_ontime(server, *_)
+ self._resolve_game_server_count(server, *_)
+ self._resolve_game_server_ontime(server, *_)
- self._resolve_user_warning_count(server, *_)
)
/ self._resolve_active_count(server, *_)
)
/ days
* 1000
)
def _resolve_message_count(self, server, *_):
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{server.server.discord_id}")
return (
self._user_messages.get_user_message_count_per_hours()
.where(
lambda x: x.user.server.id == server.server.id
and x.created_at.date() >= self._get_date(**server.kwargs)
)
.sum(lambda x: x.xp_count / settings.xp_per_message)
)
def _resolve_active_count(self, server, *_):
return self._users.get_users_by_server_id(server.server.id).where(lambda x: not x.left_server).count()
def _resolve_voice_channel_count(self, server, *_):
return (
self._user_joined_voice_channels.get_user_joined_voice_channels()
.where(
lambda x: x.user.server.id == server.server.id
and x.created_at.date() >= self._get_date(**server.kwargs)
)
.count()
)
def _resolve_voice_channel_ontime(self, server, *_):
return (
self._user_joined_voice_channels.get_user_joined_voice_channels()
.where(
lambda x: x.user.server.id == server.server.id
and x.created_at.date() >= self._get_date(**server.kwargs)
)
.sum(lambda x: x.time)
)
def _resolve_game_server_count(self, server, *_):
return (
self._user_joined_game_servers.get_user_joined_game_servers()
.where(
lambda x: x.user.server.id == server.server.id
and x.created_at.date() >= self._get_date(**server.kwargs)
)
.count()
)
def _resolve_game_server_ontime(self, server, *_):
return (
self._user_joined_game_servers.get_user_joined_game_servers()
.where(
lambda x: x.user.server.id == server.server.id
and x.created_at.date() >= self._get_date(**server.kwargs)
)
.sum(lambda x: x.time)
)
def _resolve_user_warning_count(self, server, *_):
return (
self._user_warnings.get_user_warnings()
.where(
lambda x: x.user.server.id == server.server.id
and x.created_at.date() >= self._get_date(**server.kwargs)
)
.count()
)
def _resolve_achievements(self, server, *_):
return (
self._achievements.get_achievements_by_server_id(server.server.id)
.select_many(lambda x: self._achievements.get_user_got_achievements_by_achievement_id(x.id))
.where(
lambda x: x.user.server.id == server.server.id
and x.created_at.date() >= self._get_date(**server.kwargs)
)
.count()
)
def _get_date(self, **kwargs) -> datetime.date:
if "date" not in kwargs:
return datetime.date.today() - datetime.timedelta(days=7)
return datetime.datetime.strptime(kwargs["date"], "%d.%m.%Y").date()

View File

@@ -14,8 +14,6 @@ class TechnicianConfigHistoryQuery(HistoryQueryABC):
self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart)
self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown)
self.set_field("cacheMaxMessages", lambda config, *_: config.cache_max_messages)
self.set_field("maxSteamOfferCount", lambda config, *_: config.max_steam_offer_count)
self.set_field("maintenance", lambda config, *_: config.maintenance)
self.add_collection(
"featureFlag",
lambda config, *_: List(

View File

@@ -27,8 +27,6 @@ class TechnicianConfigQuery(DataQueryWithHistoryABC):
self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart)
self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown)
self.set_field("cacheMaxMessages", lambda config, *_: config.cache_max_messages)
self.set_field("maxSteamOfferCount", lambda config, *_: config.max_steam_offer_count)
self.set_field("maintenance", lambda config, *_: config.maintenance)
self.add_collection(
"featureFlag",
lambda config, *_: List(

View File

@@ -56,7 +56,7 @@ class UserQuery(DataQueryWithHistoryABC):
self.set_field("xp", self.resolve_xp)
self.set_field("messageCount", lambda x, *_: x.message_count)
self.set_field("reactionCount", lambda x, *_: x.reaction_count)
self.set_field("birthday", lambda x, *_: None if x.birthday is None else x.birthday.strftime("%d.%m.%Y"))
self.set_field("birthday", lambda x, *_: x.birthday)
self.set_field("ontime", self.resolve_ontime)
self.set_field("level", self.resolve_level)
self.add_collection(

View File

@@ -35,7 +35,7 @@ class AchievementOnMessageEvent(OnMessageABC):
self._servers = servers
self._users = users
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_message(self, message: discord.Message):
if message.guild is None:
return

View File

@@ -9,7 +9,6 @@ from cpl_discord.service import DiscordBotServiceABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_core.helper.event_checks import EventChecks
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.model.server_config import ServerConfig
@@ -37,7 +36,6 @@ class AchievementOnReactionAddEvent(OnReactionAddABC):
self._servers = servers
self._users = users
@EventChecks.check_is_ready
async def on_reaction_add(
self,
reaction: discord.reaction.Reaction,

View File

@@ -9,7 +9,6 @@ from cpl_discord.service import DiscordBotServiceABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_core.helper.event_checks import EventChecks
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.model.server_config import ServerConfig
@@ -37,7 +36,6 @@ class AchievementOnReactionRemoveEvent(OnReactionRemoveABC):
self._servers = servers
self._users = users
@EventChecks.check_is_ready
async def on_reaction_remove(
self,
reaction: discord.reaction.Reaction,

View File

@@ -7,7 +7,6 @@ from cpl_discord.service import DiscordBotServiceABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_core.helper.event_checks import EventChecks
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.model.server_config import ServerConfig
@@ -35,7 +34,6 @@ class AchievementOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC):
self._servers = servers
self._users = users
@EventChecks.check_is_ready
async def on_voice_state_update(
self,
member: discord.member.Member,

View File

@@ -32,7 +32,7 @@ class AutoRoleOnRawReactionAddEvent(OnRawReactionAddABC):
self._auto_roles = auto_roles
self._reaction_handler = reaction_handler
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
self._logger.debug(__name__, f"Module {type(self)} started")
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")

View File

@@ -32,7 +32,7 @@ class AutoRoleOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
self._auto_roles = auto_roles
self._reaction_handler = reaction_handler
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_raw_reaction_remove(self, payload: RawReactionActionEvent):
self._logger.debug(__name__, f"Module {type(self)} started")
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")

View File

@@ -34,8 +34,7 @@ class BirthdayWatcher(TaskABC):
self._message_service = message_service
self._t = t
if not self._is_maintenance():
self.watch.start()
self.watch.start()
@tasks.loop(time=datetime.time(hour=8, minute=0))
async def watch(self):

View File

@@ -11,7 +11,6 @@ from discord.ext.commands import Context, CommandError
from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.exception.check_error import CheckError
from bot_core.helper.event_checks import EventChecks
from bot_data.model.technician_config import TechnicianConfig
@@ -33,7 +32,6 @@ class BaseOnCommandErrorEvent(OnCommandErrorABC):
self._time_format_settings = time_format_settings
self._t = translate
@EventChecks.check_is_ready
async def on_command_error(self, ctx: Context, error: CommandError):
if isinstance(error, CheckError):
return

View File

@@ -10,7 +10,6 @@ from cpl_translation import TranslatePipe
from discord.ext.commands import Context
from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.helper.event_checks import EventChecks
from bot_core.logging.command_logger import CommandLogger
from bot_data.abc.client_repository_abc import ClientRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC
@@ -79,7 +78,6 @@ class BaseOnCommandEvent(OnCommandABC):
self._logger.debug(__name__, f"User {user} sent message. xp: from {old_xp} to {user.xp}")
@EventChecks.check_is_ready
async def on_command(self, ctx: Context):
self._logger.debug(__name__, f"Module {type(self)} started")
self._logger.info(__name__, f"Received command: {ctx.command} from {ctx.channel}")

View File

@@ -4,7 +4,6 @@ from cpl_discord.events import OnGuildJoinABC
from cpl_discord.service import DiscordBotServiceABC
from discord import Guild
from bot_core.helper.event_checks import EventChecks
from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.model.server import Server
@@ -30,7 +29,6 @@ class BaseOnGuildJoinEvent(OnGuildJoinABC):
self._db = db
self._seeder = seeder
@EventChecks.check_is_ready
async def on_guild_join(self, guild: Guild):
if self._servers.find_server_by_discord_id(guild.id) is None:
self._servers.add_server(Server(guild.id))

View File

@@ -101,11 +101,9 @@ class BaseOnMemberJoinEvent(OnMemberJoinABC):
)
self._logger.trace(__name__, f"Notified team that a member left")
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_member_join(self, member: discord.Member):
self._logger.debug(__name__, f"Module {type(self)} started")
if member.bot:
return
await self._client_utils.check_default_role(member)
self._check_for_known_user(member)
await self._add_if_not_exists_user_async(member)

View File

@@ -69,7 +69,7 @@ class BaseOnMemberRemoveEvent(OnMemberRemoveABC):
)
self._logger.trace(__name__, f"Notified team that a member left")
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_member_remove(self, member: discord.Member):
self._logger.debug(__name__, f"Module {type(self)} started")
await self._remove_user(member)

View File

@@ -6,7 +6,6 @@ from cpl_core.database.context import DatabaseContextABC
from cpl_discord.events import OnMessageDeleteABC
from cpl_discord.service import DiscordBotServiceABC
from bot_core.helper.event_checks import EventChecks
from bot_core.helper.log_message_helper import LogMessageHelper
from bot_core.logging.message_logger import MessageLogger
from bot_data.abc.client_repository_abc import ClientRepositoryABC
@@ -73,7 +72,6 @@ class BaseOnMessageDeleteEvent(OnMessageDeleteABC):
f"Removed message from user {user}. xp: from {old_xp} to {user.xp}",
)
@EventChecks.check_is_ready
async def on_message_delete(self, message: discord.Message):
self._logger.debug(__name__, f"Module {type(self)} started")
if message is None or message.guild is None:

View File

@@ -79,7 +79,7 @@ class BaseOnMessageEvent(OnMessageABC):
self._logger.debug(__name__, f"User {user} sent message. xp: from {old_xp} to {user.xp}")
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_message(self, message: discord.Message):
self._logger.debug(__name__, f"Module {type(self)} started")
if message is None or message.guild is None:

View File

@@ -26,7 +26,7 @@ class BaseOnRawReactionAddEvent(OnRawReactionAddABC):
self._auto_roles = auto_roles
self._reaction_handler = reaction_handler
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
self._logger.debug(__name__, f"Module {type(self)} started")

View File

@@ -26,7 +26,7 @@ class BaseOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
self._auto_roles = auto_roles
self._reaction_handler = reaction_handler
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_raw_reaction_remove(self, payload: RawReactionActionEvent):
self._logger.debug(__name__, f"Module {type(self)} started")

View File

@@ -4,7 +4,6 @@ from cpl_discord.events.on_scheduled_event_update_abc import OnScheduledEventUpd
from cpl_discord.service import DiscordBotServiceABC
from discord import EventStatus
from bot_core.helper.event_checks import EventChecks
from modules.base.model.active_event import ActiveEvent
from modules.base.service.event_service import EventService
@@ -22,7 +21,6 @@ class BaseOnScheduledEventUpdateEvent(OnScheduledEventUpdateABC):
self._bot = bot
self._events = events
@EventChecks.check_is_ready
async def on_scheduled_event_update(self, before: discord.ScheduledEvent, after: discord.ScheduledEvent):
self._logger.debug(__name__, f"Module {type(self)} started")

View File

@@ -83,7 +83,7 @@ class BaseOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC):
except Exception as e:
self._logger.error(__name__, f"Ontime validation failed", e)
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_voice_state_update(
self,
member: discord.Member,
@@ -97,8 +97,6 @@ class BaseOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC):
)
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{member.guild.id}")
server = self._servers.get_server_by_discord_id(member.guild.id)
if member.bot:
return
try:
if before.channel == after.channel:

View File

@@ -42,7 +42,7 @@ class BaseOnVoiceStateUpdateEventHelpChannel(OnVoiceStateUpdateABC):
)
self._logger.trace(__name__, f"Notified team that a member need help")
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_voice_state_update(
self,
member: discord.Member,

View File

@@ -30,7 +30,7 @@ class BaseOnVoiceStateUpdateEventScheduledEventBonus(OnVoiceStateUpdateABC):
self._logger.info(__name__, f"Module {type(self)} loaded")
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_voice_state_update(
self,
member: discord.Member,

View File

@@ -82,6 +82,6 @@ class BootLogOnReadyEvent(OnReadyABC):
)
)
self._config.add_configuration("IS_READY", True)
self._config.add_configuration("IS_READY", "true")
self._logger.info(__name__, "Bot is ready")
self._logger.trace(__name__, f"Module {type(self)} stopped")

View File

@@ -19,4 +19,4 @@ class ConfigExtension(ApplicationExtensionABC):
logger: LoggerABC = services.get_service(LoggerABC)
logger.debug(__name__, "Config extension started")
config: ConfigService = services.get_service(ConfigService)
await config.reload_technician_config()
config.reload_technician_config()

View File

@@ -8,7 +8,6 @@ from cpl_core.logging import LoggerABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_core.environment_variables import MIGRATION_ONLY
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.service.migration_service import MigrationService
@@ -26,6 +25,6 @@ class DatabaseExtension(ApplicationExtensionABC):
config.add_configuration("Database_StartTime", str(datetime.now()))
migrations: MigrationService = services.get_service(MigrationService)
migrations.migrate()
if config.get_configuration(MIGRATION_ONLY):
if config.get_configuration("MIGRATION_ONLY"):
logger.warn(__name__, "Migrations finished. Stopping application...")
sys.exit()

View File

@@ -1,31 +0,0 @@
{
"DefaultLevel": {
"LevelHeader": "~~~ dev-Level ~~~",
"Levels": [
{
"Name": "dev-Newbie",
"Color": "0x1abc9c",
"MinXp": 0,
"Permissions": 968552209984
},
{
"Name": "dev-Keks",
"Color": "0x2ecc71",
"MinXp": 100,
"Permissions": 1002928856640
},
{
"Name": "dev-Doppelkeks",
"Color": "0x3498db",
"MinXp": 200,
"Permissions": 1071849660224
},
{
"Name": "dev-Auror",
"Color": "0xf1c40f",
"MinXp": 300,
"Permissions": 1089042120513
}
]
}
}

View File

@@ -1,31 +0,0 @@
{
"DefaultLevel": {
"LevelHeader": "~~~ ed-Level ~~~",
"Levels": [
{
"Name": "ed-Newbie",
"Color": "0x1abc9c",
"MinXp": 0,
"Permissions": 968552209984
},
{
"Name": "ed-Keks",
"Color": "0x2ecc71",
"MinXp": 100,
"Permissions": 1002928856640
},
{
"Name": "ed-Doppelkeks",
"Color": "0x3498db",
"MinXp": 200,
"Permissions": 1071849660224
},
{
"Name": "ed-Auror",
"Color": "0xf1c40f",
"MinXp": 300,
"Permissions": 1089042120513
}
]
}
}

View File

@@ -1,31 +0,0 @@
{
"DefaultLevel": {
"LevelHeader": "~~~ ed-Level ~~~",
"Levels": [
{
"Name": "ed-Newbie",
"Color": "0x1abc9c",
"MinXp": 0,
"Permissions": 968552209984
},
{
"Name": "ed-Keks",
"Color": "0x2ecc71",
"MinXp": 100,
"Permissions": 1002928856640
},
{
"Name": "ed-Doppelkeks",
"Color": "0x3498db",
"MinXp": 200,
"Permissions": 1071849660224
},
{
"Name": "ed-Auror",
"Color": "0xf1c40f",
"MinXp": 300,
"Permissions": 1089042120513
}
]
}
}

View File

@@ -1,31 +0,0 @@
{
"DefaultLevel": {
"LevelHeader": "~~~ test-Level ~~~",
"Levels": [
{
"Name": "test-Newbie",
"Color": "0x1abc9c",
"MinXp": 0,
"Permissions": 968552209984
},
{
"Name": "test-Keks",
"Color": "0x2ecc71",
"MinXp": 100,
"Permissions": 1002928856640
},
{
"Name": "test-Doppelkeks",
"Color": "0x3498db",
"MinXp": 200,
"Permissions": 1071849660224
},
{
"Name": "test-Auror",
"Color": "0xf1c40f",
"MinXp": 300,
"Permissions": 1089042120513
}
]
}
}

View File

@@ -17,7 +17,7 @@ class LevelOnMemberJoinEvent(OnMemberJoinABC):
self._logger = logger
self._level = level
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_member_join(self, member: discord.Member):
self._logger.debug(__name__, f"Module {type(self)} started")
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{member.guild.id}")

View File

@@ -17,7 +17,7 @@ class LevelOnMessageEvent(OnMessageABC):
self._logger = logger
self._level = level
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_message(self, message: discord.Message):
self._logger.debug(__name__, f"Module {type(self)} started")
if message.guild is None:

View File

@@ -26,7 +26,7 @@ class LevelOnRawReactionAddEvent(OnRawReactionAddABC):
self._bot = bot
self._level = level
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
self._logger.debug(__name__, f"Module {type(self)} started")
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")

View File

@@ -26,7 +26,7 @@ class LevelOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
self._bot = bot
self._level = level
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_raw_reaction_remove(self, payload: RawReactionActionEvent):
self._logger.debug(__name__, f"Module {type(self)} started")
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")

View File

@@ -19,7 +19,7 @@ class LevelOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC):
self._logger.info(__name__, f"Module {type(self)} loaded")
@EventChecks.check_is_ready
@EventChecks.check_is_ready()
async def on_voice_state_update(
self,
member: discord.Member,

View File

@@ -32,9 +32,7 @@ class LevelModule(ModuleABC):
def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
cwd = env.working_directory
env.set_working_directory(os.path.dirname(os.path.realpath(__file__)))
config.add_json_file(f"config/default-level.json", optional=False)
config.add_json_file(f"config/default-level.{env.environment_name}.json", optional=True)
config.add_json_file(f"config/default-level.{env.host_name}.json", optional=True)
config.add_json_file(f"default-level.json", optional=False)
env.set_working_directory(cwd)
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):

View File

@@ -1,7 +1,6 @@
import discord
from cpl_discord.events import OnMemberUpdateABC
from bot_core.helper.event_checks import EventChecks
from modules.short_role_name.service.short_role_name_service import ShortRoleNameService
@@ -10,7 +9,6 @@ class ShortRoleNameOnMemberUpdateEvent(OnMemberUpdateABC):
OnMemberUpdateABC.__init__(self)
self._service = service
@EventChecks.check_is_ready
async def on_member_update(self, before: discord.member.Member, after: discord.member.Member):
if before.roles != after.roles or before.name != after.name:
await self._service.check_short_role_names(after)

View File

@@ -21,7 +21,6 @@ from bot_data.abc.steam_special_offer_repository_abc import (
)
from bot_data.model.server_config import ServerConfig
from bot_data.model.steam_special_offer import SteamSpecialOffer
from bot_data.model.technician_config import TechnicianConfig
class SteamOfferWatcher(TaskABC):
@@ -34,7 +33,6 @@ class SteamOfferWatcher(TaskABC):
offers: SteamSpecialOfferRepositoryABC,
message_service: MessageService,
t: TranslatePipe,
tech_config: TechnicianConfig,
):
TaskABC.__init__(self)
@@ -45,14 +43,12 @@ class SteamOfferWatcher(TaskABC):
self._bot = bot
self._message_service = message_service
self._t = t
self._tech_config = tech_config
self._is_new = False
self._urls = {}
self._image_urls = {}
if not self._is_maintenance():
self.watch.start()
self.watch.start()
@staticmethod
def _get_max_count() -> int:
@@ -70,7 +66,7 @@ class SteamOfferWatcher(TaskABC):
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&filter=topsellers"
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"})
@@ -112,12 +108,10 @@ class SteamOfferWatcher(TaskABC):
def _get_new_game_offers(self) -> List[SteamSpecialOffer]:
new_offers = List(SteamSpecialOffer)
sale_count = self._tech_config.max_steam_offer_count
# todo: let admins change the value
# sale_count = self._get_max_count() + 100
sale_count = 500 # only look at first 500
self._logger.debug(__name__, f"Get special offers from 0 to {sale_count}")
for i in range(0, sale_count, 100):
if i > sale_count:
break
new_offers.extend(self._get_games_from_page(i, 100))
self._logger.debug(__name__, f"Got {new_offers.count()} offers")
@@ -187,7 +181,7 @@ class SteamOfferWatcher(TaskABC):
self._logger.trace(__name__, "Finished watching")
return offers_for_notifications
@tasks.loop(hours=4)
@tasks.loop(time=datetime.time(hour=16, minute=30))
async def watch(self):
self._logger.info(__name__, "Watching steam special offers")
try:

View File

@@ -129,7 +129,7 @@ class SyncXpGroup(DiscordCommandABC):
other_server = self._servers.get_server_by_id(server_id)
user = self._users.get_user_by_discord_id_and_server_id(
member.id, self._servers.get_server_by_discord_id(ctx.guild.id).id
self._servers.get_server_by_discord_id(ctx.guild.id).id, member.id
)
try:

View File

@@ -3,7 +3,7 @@
"version": 1,
"newProjectRoot": "projects",
"projects": {
"web": {
"kdb-web": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
@@ -20,7 +20,7 @@
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/web",
"outputPath": "dist/kdb-web",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
@@ -86,10 +86,10 @@
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "web:build:production"
"browserTarget": "kdb-web:build:production"
},
"development": {
"browserTarget": "web:build:development"
"browserTarget": "kdb-web:build:development"
}
},
"defaultConfiguration": "development"
@@ -97,7 +97,7 @@
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "web:build"
"browserTarget": "kdb-web:build"
}
},
"test": {

4
web/package-lock.json generated
View File

@@ -1,11 +1,11 @@
{
"name": "web",
"name": "kdb-web",
"version": "1.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "web",
"name": "kdb-web",
"version": "1.2.0",
"dependencies": {
"@angular/animations": "^15.1.4",

View File

@@ -10,11 +10,10 @@
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"gv": "echo $npm_package_version",
"predocker-build": "npm run update-version",
"docker-build": "export VERSION=$npm_package_version; ng build; docker build -t sh-edraft.de/sdb-web:$VERSION .",
"docker-build-dev": "export VERSION=$npm_package_version; ng build --configuration development; docker build -t sh-edraft.de/sdb-web:$VERSION .",
"docker-build-stage": "export VERSION=$npm_package_version; ng build --configuration staging; docker build -t sh-edraft.de/sdb-web:$VERSION ."
"docker-build": "export VERSION=$npm_package_version; ng build; docker build -t sh-edraft.de/kdb-web:$VERSION .",
"docker-build-dev": "export VERSION=$npm_package_version; ng build --configuration development; docker build -t sh-edraft.de/kdb-web:$VERSION .",
"docker-build-stage": "export VERSION=$npm_package_version; ng build --configuration staging; docker build -t sh-edraft.de/kdb-web:$VERSION ."
},
"private": true,
"dependencies": {
@@ -53,4 +52,4 @@
"tslib": "^2.4.1",
"typescript": "~4.9.5"
}
}
}

View File

@@ -4,6 +4,7 @@ export interface Column {
}
export class ComponentWithTable {
private _hiddenColumns: Column[] = [];
set hiddenColumns(value: Column[]) {
this._hiddenColumns = value;
@@ -16,19 +17,10 @@ export class ComponentWithTable {
public name: string = "";
public columns: Column[] = [];
public isEditingNew: boolean = false;
public callback = (data: any[], isNew: boolean) => {
this.save(data, isNew);
};
public validator: (oldElement: any, newElement: any) => boolean = (oldElement: any, newElement: any) => {
return true;
};
constructor(
name: string,
columns: string[],
validator?: (oldElement: any, newElement: any) => boolean
columns: string[]
) {
this.name = name;
this.columns = columns.map(column => {
@@ -40,9 +32,6 @@ export class ComponentWithTable {
hiddenColumns = localStorage.getItem("hiddenColumns") ?? JSON.stringify([{}]);
}
this._hiddenColumns = JSON.parse(hiddenColumns);
if (validator) {
this.validator = validator;
}
}
private getKey(column: string): string {
@@ -52,14 +41,4 @@ export class ComponentWithTable {
public isColumnVisible(column: string): boolean {
return !this._hiddenColumns.map(column => column.key).includes(this.getKey(column));
}
public onRowEditSave(newLevel: any, index: number) {
}
public save(data: any[], isNew: boolean) {
for (let i = 0; i < data.length; i++) {
this.isEditingNew = isNew;
this.onRowEditSave(data[i], i);
}
}
}

View File

@@ -7,8 +7,6 @@ export interface TechnicianConfig extends DataWithHistory {
waitForRestart?: number;
waitForShutdown?: number;
cacheMaxMessages?: number;
maxSteamOfferCount?: number;
maintenance?: boolean;
featureFlags: FeatureFlag[];
pingURLs: string[];
technicianIds: string[];

View File

@@ -20,11 +20,9 @@ export interface Server extends Data {
autoRoles?: AutoRole[];
clientCount?: number;
clients?: Client[];
statistic?: ServerStatistic;
levelCount?: number;
levels?: Level[];
userCount?: number;
activeUserCount?: number;
users?: User[];
config?: ServerConfig;
hasFeatureFlag?: FeatureFlag;
@@ -36,16 +34,3 @@ export interface ServerFilter {
discordId?: String;
name?: String;
}
export interface ServerStatistic {
achievementsAchieved?: Number
messageCount?: Number
userCount?: Number
activeUserCount?: Number
userJoinedVoiceChannelCount?: Number
userJoinedVoiceChannelOntime?: Number
userJoinedGameServerCount?: Number
userJoinedGameServerOntime?: Number
userWarningCount?: Number
activityScore?: Number
}

View File

@@ -216,7 +216,7 @@ export class Mutations {
`;
static updateTechnicianConfig = `
mutation updateTechnicianConfig($id: ID, $helpCommandReferenceUrl: String, $waitForRestart: Int, $waitForShutdown: Int, $cacheMaxMessages: Int, $maxSteamOfferCount: Int, $maintenance: Boolean, $featureFlags: [FeatureFlagInput], $pingURLs: [String], $technicianIds: [String]) {
mutation updateTechnicianConfig($id: ID, $helpCommandReferenceUrl: String, $waitForRestart: Int, $waitForShutdown: Int, $cacheMaxMessages: Int, $featureFlags: [FeatureFlagInput], $pingURLs: [String], $technicianIds: [String]) {
technicianConfig {
updateTechnicianConfig(input: {
id: $id,
@@ -224,8 +224,6 @@ export class Mutations {
waitForRestart: $waitForRestart,
waitForShutdown: $waitForShutdown,
cacheMaxMessages: $cacheMaxMessages,
maxSteamOfferCount: $maxSteamOfferCount,
maintenance: $maintenance,
featureFlags: $featureFlags,
pingURLs: $pingURLs,
technicianIds: $technicianIds
@@ -235,8 +233,6 @@ export class Mutations {
waitForRestart
waitForShutdown
cacheMaxMessages
maxSteamOfferCount
maintenance
featureFlags {
key
value

View File

@@ -68,20 +68,6 @@ export class Queries {
name
iconURL
userCount
activeUserCount
}
}
`;
static serversDashboardQuery = `
query DetailedServerInfo($filter: ServerFilter, $page: Page, $sort: Sort) {
servers(filter: $filter, page: $page, sort: $sort) {
id
discordId
name
iconURL
userCount
activeUserCount
clients {
id
discordId
@@ -96,19 +82,6 @@ export class Queries {
}
`;
// statistic {
// achievementsAchieved
// messageCount
// userCount
// activeUserCount
// userJoinedVoiceChannelCount
// userJoinedVoiceChannelOntime
// userJoinedGameServerCount
// userJoinedGameServerOntime
// userWarningCount
// activityScore
// }
static hasServerFeatureFlag = `
query HasServerFeatureFlag($filter: ServerFilter, $flag: String) {
servers(filter: $filter) {
@@ -524,8 +497,6 @@ export class Queries {
waitForRestart
waitForShutdown
cacheMaxMessages
maxSteamOfferCount
maintenance
featureFlags {
key
value
@@ -561,7 +532,6 @@ export class Queries {
loginMessageChannelId
defaultRoleId
shortRoleNameOnlySetHighestRole
gameOfferNotificationChatId
featureFlags {
key
value

View File

@@ -225,7 +225,7 @@
(click)="deleteUser(user)"></button>
<button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn"
icon="pi pi-check-circle" (click)="onRowEditSave(user, ri)"></button>
icon="pi pi-check-circle" (click)="onRowEditSave(dt, user, ri)"></button>
<button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn"
icon="pi pi-times-circle" (click)="onRowEditCancel(user, ri)"></button>
</div>

View File

@@ -31,6 +31,7 @@ export class AuthUserComponent extends ComponentWithTable implements OnInit, OnD
activityValues: number[] = [0, 100];
clonedUsers: { [s: string]: AuthUserDTO; } = {};
isEditingNew: boolean = false;
authRoles = [
{ label: AuthRoles[AuthRoles.Normal].toString(), value: AuthRoles.Normal },
@@ -192,7 +193,7 @@ export class AuthUserComponent extends ComponentWithTable implements OnInit, OnD
this.clonedUsers[index] = { ...user };
}
public override onRowEditSave(newUser: AuthUserDTO, index: number) {
onRowEditSave(table: Table, newUser: AuthUserDTO, index: number) {
const oldUser = this.clonedUsers[index];
delete this.clonedUsers[index];
@@ -218,6 +219,7 @@ export class AuthUserComponent extends ComponentWithTable implements OnInit, OnD
newUser.email == ""
)
) {
table.initRowEdit(newUser);
return;
}
@@ -237,6 +239,7 @@ export class AuthUserComponent extends ComponentWithTable implements OnInit, OnD
this.toastService.error(this.translate.instant("admin.auth_users.message.user_already_exists"), this.translate.instant("admin.auth_users.message.user_already_exists_d", { email: newUser.email }));
}
error.error = null;
table.initRowEdit(newUser);
}
this.spinnerService.hideSpinner();

View File

@@ -109,8 +109,7 @@
<form [formGroup]="testMailForm" class="content-column">
<div class="content-data-name">
<div class="input-field content-input-field">
<input type="email" pInputText formControlName="mail" placeholder="{{'common.email' | translate}}"
autocomplete="email">
<input type="email" pInputText formControlName="mail" placeholder="{{'common.email' | translate}}" autocomplete="email">
</div>
</div>
@@ -137,8 +136,7 @@
<div class="content-column">
<div class="content-data-name">{{'admin.settings.bot.help_url' | translate}}:</div>
<div class="content-data-value">
<input type="text" pInputText [(ngModel)]="config.helpCommandReferenceUrl"
placeholder="{{'admin.settings.bot.help_url' | translate}}">
<input type="text" pInputText [(ngModel)]="config.helpCommandReferenceUrl" placeholder="{{'admin.settings.bot.help_url' | translate}}">
</div>
</div>
</div>
@@ -147,8 +145,7 @@
<div class="content-column">
<div class="content-data-name">{{'admin.settings.bot.wait_for_restart' | translate}}:</div>
<div class="content-data-value">
<input type="number" pInputText [(ngModel)]="config.waitForRestart"
placeholder="{{'admin.settings.bot.wait_for_restart' | translate}}">
<input type="number" pInputText [(ngModel)]="config.waitForRestart" placeholder="{{'admin.settings.bot.wait_for_restart' | translate}}">
</div>
</div>
</div>
@@ -157,8 +154,7 @@
<div class="content-column">
<div class="content-data-name">{{'admin.settings.bot.wait_for_shutdown' | translate}}:</div>
<div class="content-data-value">
<input type="number" pInputText [(ngModel)]="config.waitForShutdown"
placeholder="{{'admin.settings.bot.wait_for_shutdown' | translate}}">
<input type="number" pInputText [(ngModel)]="config.waitForShutdown" placeholder="{{'admin.settings.bot.wait_for_shutdown' | translate}}">
</div>
</div>
</div>
@@ -167,33 +163,14 @@
<div class="content-column">
<div class="content-data-name">{{'admin.settings.bot.cache_max_messages' | translate}}:</div>
<div class="content-data-value">
<input type="number" pInputText [(ngModel)]="config.cacheMaxMessages"
placeholder="{{'admin.settings.bot.cache_max_messages' | translate}}">
<input type="number" pInputText [(ngModel)]="config.cacheMaxMessages" placeholder="{{'admin.settings.bot.cache_max_messages' | translate}}">
</div>
</div>
</div>
<div class="content-row">
<div class="content-column">
<div class="content-data-name">{{'admin.settings.bot.max_steam_offer_count' | translate}}:</div>
<div class="content-data-value">
<input type="number" pInputText [(ngModel)]="config.maxSteamOfferCount"
placeholder="{{'admin.settings.bot.max_steam_offer_count' | translate}}">
</div>
</div>
</div>
<div class="content-row">
<div class="content-column">
<div class="content-data-name">{{'view.server.config.bot.maintenance' | translate}}:</div>
<p-selectButton class="table-edit-input" [options]="stateOptions" [(ngModel)]="config.maintenance"></p-selectButton>
</div>
</div>
<div class="content-divider"></div>
<app-config-list translationKey="admin.settings.bot.ping_urls" [(data)]="config.pingURLs"></app-config-list>
<app-config-list translationKey="admin.settings.bot.technician_ids" [options]="possibleTechnicians"
optionLabel="name" optionValue="id"
<app-config-list translationKey="admin.settings.bot.technician_ids" [options]="possibleTechnicians" optionLabel="name" optionValue="id"
[(data)]="config.technicianIds"></app-config-list>
<app-feature-flag-list [(data)]="config.featureFlags"></app-feature-flag-list>

View File

@@ -56,10 +56,6 @@ export class SettingsComponent implements OnInit {
};
possibleTechnicians?: DiscordUser[];
stateOptions: any[] = [
{ label: this.translate.instant("common.state.off"), value: false },
{ label: this.translate.instant("common.state.on"), value: true }
];
constructor(
private dataService: DataService,
@@ -160,8 +156,6 @@ export class SettingsComponent implements OnInit {
waitForRestart: this.config.waitForRestart,
waitForShutdown: this.config.waitForShutdown,
cacheMaxMessages: this.config.cacheMaxMessages,
maxSteamOfferCount: this.config.maxSteamOfferCount,
maintenance: this.config.maintenance,
featureFlags: this.config.featureFlags,
pingURLs: this.config.pingURLs,
technicianIds: this.config.technicianIds

View File

@@ -5,11 +5,9 @@ import { ComponentWithTable } from "../../../base/component-with-table";
export class HideableComponent {
@HostBinding("class.hidden-column")
get hidden() {
const column = this.subColumn ?? this.column;
return !(this.parent?.isColumnVisible(column) ?? true);
return !(this.parent?.isColumnVisible(this.column) ?? true);
};
@Input() column!: string;
@Input() subColumn!: string;
@Input() parent!: ComponentWithTable;
}

View File

@@ -1,10 +0,0 @@
<button pButton pTooltip="{{'common.export' | translate}}" tooltipPosition="left" icon="pi pi-download"
class="icon-btn btn" (click)="export()">
</button>
<p-fileUpload #upload pTooltip="{{'common.import' | translate}}" tooltipPosition="left" chooseIcon="pi pi-upload"
styleClass="icon-btn btn" mode="basic"
[auto]="true"
[customUpload]="true" accept="application/json"
(uploadHandler)="import($event)">
</p-fileUpload>

View File

@@ -1,5 +0,0 @@
:host {
display: flex;
flex-direction: row;
}

View File

@@ -1,23 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DataImportAndExportComponent } from './data-import-and-export.component';
describe('DataImportAndExportComponent', () => {
let component: DataImportAndExportComponent;
let fixture: ComponentFixture<DataImportAndExportComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ DataImportAndExportComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(DataImportAndExportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,86 +0,0 @@
import { Component, EventEmitter, Input, Output, ViewChild } from "@angular/core";
import { ToastService } from "../../../../services/toast/toast.service";
import { TranslateService } from "@ngx-translate/core";
import { elementAt } from "rxjs";
interface UploadEvent {
originalEvent: Event;
files: File[];
}
@Component({
selector: "app-data-import-and-export",
templateUrl: "./data-import-and-export.component.html",
styleUrls: ["./data-import-and-export.component.scss"]
})
export class DataImportAndExportComponent {
@ViewChild("upload") upload: any;
private _data: any[] = [];
@Input() name: string = "";
@Input()
set data(data: any[]) {
this._data = data;
this.dataChange.emit(data);
}
get data(): any[] {
return this._data;
}
@Output() dataChange: EventEmitter<any[]> = new EventEmitter<any[]>();
@Input() callback!: (data: any[], isNew: boolean) => void;
@Input() validator: (oldElement: any, newElement: any) => boolean = (oldElement: any, newElement: any) => {
return true;
};
public constructor(
private toastService: ToastService,
private translate: TranslateService
) {
}
public export() {
const json = JSON.stringify(this.data);
const element = document.createElement("a");
element.setAttribute("href", "data:application/json;charset=UTF-8," + encodeURIComponent(json));
element.setAttribute("download", `${this.name}.json`);
element.style.display = "none";
document.body.appendChild(element);
element.click(); // simulate click
document.body.removeChild(element);
}
public import(event: { files: File[] }) {
const file = event.files[0];
const fileReader = new FileReader();
fileReader.onload = () => {
if (!fileReader.result) return;
const newData: any[] = JSON.parse(fileReader.result.toString());
this.upload.clear();
newData.forEach(element => {
element.id = 0;
});
this.data.forEach(element => {
const existingElement = newData.find(x => this.validator(x, element));
if (existingElement) {
const index = this.data.indexOf(element);
const oldId = element.id;
element = existingElement;
element.id = oldId;
this.data[index] = element;
newData.splice(newData.indexOf(existingElement), 1);
}
});
this.callback(this.data, false);
this.callback(newData, true);
this.data.push(...newData);
this.toastService.success(this.translate.instant("common.file.uploaded"), this.translate.instant("common.file.uploaded"));
};
fileReader.readAsText(file, "UTF-8");
}
}

View File

@@ -2,7 +2,7 @@
<ng-content></ng-content>
</ng-template>
<div *ngIf="sortable; else without" [pSortableColumn]="subColumn ?? column">
<div *ngIf="sortable; else without" [pSortableColumn]="column">
<ng-container *ngTemplateOutlet="content"></ng-container>
</div>

View File

@@ -33,9 +33,6 @@ import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-s
import { FeatureFlagListComponent } from './components/feature-flag-list/feature-flag-list.component';
import { InputSwitchModule } from "primeng/inputswitch";
import { CalendarModule } from "primeng/calendar";
import { DataImportAndExportComponent } from './components/data-import-and-export/data-import-and-export.component';
import { FileUploadModule } from "primeng/fileupload";
import { SelectButtonModule } from "primeng/selectbutton";
const PrimeNGModules = [
@@ -64,8 +61,6 @@ const PrimeNGModules = [
MultiSelectModule,
InputSwitchModule,
CalendarModule,
FileUploadModule,
SelectButtonModule,
]
@NgModule({
@@ -79,7 +74,6 @@ const PrimeNGModules = [
HideableHeaderComponent,
MultiSelectColumnsComponent,
FeatureFlagListComponent,
DataImportAndExportComponent,
],
imports: [
CommonModule,
@@ -97,7 +91,6 @@ const PrimeNGModules = [
HideableHeaderComponent,
MultiSelectColumnsComponent,
FeatureFlagListComponent,
DataImportAndExportComponent
]
})
export class SharedModule {

Some files were not shown because too many files have changed in this diff Show More