Compare commits
98 Commits
9622232c33
...
1.2.0
Author | SHA1 | Date | |
---|---|---|---|
9bad75e7c2 | |||
7358b67072 | |||
1b0ba01258 | |||
6fc5ee3ed3 | |||
099707446d | |||
d6b7fd73df | |||
6bfb0ddbf9 | |||
e1b76fa628 | |||
e6f98def6a | |||
590479eee2 | |||
d25305be4a | |||
2889a97f17 | |||
b540821a32 | |||
5b43b72838 | |||
46cd33d194 | |||
1287829bdf | |||
c91c8b2bcd | |||
a5b4c4cd66 | |||
1688347367 | |||
6e79811bc9 | |||
e1258151de | |||
a7c833b9db | |||
2f161d2f43 | |||
0a5f23f1af | |||
23a3dbbc5e | |||
8975665407 | |||
90de90684c | |||
d1ecfe9603 | |||
f7f25e9428 | |||
6ae7ab5c5a | |||
315c90cacc | |||
2caa910613 | |||
8e55ebc4b7 | |||
665e524aa9 | |||
ae021ac7ea | |||
dcbb481b10 | |||
e6165caed9 | |||
58fdc9f48f | |||
1c02608410 | |||
5e0b322273 | |||
4f336bed05 | |||
99d476df86 | |||
81062e74d7 | |||
acae8ac891 | |||
e3dc0f725e | |||
40a7919a3f | |||
14d0e38c5d | |||
62649226ba | |||
0a04ad74d8 | |||
467050d87e | |||
e8f2a01851 | |||
f972055ebf | |||
9bbfe498cc | |||
b21c9f894f | |||
7a0f29f557 | |||
ed72620d33 | |||
b8356917b3 | |||
84fedfaa0b | |||
2d358188af | |||
79278d8f4b | |||
b943b9a7ed | |||
1c20bbed66 | |||
33006e3d01 | |||
90ae55c0d4 | |||
626d0891f9 | |||
09cccd1b89 | |||
940a2ed065 | |||
c2fa1a1c00 | |||
1f1b1f7b65 | |||
4b52995143 | |||
6a6d19686c | |||
798162fb62 | |||
74c71abea5 | |||
0e679eda32 | |||
403c169b71 | |||
a113e21e19 | |||
71c091c226 | |||
b8d27cc682 | |||
c9b967b9d0 | |||
410049be6e | |||
be6361f619 | |||
3a7daf8b42 | |||
f435d3dd48 | |||
eb32bec43c | |||
232429a77d | |||
0946734633 | |||
ea1472a9eb | |||
f710f6ad6c | |||
030fedfcfb | |||
bd1d230f67 | |||
dcafa63d74 | |||
3a42b42dbf | |||
4747f23202 | |||
5057cbed16 | |||
7aff767a4b | |||
61bdc8a52a | |||
5afd0fafa8 | |||
eeda0405f3 |
@@ -8,14 +8,8 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
on-push-deploy_sh-edraft:
|
on-push-deploy_sh-edraft:
|
||||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||||
container: catthehacker/ubuntu:act-latest
|
container: sh-edraft.de/act-runner:latest
|
||||||
steps:
|
steps:
|
||||||
- name: Setup Python 3.10
|
|
||||||
uses: actions/setup-python@v3
|
|
||||||
with:
|
|
||||||
python-version: "3.10.12"
|
|
||||||
- run: python -v
|
|
||||||
|
|
||||||
- name: Setup docker
|
- name: Setup docker
|
||||||
uses: https://github.com/papodaca/install-docker-action@main
|
uses: https://github.com/papodaca/install-docker-action@main
|
||||||
- run: docker -v
|
- run: docker -v
|
||||||
@@ -26,21 +20,12 @@ jobs:
|
|||||||
token: ${{ secrets.CI_ACCESS_TOKEN }}
|
token: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||||
submodules: true
|
submodules: true
|
||||||
|
|
||||||
- name: Shutdown stack
|
|
||||||
run: docker stack rm sdb_staging
|
|
||||||
|
|
||||||
- name: Prepare bot build
|
- name: Prepare bot build
|
||||||
run: |
|
run: |
|
||||||
cd bot
|
cd bot
|
||||||
pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
|
python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
|
||||||
cpl i
|
cpl i
|
||||||
|
|
||||||
- name: Build docker bot
|
|
||||||
run: |
|
|
||||||
cd bot
|
|
||||||
docker image prune -f
|
|
||||||
cpl docker-build
|
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: https://github.com/actions/setup-node@v3
|
uses: https://github.com/actions/setup-node@v3
|
||||||
|
|
||||||
@@ -48,13 +33,31 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd web
|
cd web
|
||||||
npm install -g ts-node
|
npm install -g ts-node
|
||||||
npm i
|
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 .
|
||||||
|
|
||||||
- name: Build docker web
|
- name: Build docker web
|
||||||
run: |
|
run: |
|
||||||
cd web
|
cd web
|
||||||
docker image prune -f
|
docker image prune -f
|
||||||
npm run docker-build
|
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
|
||||||
|
|
||||||
- name: Deploy Stack to sh-edraft.de
|
- name: Deploy Stack to sh-edraft.de
|
||||||
uses: https://github.com/kgierke/portainer-stack-deployment@v1
|
uses: https://github.com/kgierke/portainer-stack-deployment@v1
|
||||||
@@ -63,6 +66,6 @@ jobs:
|
|||||||
portainer-username: "gitea_job"
|
portainer-username: "gitea_job"
|
||||||
portainer-password: "${{ secrets.docker_job }}"
|
portainer-password: "${{ secrets.docker_job }}"
|
||||||
portainer-endpoint: 2
|
portainer-endpoint: 2
|
||||||
name: sdb_staging
|
name: sdb_dev
|
||||||
file: bot/docker/docker-compose.staging.yml
|
file: bot/docker/docker-compose.dev.yml
|
||||||
variables: '{}'
|
variables: '{}'
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
name: Deploy dev on push
|
name: Deploy prod on push
|
||||||
run-name: Deploy dev on push
|
run-name: Deploy prod on push
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
@@ -8,36 +8,24 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
on-push-deploy_sh-edraft:
|
on-push-deploy_sh-edraft:
|
||||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||||
container: catthehacker/ubuntu:act-latest
|
container: sh-edraft.de/act-runner:latest
|
||||||
steps:
|
steps:
|
||||||
- name: Setup Python 3.10
|
|
||||||
uses: actions/setup-python@v3
|
|
||||||
with:
|
|
||||||
python-version: "3.10.12"
|
|
||||||
- run: python -v
|
|
||||||
|
|
||||||
- name: Setup docker
|
- name: Setup docker
|
||||||
uses: https://github.com/papodaca/install-docker-action@main
|
uses: https://github.com/papodaca/install-docker-action@main
|
||||||
- run: docker -v
|
- run: docker -v
|
||||||
|
|
||||||
- name: Clone Repository
|
- name: Clone Repository
|
||||||
uses: https://github.com/actions/checkout@v3
|
uses: https://github.com/actions/checkout@v3
|
||||||
|
with:
|
||||||
- name: Shutdown stack
|
token: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||||
run: docker stack rm sdb_prod
|
submodules: true
|
||||||
|
|
||||||
- name: Prepare bot build
|
- name: Prepare bot build
|
||||||
run: |
|
run: |
|
||||||
cd bot
|
cd bot
|
||||||
pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
|
python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
|
||||||
cpl i
|
cpl i
|
||||||
|
|
||||||
- name: Build docker bot
|
|
||||||
run: |
|
|
||||||
cd bot
|
|
||||||
docker image prune -f
|
|
||||||
cpl docker-build
|
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: https://github.com/actions/setup-node@v3
|
uses: https://github.com/actions/setup-node@v3
|
||||||
|
|
||||||
@@ -45,13 +33,30 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd web
|
cd web
|
||||||
npm install -g ts-node
|
npm install -g ts-node
|
||||||
npm i
|
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) .
|
||||||
|
|
||||||
- name: Build docker web
|
- name: Build docker web
|
||||||
run: |
|
run: |
|
||||||
cd web
|
cd web
|
||||||
docker image prune -f
|
docker image prune -f
|
||||||
npm run docker-build
|
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;)
|
||||||
|
|
||||||
- name: Deploy Stack to sh-edraft.de
|
- name: Deploy Stack to sh-edraft.de
|
||||||
uses: https://github.com/kgierke/portainer-stack-deployment@v1
|
uses: https://github.com/kgierke/portainer-stack-deployment@v1
|
||||||
@@ -61,5 +66,5 @@ jobs:
|
|||||||
portainer-password: "${{ secrets.docker_job }}"
|
portainer-password: "${{ secrets.docker_job }}"
|
||||||
portainer-endpoint: 2
|
portainer-endpoint: 2
|
||||||
name: sdb_prod
|
name: sdb_prod
|
||||||
file: ./docker-compose.yml
|
file: bot/docker/docker-compose.yml
|
||||||
variables: '{}'
|
variables: '{}'
|
||||||
|
71
.gitea/workflows/deploy_staging.yaml
Normal file
71
.gitea/workflows/deploy_staging.yaml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
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 updated: 91461d3ce3...9c0dc59534
@@ -11,6 +11,7 @@ from bot_api.api_thread import ApiThread
|
|||||||
from bot_core.abc.task_abc import TaskABC
|
from bot_core.abc.task_abc import TaskABC
|
||||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||||
|
from bot_core.environment_variables import MAINTENANCE
|
||||||
from bot_core.service.data_integrity_service import DataIntegrityService
|
from bot_core.service.data_integrity_service import DataIntegrityService
|
||||||
|
|
||||||
|
|
||||||
@@ -58,8 +59,9 @@ class Application(DiscordBotApplicationABC):
|
|||||||
return
|
return
|
||||||
|
|
||||||
self._logger.info(__name__, f"Try to start {DiscordBotService.__name__}")
|
self._logger.info(__name__, f"Try to start {DiscordBotService.__name__}")
|
||||||
for task in self._tasks:
|
if not self._config.get_configuration(MAINTENANCE):
|
||||||
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.start_async()
|
||||||
await self._bot.stop_async()
|
await self._bot.stop_async()
|
||||||
|
Submodule bot/src/bot/config updated: 6f4414ce9d...c11ca6f2e8
@@ -9,7 +9,7 @@ from bot.application import Application
|
|||||||
from bot.extension.init_bot_extension import InitBotExtension
|
from bot.extension.init_bot_extension import InitBotExtension
|
||||||
from bot.startup import Startup
|
from bot.startup import Startup
|
||||||
from bot.startup_discord_extension import StartupDiscordExtension
|
from bot.startup_discord_extension import StartupDiscordExtension
|
||||||
from bot.startup_migration_extension import StartupMigrationExtension
|
from bot_data.startup_migration_extension import StartupMigrationExtension
|
||||||
from bot.startup_module_extension import StartupModuleExtension
|
from bot.startup_module_extension import StartupModuleExtension
|
||||||
from bot.startup_settings_extension import StartupSettingsExtension
|
from bot.startup_settings_extension import StartupSettingsExtension
|
||||||
from bot_api.app_api_extension import AppApiExtension
|
from bot_api.app_api_extension import AppApiExtension
|
||||||
|
@@ -8,6 +8,7 @@ from cpl_core.dependency_injection import ServiceCollectionABC
|
|||||||
from cpl_core.environment import ApplicationEnvironmentABC
|
from cpl_core.environment import ApplicationEnvironmentABC
|
||||||
|
|
||||||
from bot_core.configuration.bot_logging_settings import BotLoggingSettings
|
from bot_core.configuration.bot_logging_settings import BotLoggingSettings
|
||||||
|
from bot_core.environment_variables import MAINTENANCE, MIGRATION_ONLY
|
||||||
|
|
||||||
|
|
||||||
class StartupSettingsExtension(StartupExtensionABC):
|
class StartupSettingsExtension(StartupExtensionABC):
|
||||||
@@ -19,6 +20,12 @@ class StartupSettingsExtension(StartupExtensionABC):
|
|||||||
environment.set_working_directory(os.path.dirname(os.path.realpath(__file__)))
|
environment.set_working_directory(os.path.dirname(os.path.realpath(__file__)))
|
||||||
configuration.add_environment_variables("SDB_")
|
configuration.add_environment_variables("SDB_")
|
||||||
configuration.add_environment_variables("DISCORD_")
|
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.json", optional=False)
|
||||||
configuration.add_json_file(f"config/appsettings.{environment.environment_name}.json", optional=True)
|
configuration.add_json_file(f"config/appsettings.{environment.environment_name}.json", optional=True)
|
||||||
|
@@ -90,7 +90,8 @@
|
|||||||
"booting": "Ich fahre gerade hoch...",
|
"booting": "Ich fahre gerade hoch...",
|
||||||
"restart": "Muss neue Kekse holen...",
|
"restart": "Muss neue Kekse holen...",
|
||||||
"running": "Ich esse Kekse :D",
|
"running": "Ich esse Kekse :D",
|
||||||
"shutdown": "Ich werde bestimmt wieder kommen..."
|
"shutdown": "Ich werde bestimmt wieder kommen...",
|
||||||
|
"maintenance": "In Wartung!"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
|
Submodule bot/src/bot_api/config updated: b6ffed4da1...521951b8ab
@@ -75,3 +75,7 @@ class ClientUtilsABC(ABC):
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def check_default_role(self, member: Union[discord.User, discord.Member]):
|
async def check_default_role(self, member: Union[discord.User, discord.Member]):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def set_maintenance_mode(self, state: bool):
|
||||||
|
pass
|
||||||
|
@@ -6,6 +6,7 @@ from cpl_core.dependency_injection import ServiceProviderABC
|
|||||||
from cpl_discord.service import DiscordBotServiceABC
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
||||||
|
from bot_core.environment_variables import MAINTENANCE
|
||||||
from bot_core.logging.task_logger import TaskLogger
|
from bot_core.logging.task_logger import TaskLogger
|
||||||
|
|
||||||
|
|
||||||
@@ -14,14 +15,18 @@ class TaskABC(commands.Cog):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
commands.Cog.__init__(self)
|
commands.Cog.__init__(self)
|
||||||
|
|
||||||
|
@ServiceProviderABC.inject
|
||||||
|
def _is_maintenance(self, config: ConfigurationABC) -> bool:
|
||||||
|
return config.get_configuration(MAINTENANCE) is True
|
||||||
|
|
||||||
@ServiceProviderABC.inject
|
@ServiceProviderABC.inject
|
||||||
async def _wait_until_ready(self, config: ConfigurationABC, logger: TaskLogger, bot: DiscordBotServiceABC):
|
async def _wait_until_ready(self, config: ConfigurationABC, logger: TaskLogger, bot: DiscordBotServiceABC):
|
||||||
logger.debug(__name__, f"Waiting before {type(self).__name__}")
|
logger.debug(__name__, f"Waiting before {type(self).__name__}")
|
||||||
await bot.wait_until_ready()
|
await bot.wait_until_ready()
|
||||||
|
|
||||||
async def wait():
|
async def wait():
|
||||||
is_ready = config.get_configuration("IS_READY")
|
is_ready = config.get_configuration("IS_READY") is True
|
||||||
if is_ready != "true":
|
if not is_ready:
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
await wait()
|
await wait()
|
||||||
|
|
||||||
|
@@ -1,16 +1,19 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
|
from cpl_core.configuration import ConfigurationABC
|
||||||
from cpl_core.logging import LoggerABC
|
from cpl_core.logging import LoggerABC
|
||||||
from cpl_discord.events import OnReadyABC
|
from cpl_discord.events import OnReadyABC
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
from cpl_translation import TranslatePipe
|
from cpl_translation import TranslatePipe
|
||||||
|
|
||||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
||||||
|
from bot_core.environment_variables import MAINTENANCE
|
||||||
|
|
||||||
|
|
||||||
class CoreExtensionOnReadyEvent(OnReadyABC):
|
class CoreExtensionOnReadyEvent(OnReadyABC):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
config: ConfigurationABC,
|
||||||
logger: LoggerABC,
|
logger: LoggerABC,
|
||||||
bot: DiscordBotServiceABC,
|
bot: DiscordBotServiceABC,
|
||||||
client_utils: ClientUtilsABC,
|
client_utils: ClientUtilsABC,
|
||||||
@@ -18,6 +21,7 @@ class CoreExtensionOnReadyEvent(OnReadyABC):
|
|||||||
):
|
):
|
||||||
OnReadyABC.__init__(self)
|
OnReadyABC.__init__(self)
|
||||||
|
|
||||||
|
self._config = config
|
||||||
self._logger = logger
|
self._logger = logger
|
||||||
self._bot = bot
|
self._bot = bot
|
||||||
self._client_utils = client_utils
|
self._client_utils = client_utils
|
||||||
@@ -27,5 +31,5 @@ class CoreExtensionOnReadyEvent(OnReadyABC):
|
|||||||
|
|
||||||
async def on_ready(self):
|
async def on_ready(self):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
await self._client_utils.presence_game("common.presence.running")
|
await self._client_utils.set_maintenance_mode(self._config.get_configuration(MAINTENANCE))
|
||||||
self._logger.trace(__name__, f"Module {type(self)} stopped")
|
self._logger.trace(__name__, f"Module {type(self)} stopped")
|
||||||
|
2
bot/src/bot_core/environment_variables.py
Normal file
2
bot/src/bot_core/environment_variables.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
MIGRATION_ONLY = "MIGRATION_ONLY"
|
||||||
|
MAINTENANCE = "MAINTENANCE"
|
@@ -1,3 +1,4 @@
|
|||||||
|
import inspect
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
@@ -17,11 +18,18 @@ class EventChecks:
|
|||||||
cls._client_utils = client_utils
|
cls._client_utils = client_utils
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def check_is_ready(cls):
|
def check_is_ready(cls, func):
|
||||||
async def check_if_bot_is_ready() -> bool:
|
async def check_if_bot_is_ready(*args, **kwargs):
|
||||||
result = await cls._client_utils.check_if_bot_is_ready_yet()
|
result = await cls._client_utils.check_if_bot_is_ready_yet()
|
||||||
if not result:
|
if not result:
|
||||||
raise CheckError(f"Bot is not ready")
|
|
||||||
return result
|
|
||||||
|
|
||||||
return commands.check(check_if_bot_is_ready)
|
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
|
||||||
|
@@ -16,6 +16,7 @@ from bot_core.abc.client_utils_abc import ClientUtilsABC
|
|||||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||||
|
from bot_core.environment_variables import MAINTENANCE
|
||||||
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||||
from bot_data.abc.user_joined_voice_channel_repository_abc import (
|
from bot_data.abc.user_joined_voice_channel_repository_abc import (
|
||||||
@@ -87,7 +88,14 @@ class ClientUtilsService(ClientUtilsABC):
|
|||||||
return client
|
return client
|
||||||
|
|
||||||
async def check_if_bot_is_ready_yet(self) -> bool:
|
async def check_if_bot_is_ready_yet(self) -> bool:
|
||||||
if self._config.get_configuration("IS_READY") == "true":
|
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:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self._logger.debug(
|
self._logger.debug(
|
||||||
@@ -239,3 +247,10 @@ class ClientUtilsService(ClientUtilsABC):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._logger.error(__name__, f"Cannot check for default role for member {member.id}", 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")
|
||||||
|
@@ -7,6 +7,7 @@ from bot_data.abc.technician_config_repository_abc import TechnicianConfigReposi
|
|||||||
from bot_data.model.server import Server
|
from bot_data.model.server import Server
|
||||||
from bot_data.model.technician_config import TechnicianConfig
|
from bot_data.model.technician_config import TechnicianConfig
|
||||||
from bot_data.service.server_config_seeder import ServerConfigSeeder
|
from bot_data.service.server_config_seeder import ServerConfigSeeder
|
||||||
|
from bot_data.service.technician_config_seeder import TechnicianConfigSeeder
|
||||||
|
|
||||||
|
|
||||||
class ConfigService:
|
class ConfigService:
|
||||||
@@ -16,17 +17,24 @@ class ConfigService:
|
|||||||
services: ServiceProviderABC,
|
services: ServiceProviderABC,
|
||||||
technician_config_repo: TechnicianConfigRepositoryABC,
|
technician_config_repo: TechnicianConfigRepositoryABC,
|
||||||
server_config_repo: ServerConfigRepositoryABC,
|
server_config_repo: ServerConfigRepositoryABC,
|
||||||
|
technician_seeder: TechnicianConfigSeeder,
|
||||||
server_seeder: ServerConfigSeeder,
|
server_seeder: ServerConfigSeeder,
|
||||||
):
|
):
|
||||||
self._config = config
|
self._config = config
|
||||||
self._services = services
|
self._services = services
|
||||||
self._technician_config_repo = technician_config_repo
|
self._technician_config_repo = technician_config_repo
|
||||||
|
self._technician_seeder = technician_seeder
|
||||||
self._server_config_repo = server_config_repo
|
self._server_config_repo = server_config_repo
|
||||||
|
|
||||||
self._server_seeder = server_seeder
|
self._server_seeder = server_seeder
|
||||||
|
|
||||||
def reload_technician_config(self):
|
async def reload_technician_config(self):
|
||||||
technician_config = self._technician_config_repo.get_technician_config()
|
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()
|
||||||
|
|
||||||
self._config.add_configuration(TechnicianConfig, technician_config)
|
self._config.add_configuration(TechnicianConfig, technician_config)
|
||||||
self._config.add_configuration(
|
self._config.add_configuration(
|
||||||
FeatureFlagsSettings,
|
FeatureFlagsSettings,
|
||||||
|
@@ -389,6 +389,22 @@ class DataIntegrityService:
|
|||||||
for member in guild.members:
|
for member in guild.members:
|
||||||
await self._client_utils.check_default_role(member)
|
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):
|
async def check_data_integrity(self, is_for_shutdown=False):
|
||||||
if is_for_shutdown != self._is_for_shutdown:
|
if is_for_shutdown != self._is_for_shutdown:
|
||||||
self._is_for_shutdown = is_for_shutdown
|
self._is_for_shutdown = is_for_shutdown
|
||||||
@@ -402,3 +418,4 @@ class DataIntegrityService:
|
|||||||
self._check_user_joins_vc()
|
self._check_user_joins_vc()
|
||||||
self._check_user_joined_gs()
|
self._check_user_joined_gs()
|
||||||
await self._check_for_user_achievements()
|
await self._check_for_user_achievements()
|
||||||
|
self._check_for_bots()
|
||||||
|
@@ -5,6 +5,8 @@ CREATE TABLE IF NOT EXISTS `CFG_TechnicianHistory`
|
|||||||
`WaitForRestart` BIGINT NOT NULL DEFAULT 8,
|
`WaitForRestart` BIGINT NOT NULL DEFAULT 8,
|
||||||
`WaitForShutdown` BIGINT NOT NULL DEFAULT 8,
|
`WaitForShutdown` BIGINT NOT NULL DEFAULT 8,
|
||||||
`CacheMaxMessages` BIGINT NOT NULL DEFAULT 1000000,
|
`CacheMaxMessages` BIGINT NOT NULL DEFAULT 1000000,
|
||||||
|
`MaxSteamOfferCount` BIGINT NOT NULL DEFAULT 250,
|
||||||
|
`Maintenance` BOOLEAN DEFAULT FALSE,
|
||||||
`FeatureFlags` JSON NULL DEFAULT ('{}'),
|
`FeatureFlags` JSON NULL DEFAULT ('{}'),
|
||||||
`Deleted` BOOL DEFAULT FALSE,
|
`Deleted` BOOL DEFAULT FALSE,
|
||||||
`DateFrom` DATETIME(6) NOT NULL,
|
`DateFrom` DATETIME(6) NOT NULL,
|
||||||
@@ -23,6 +25,8 @@ BEGIN
|
|||||||
`WaitForRestart`,
|
`WaitForRestart`,
|
||||||
`WaitForShutdown`,
|
`WaitForShutdown`,
|
||||||
`CacheMaxMessages`,
|
`CacheMaxMessages`,
|
||||||
|
`MaxSteamOfferCount`,
|
||||||
|
`Maintenance`,
|
||||||
`FeatureFlags`,
|
`FeatureFlags`,
|
||||||
`DateFrom`,
|
`DateFrom`,
|
||||||
`DateTo`)
|
`DateTo`)
|
||||||
@@ -31,6 +35,8 @@ BEGIN
|
|||||||
OLD.WaitForRestart,
|
OLD.WaitForRestart,
|
||||||
OLD.WaitForShutdown,
|
OLD.WaitForShutdown,
|
||||||
OLD.CacheMaxMessages,
|
OLD.CacheMaxMessages,
|
||||||
|
OLD.MaxSteamOfferCount,
|
||||||
|
OLD.Maintenance,
|
||||||
OLD.FeatureFlags,
|
OLD.FeatureFlags,
|
||||||
OLD.LastModifiedAt,
|
OLD.LastModifiedAt,
|
||||||
CURRENT_TIMESTAMP(6));
|
CURRENT_TIMESTAMP(6));
|
||||||
@@ -48,6 +54,8 @@ BEGIN
|
|||||||
`WaitForRestart`,
|
`WaitForRestart`,
|
||||||
`WaitForShutdown`,
|
`WaitForShutdown`,
|
||||||
`CacheMaxMessages`,
|
`CacheMaxMessages`,
|
||||||
|
`MaxSteamOfferCount`,
|
||||||
|
`Maintenance`,
|
||||||
`FeatureFlags`,
|
`FeatureFlags`,
|
||||||
`Deleted`,
|
`Deleted`,
|
||||||
`DateFrom`,
|
`DateFrom`,
|
||||||
@@ -57,6 +65,8 @@ BEGIN
|
|||||||
OLD.WaitForRestart,
|
OLD.WaitForRestart,
|
||||||
OLD.WaitForShutdown,
|
OLD.WaitForShutdown,
|
||||||
OLD.CacheMaxMessages,
|
OLD.CacheMaxMessages,
|
||||||
|
OLD.MaxSteamOfferCount,
|
||||||
|
OLD.Maintenance,
|
||||||
OLD.FeatureFlags,
|
OLD.FeatureFlags,
|
||||||
TRUE,
|
TRUE,
|
||||||
OLD.LastModifiedAt,
|
OLD.LastModifiedAt,
|
||||||
|
@@ -17,14 +17,10 @@ class FixUserHistoryMigration(MigrationABC):
|
|||||||
|
|
||||||
# fix 1.1.0_AchievementsMigration
|
# fix 1.1.0_AchievementsMigration
|
||||||
self._cursor.execute(
|
self._cursor.execute(
|
||||||
str(
|
str(f"""ALTER TABLE UsersHistory ADD COLUMN ReactionCount BIGINT NOT NULL DEFAULT 0 AFTER XP;""")
|
||||||
f"""ALTER TABLE UsersHistory ADD COLUMN IF NOT EXISTS ReactionCount BIGINT NOT NULL DEFAULT 0 AFTER XP;"""
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
self._cursor.execute(
|
self._cursor.execute(
|
||||||
str(
|
str(f"""ALTER TABLE UsersHistory ADD COLUMN MessageCount BIGINT NOT NULL DEFAULT 0 AFTER ReactionCount;""")
|
||||||
f"""ALTER TABLE UsersHistory ADD COLUMN IF NOT EXISTS MessageCount BIGINT NOT NULL DEFAULT 0 AFTER ReactionCount;"""
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
self._exec(__file__, "users.sql")
|
self._exec(__file__, "users.sql")
|
||||||
|
|
||||||
|
51
bot/src/bot_data/migration/maintenance_mode_migration.py
Normal file
51
bot/src/bot_data/migration/maintenance_mode_migration.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
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;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
@@ -0,0 +1,51 @@
|
|||||||
|
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;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
@@ -36,7 +36,7 @@ class SteamSpecialOfferMigration(MigrationABC):
|
|||||||
str(
|
str(
|
||||||
f"""
|
f"""
|
||||||
ALTER TABLE CFG_Server
|
ALTER TABLE CFG_Server
|
||||||
ADD COLUMN IF NOT EXISTS GameOfferNotificationChatId BIGINT NULL AFTER ShortRoleNameSetOnlyHighest;
|
ADD COLUMN GameOfferNotificationChatId BIGINT NULL AFTER ShortRoleNameSetOnlyHighest;
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -45,7 +45,7 @@ class SteamSpecialOfferMigration(MigrationABC):
|
|||||||
str(
|
str(
|
||||||
f"""
|
f"""
|
||||||
ALTER TABLE CFG_ServerHistory
|
ALTER TABLE CFG_ServerHistory
|
||||||
ADD COLUMN IF NOT EXISTS GameOfferNotificationChatId BIGINT NULL AFTER ShortRoleNameSetOnlyHighest;
|
ADD COLUMN GameOfferNotificationChatId BIGINT NULL AFTER ShortRoleNameSetOnlyHighest;
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@@ -15,6 +15,8 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
|
|||||||
wait_for_restart: int,
|
wait_for_restart: int,
|
||||||
wait_for_shutdown: int,
|
wait_for_shutdown: int,
|
||||||
cache_max_messages: int,
|
cache_max_messages: int,
|
||||||
|
max_steam_offer_count: int,
|
||||||
|
maintenance: bool,
|
||||||
feature_flags: dict[FeatureFlagsEnum],
|
feature_flags: dict[FeatureFlagsEnum],
|
||||||
technician_ids: List[int],
|
technician_ids: List[int],
|
||||||
ping_urls: List[str],
|
ping_urls: List[str],
|
||||||
@@ -27,6 +29,9 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
|
|||||||
self._wait_for_restart = wait_for_restart
|
self._wait_for_restart = wait_for_restart
|
||||||
self._wait_for_shutdown = wait_for_shutdown
|
self._wait_for_shutdown = wait_for_shutdown
|
||||||
self._cache_max_messages = cache_max_messages
|
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._feature_flags = feature_flags
|
||||||
self._technician_ids = technician_ids
|
self._technician_ids = technician_ids
|
||||||
self._ping_urls = ping_urls
|
self._ping_urls = ping_urls
|
||||||
@@ -71,6 +76,14 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
|
|||||||
def cache_max_messages(self, value: int):
|
def cache_max_messages(self, value: int):
|
||||||
self._cache_max_messages = value
|
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
|
@property
|
||||||
def feature_flags(self) -> dict[FeatureFlagsEnum]:
|
def feature_flags(self) -> dict[FeatureFlagsEnum]:
|
||||||
return self._feature_flags
|
return self._feature_flags
|
||||||
@@ -95,6 +108,14 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
|
|||||||
def ping_urls(self, value: List[str]):
|
def ping_urls(self, value: List[str]):
|
||||||
self._ping_urls = value
|
self._ping_urls = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def maintenance(self) -> bool:
|
||||||
|
return self._maintenance
|
||||||
|
|
||||||
|
@maintenance.setter
|
||||||
|
def maintenance(self, value: bool):
|
||||||
|
self._maintenance = value
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_select_all_string() -> str:
|
def get_select_all_string() -> str:
|
||||||
return str(
|
return str(
|
||||||
@@ -117,12 +138,13 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
|
|||||||
return str(
|
return str(
|
||||||
f"""
|
f"""
|
||||||
INSERT INTO `CFG_Technician` (
|
INSERT INTO `CFG_Technician` (
|
||||||
`HelpCommandReferenceUrl`, `WaitForRestart`, `WaitForShutdown`, `CacheMaxMessages`, `FeatureFlags`
|
`HelpCommandReferenceUrl`, `WaitForRestart`, `WaitForShutdown`, `CacheMaxMessages`, `MaxSteamOfferCount`, `FeatureFlags`
|
||||||
) VALUES (
|
) VALUES (
|
||||||
'{self._help_command_reference_url}',
|
'{self._help_command_reference_url}',
|
||||||
{self._wait_for_restart},
|
{self._wait_for_restart},
|
||||||
{self._wait_for_shutdown},
|
{self._wait_for_shutdown},
|
||||||
{self._cache_max_messages},
|
{self._cache_max_messages},
|
||||||
|
{self._max_steam_offer_count},
|
||||||
'{json.dumps(self._feature_flags)}'
|
'{json.dumps(self._feature_flags)}'
|
||||||
);
|
);
|
||||||
"""
|
"""
|
||||||
@@ -137,6 +159,7 @@ class TechnicianConfig(TableABC, ConfigurationModelABC):
|
|||||||
`WaitForRestart` = {self._wait_for_restart},
|
`WaitForRestart` = {self._wait_for_restart},
|
||||||
`WaitForShutdown` = {self._wait_for_shutdown},
|
`WaitForShutdown` = {self._wait_for_shutdown},
|
||||||
`CacheMaxMessages` = {self._cache_max_messages},
|
`CacheMaxMessages` = {self._cache_max_messages},
|
||||||
|
`MaxSteamOfferCount` = {self._max_steam_offer_count},
|
||||||
`FeatureFlags` = '{json.dumps(self._feature_flags)}'
|
`FeatureFlags` = '{json.dumps(self._feature_flags)}'
|
||||||
WHERE `Id` = {self._id};
|
WHERE `Id` = {self._id};
|
||||||
"""
|
"""
|
||||||
|
@@ -124,6 +124,6 @@ class UserJoinedServer(TableABC):
|
|||||||
return str(
|
return str(
|
||||||
f"""
|
f"""
|
||||||
DELETE FROM `UserJoinedServers`
|
DELETE FROM `UserJoinedServers`
|
||||||
WHERE `Id` = {self._join_id};
|
WHERE `JoinId` = {self._join_id};
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@@ -46,11 +46,13 @@ class TechnicianConfigRepositoryService(TechnicianConfigRepositoryABC):
|
|||||||
result[2],
|
result[2],
|
||||||
result[3],
|
result[3],
|
||||||
result[4],
|
result[4],
|
||||||
json.loads(result[5]),
|
result[5],
|
||||||
|
bool(result[6]),
|
||||||
|
json.loads(result[7]),
|
||||||
self._get_technician_ids(),
|
self._get_technician_ids(),
|
||||||
self._get_technician_ping_urls(),
|
self._get_technician_ping_urls(),
|
||||||
result[6],
|
result[8],
|
||||||
result[7],
|
result[9],
|
||||||
id=result[0],
|
id=result[0],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -20,6 +20,8 @@ from bot_data.migration.fix_updates_migration import FixUpdatesMigration
|
|||||||
from bot_data.migration.fix_user_history_migration import FixUserHistoryMigration
|
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.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.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 (
|
from bot_data.migration.short_role_name_only_highest_migration import (
|
||||||
@@ -68,3 +70,5 @@ class StartupMigrationExtension(StartupExtensionABC):
|
|||||||
services.add_transient(MigrationABC, FixUserHistoryMigration) # 10.10.2023 #401 - 1.2.0
|
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, BirthdayMigration) # 10.10.2023 #401 - 1.2.0
|
||||||
services.add_transient(MigrationABC, SteamSpecialOfferMigration) # 10.10.2023 #188 - 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
|
@@ -1,6 +1,7 @@
|
|||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
from ariadne import ObjectType
|
from ariadne import ObjectType
|
||||||
|
from cpl_core.configuration import ConfigurationABC
|
||||||
from cpl_core.dependency_injection import ServiceProviderABC
|
from cpl_core.dependency_injection import ServiceProviderABC
|
||||||
from cpl_core.type import T
|
from cpl_core.type import T
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
@@ -10,6 +11,7 @@ from bot_api.exception.service_error_code_enum import ServiceErrorCode
|
|||||||
from bot_api.exception.service_exception import ServiceException
|
from bot_api.exception.service_exception import ServiceException
|
||||||
from bot_api.route.route import Route
|
from bot_api.route.route import Route
|
||||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
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.achievement import Achievement
|
||||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
from bot_data.model.auth_role_enum import AuthRoleEnum
|
||||||
from bot_data.model.auth_user import AuthUser
|
from bot_data.model.auth_user import AuthUser
|
||||||
@@ -75,9 +77,14 @@ class QueryABC(ObjectType):
|
|||||||
def get_services(services: ServiceProviderABC) -> ServiceProviderABC:
|
def get_services(services: ServiceProviderABC) -> ServiceProviderABC:
|
||||||
return services
|
return services
|
||||||
|
|
||||||
|
@ServiceProviderABC.inject
|
||||||
|
def get_config(config: ConfigurationABC) -> ConfigurationABC:
|
||||||
|
return config
|
||||||
|
|
||||||
services = get_services()
|
services = get_services()
|
||||||
permissions: PermissionService = services.get_service(PermissionService)
|
permissions: PermissionService = services.get_service(PermissionService)
|
||||||
bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC)
|
bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC)
|
||||||
|
config = get_config()
|
||||||
|
|
||||||
if user.auth_role == AuthRoleEnum.admin:
|
if user.auth_role == AuthRoleEnum.admin:
|
||||||
return True
|
return True
|
||||||
@@ -87,6 +94,9 @@ class QueryABC(ObjectType):
|
|||||||
if permissions.is_member_technician(guild.get_member(u.discord_id)):
|
if permissions.is_member_technician(guild.get_member(u.discord_id)):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
if config.get_configuration(MAINTENANCE):
|
||||||
|
return False
|
||||||
|
|
||||||
access = False
|
access = False
|
||||||
if type(element) == Achievement:
|
if type(element) == Achievement:
|
||||||
element: Achievement = element
|
element: Achievement = element
|
||||||
@@ -215,7 +225,9 @@ class QueryABC(ObjectType):
|
|||||||
return access
|
return access
|
||||||
|
|
||||||
@ServiceProviderABC.inject
|
@ServiceProviderABC.inject
|
||||||
def _can_user_mutate_data(self, server: Server, permission: UserRoleEnum, services: ServiceProviderABC):
|
def _can_user_mutate_data(
|
||||||
|
self, server: Server, permission: UserRoleEnum, services: ServiceProviderABC, config: ConfigurationABC
|
||||||
|
):
|
||||||
permissions: PermissionService = services.get_service(PermissionService)
|
permissions: PermissionService = services.get_service(PermissionService)
|
||||||
bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC)
|
bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC)
|
||||||
|
|
||||||
@@ -227,16 +239,20 @@ class QueryABC(ObjectType):
|
|||||||
auth_user.users.where(lambda x: x.server.id == server.id).single().discord_id
|
auth_user.users.where(lambda x: x.server.id == server.id).single().discord_id
|
||||||
)
|
)
|
||||||
|
|
||||||
check_perm = lambda x: True
|
can_edit = lambda x: False
|
||||||
match permission:
|
match permission:
|
||||||
case UserRoleEnum.moderator:
|
case UserRoleEnum.moderator:
|
||||||
check_perm = lambda x: permissions.is_member_moderator(x)
|
can_edit = permissions.is_member_moderator
|
||||||
|
if config.get_configuration(MAINTENANCE):
|
||||||
|
can_edit = lambda x: False
|
||||||
case UserRoleEnum.admin:
|
case UserRoleEnum.admin:
|
||||||
check_perm = lambda x: permissions.is_member_admin(x)
|
can_edit = permissions.is_member_admin
|
||||||
|
if config.get_configuration(MAINTENANCE):
|
||||||
|
can_edit = lambda x: False
|
||||||
case UserRoleEnum.technician:
|
case UserRoleEnum.technician:
|
||||||
check_perm = lambda x: permissions.is_member_technician(x)
|
can_edit = permissions.is_member_technician
|
||||||
|
|
||||||
if not check_perm(member):
|
if not can_edit(member):
|
||||||
ex = ServiceException(ServiceErrorCode.Forbidden, f"User not allowed to mutate data")
|
ex = ServiceException(ServiceErrorCode.Forbidden, f"User not allowed to mutate data")
|
||||||
raise ex
|
raise ex
|
||||||
|
|
||||||
|
@@ -26,6 +26,7 @@ type Server implements TableWithHistoryQuery {
|
|||||||
gameServers: [GameServer]
|
gameServers: [GameServer]
|
||||||
|
|
||||||
userCount: Int
|
userCount: Int
|
||||||
|
activeUserCount: Int
|
||||||
users(filter: UserFilter, page: Page, sort: Sort): [User]
|
users(filter: UserFilter, page: Page, sort: Sort): [User]
|
||||||
|
|
||||||
achievementCount: Int
|
achievementCount: Int
|
||||||
@@ -37,6 +38,8 @@ type Server implements TableWithHistoryQuery {
|
|||||||
config: ServerConfig
|
config: ServerConfig
|
||||||
hasFeatureFlag(flag: String): FeatureFlag
|
hasFeatureFlag(flag: String): FeatureFlag
|
||||||
|
|
||||||
|
# statistic(date: String): ServerStatistic
|
||||||
|
|
||||||
createdAt: String
|
createdAt: String
|
||||||
modifiedAt: String
|
modifiedAt: String
|
||||||
|
|
||||||
|
17
bot/src/bot_graphql/graphql/serverStatistic.gql
Normal file
17
bot/src/bot_graphql/graphql/serverStatistic.gql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
type ServerStatistic {
|
||||||
|
achievementsAchieved: Int
|
||||||
|
messageCount: Int
|
||||||
|
|
||||||
|
userCount: Int
|
||||||
|
activeUserCount: Int
|
||||||
|
|
||||||
|
userJoinedVoiceChannelCount: Int
|
||||||
|
userJoinedVoiceChannelOntime: Float
|
||||||
|
|
||||||
|
userJoinedGameServerCount: Int
|
||||||
|
userJoinedGameServerOntime: Float
|
||||||
|
|
||||||
|
userWarningCount: Int
|
||||||
|
|
||||||
|
activityScore: Int
|
||||||
|
}
|
@@ -4,6 +4,8 @@ type TechnicianConfig implements TableWithHistoryQuery {
|
|||||||
waitForRestart: Int
|
waitForRestart: Int
|
||||||
waitForShutdown: Int
|
waitForShutdown: Int
|
||||||
cacheMaxMessages: Int
|
cacheMaxMessages: Int
|
||||||
|
maxSteamOfferCount: Int
|
||||||
|
maintenance: Boolean
|
||||||
featureFlagCount: Int
|
featureFlagCount: Int
|
||||||
featureFlags: [FeatureFlag]
|
featureFlags: [FeatureFlag]
|
||||||
pingURLs: [String]
|
pingURLs: [String]
|
||||||
@@ -23,6 +25,8 @@ type TechnicianConfigHistory implements HistoryTableQuery {
|
|||||||
waitForRestart: Int
|
waitForRestart: Int
|
||||||
waitForShutdown: Int
|
waitForShutdown: Int
|
||||||
cacheMaxMessages: Int
|
cacheMaxMessages: Int
|
||||||
|
maxSteamOfferCount: Int
|
||||||
|
maintenance: Boolean
|
||||||
featureFlagCount: Int
|
featureFlagCount: Int
|
||||||
featureFlags: [FeatureFlag]
|
featureFlags: [FeatureFlag]
|
||||||
|
|
||||||
@@ -59,6 +63,8 @@ input TechnicianConfigInput {
|
|||||||
waitForRestart: Int
|
waitForRestart: Int
|
||||||
waitForShutdown: Int
|
waitForShutdown: Int
|
||||||
cacheMaxMessages: Int
|
cacheMaxMessages: Int
|
||||||
|
maxSteamOfferCount: Int
|
||||||
|
maintenance: Boolean
|
||||||
featureFlags: [FeatureFlagInput]
|
featureFlags: [FeatureFlagInput]
|
||||||
pingURLs: [String]
|
pingURLs: [String]
|
||||||
technicianIds: [String]
|
technicianIds: [String]
|
||||||
|
@@ -57,6 +57,7 @@ from bot_graphql.queries.level_query import LevelQuery
|
|||||||
from bot_graphql.queries.server_config_query import ServerConfigQuery
|
from bot_graphql.queries.server_config_query import ServerConfigQuery
|
||||||
from bot_graphql.queries.server_history_query import ServerHistoryQuery
|
from bot_graphql.queries.server_history_query import ServerHistoryQuery
|
||||||
from bot_graphql.queries.server_query import ServerQuery
|
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_history_query import ShortRoleNameHistoryQuery
|
||||||
from bot_graphql.queries.short_role_name_query import ShortRoleNameQuery
|
from bot_graphql.queries.short_role_name_query import ShortRoleNameQuery
|
||||||
from bot_graphql.queries.technician_config_history_query import (
|
from bot_graphql.queries.technician_config_history_query import (
|
||||||
@@ -138,6 +139,7 @@ class GraphQLModule(ModuleABC):
|
|||||||
services.add_transient(QueryABC, ShortRoleNameQuery)
|
services.add_transient(QueryABC, ShortRoleNameQuery)
|
||||||
services.add_transient(QueryABC, UserWarningHistoryQuery)
|
services.add_transient(QueryABC, UserWarningHistoryQuery)
|
||||||
services.add_transient(QueryABC, UserWarningQuery)
|
services.add_transient(QueryABC, UserWarningQuery)
|
||||||
|
services.add_transient(QueryABC, ServerStatisticQuery)
|
||||||
|
|
||||||
services.add_transient(QueryABC, DiscordQuery)
|
services.add_transient(QueryABC, DiscordQuery)
|
||||||
services.add_transient(QueryABC, GuildQuery)
|
services.add_transient(QueryABC, GuildQuery)
|
||||||
|
7
bot/src/bot_graphql/model/server_statistics.py
Normal file
7
bot/src/bot_graphql/model/server_statistics.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from bot_data.model.server import Server
|
||||||
|
|
||||||
|
|
||||||
|
class ServerStatistics:
|
||||||
|
def __init__(self, server: Server, kwargs: dict):
|
||||||
|
self.server = server
|
||||||
|
self.kwargs = kwargs
|
@@ -41,6 +41,9 @@ class LevelMutation(QueryABC):
|
|||||||
int(input["permissions"]),
|
int(input["permissions"]),
|
||||||
server,
|
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._levels.add_level(level)
|
||||||
self._db.save_changes()
|
self._db.save_changes()
|
||||||
|
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
|
from cpl_core.configuration import ConfigurationABC
|
||||||
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 cpl_query.extension import List
|
from cpl_query.extension import List
|
||||||
|
|
||||||
from bot_api.logging.api_logger import ApiLogger
|
from bot_api.logging.api_logger import ApiLogger
|
||||||
from bot_api.route.route import Route
|
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_core.service.config_service import ConfigService
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||||
from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC
|
from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC
|
||||||
@@ -18,6 +21,7 @@ from bot_graphql.abc.query_abc import QueryABC
|
|||||||
class TechnicianConfigMutation(QueryABC):
|
class TechnicianConfigMutation(QueryABC):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
config: ConfigurationABC,
|
||||||
logger: ApiLogger,
|
logger: ApiLogger,
|
||||||
bot: DiscordBotServiceABC,
|
bot: DiscordBotServiceABC,
|
||||||
servers: ServerRepositoryABC,
|
servers: ServerRepositoryABC,
|
||||||
@@ -25,9 +29,11 @@ class TechnicianConfigMutation(QueryABC):
|
|||||||
db: DatabaseContextABC,
|
db: DatabaseContextABC,
|
||||||
config_service: ConfigService,
|
config_service: ConfigService,
|
||||||
tech_seeder: TechnicianConfigSeeder,
|
tech_seeder: TechnicianConfigSeeder,
|
||||||
|
client_utils: ClientUtilsABC,
|
||||||
):
|
):
|
||||||
QueryABC.__init__(self, "TechnicianConfigMutation")
|
QueryABC.__init__(self, "TechnicianConfigMutation")
|
||||||
|
|
||||||
|
self._config = config
|
||||||
self._logger = logger
|
self._logger = logger
|
||||||
self._bot = bot
|
self._bot = bot
|
||||||
self._servers = servers
|
self._servers = servers
|
||||||
@@ -35,6 +41,7 @@ class TechnicianConfigMutation(QueryABC):
|
|||||||
self._db = db
|
self._db = db
|
||||||
self._config_service = config_service
|
self._config_service = config_service
|
||||||
self._tech_seeder = tech_seeder
|
self._tech_seeder = tech_seeder
|
||||||
|
self._client_utils = client_utils
|
||||||
|
|
||||||
self.set_field("updateTechnicianConfig", self.resolve_update_technician_config)
|
self.set_field("updateTechnicianConfig", self.resolve_update_technician_config)
|
||||||
|
|
||||||
@@ -59,6 +66,12 @@ class TechnicianConfigMutation(QueryABC):
|
|||||||
technician_config.cache_max_messages = (
|
technician_config.cache_max_messages = (
|
||||||
input["cacheMaxMessages"] if "cacheMaxMessages" in input else 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
|
old_feature_flags = technician_config.feature_flags
|
||||||
technician_config.feature_flags = (
|
technician_config.feature_flags = (
|
||||||
dict(
|
dict(
|
||||||
@@ -91,7 +104,10 @@ class TechnicianConfigMutation(QueryABC):
|
|||||||
self._update_technician_ids(technician_config)
|
self._update_technician_ids(technician_config)
|
||||||
|
|
||||||
self._db.save_changes()
|
self._db.save_changes()
|
||||||
self._config_service.reload_technician_config()
|
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())
|
||||||
return technician_config
|
return technician_config
|
||||||
|
|
||||||
def _update_ping_urls(self, new_config: TechnicianConfig):
|
def _update_ping_urls(self, new_config: TechnicianConfig):
|
||||||
|
@@ -25,7 +25,7 @@ class GuildQuery(QueryABC):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _resolve_channels(self, g: Guild, *_, filter=None):
|
def _resolve_channels(self, g: Guild, *_, filter=None):
|
||||||
channels = List(any).extend(g.channels)
|
channels = List(any).extend(g.channels).order_by(lambda x: x.position)
|
||||||
|
|
||||||
if filter is None:
|
if filter is None:
|
||||||
return channels
|
return channels
|
||||||
@@ -39,4 +39,4 @@ class GuildQuery(QueryABC):
|
|||||||
if "type" in filter:
|
if "type" in filter:
|
||||||
channels = channels.where(lambda c: type(c).__name__ == filter["type"])
|
channels = channels.where(lambda c: type(c).__name__ == filter["type"])
|
||||||
|
|
||||||
return channels.order_by(lambda x: x.position)
|
return channels
|
||||||
|
@@ -26,6 +26,7 @@ from bot_graphql.filter.client_filter import ClientFilter
|
|||||||
from bot_graphql.filter.level_filter import LevelFilter
|
from bot_graphql.filter.level_filter import LevelFilter
|
||||||
from bot_graphql.filter.short_role_name_filter import ShortRoleNameFilter
|
from bot_graphql.filter.short_role_name_filter import ShortRoleNameFilter
|
||||||
from bot_graphql.filter.user_filter import UserFilter
|
from bot_graphql.filter.user_filter import UserFilter
|
||||||
|
from bot_graphql.model.server_statistics import ServerStatistics
|
||||||
|
|
||||||
|
|
||||||
class ServerQuery(DataQueryWithHistoryABC):
|
class ServerQuery(DataQueryWithHistoryABC):
|
||||||
@@ -76,6 +77,10 @@ class ServerQuery(DataQueryWithHistoryABC):
|
|||||||
lambda server, *_: self._levels.get_levels_by_server_id(server.id),
|
lambda server, *_: self._levels.get_levels_by_server_id(server.id),
|
||||||
LevelFilter,
|
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(
|
self.add_collection(
|
||||||
"user",
|
"user",
|
||||||
lambda server, *_: self._users.get_users_by_server_id(server.id),
|
lambda server, *_: self._users.get_users_by_server_id(server.id),
|
||||||
@@ -103,6 +108,7 @@ class ServerQuery(DataQueryWithHistoryABC):
|
|||||||
"hasFeatureFlag",
|
"hasFeatureFlag",
|
||||||
lambda server, *_, **kwargs: self._resolve_has_feature_flag(server, *_, **kwargs),
|
lambda server, *_, **kwargs: self._resolve_has_feature_flag(server, *_, **kwargs),
|
||||||
)
|
)
|
||||||
|
# self.set_field("statistic", lambda server, *_, **kwargs: ServerStatistics(server, kwargs))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_id(server: Server, *_):
|
def resolve_id(server: Server, *_):
|
||||||
|
157
bot/src/bot_graphql/queries/server_statistic_query.py
Normal file
157
bot/src/bot_graphql/queries/server_statistic_query.py
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
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()
|
@@ -14,6 +14,8 @@ class TechnicianConfigHistoryQuery(HistoryQueryABC):
|
|||||||
self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart)
|
self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart)
|
||||||
self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown)
|
self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown)
|
||||||
self.set_field("cacheMaxMessages", lambda config, *_: config.cache_max_messages)
|
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(
|
self.add_collection(
|
||||||
"featureFlag",
|
"featureFlag",
|
||||||
lambda config, *_: List(
|
lambda config, *_: List(
|
||||||
|
@@ -27,6 +27,8 @@ class TechnicianConfigQuery(DataQueryWithHistoryABC):
|
|||||||
self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart)
|
self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart)
|
||||||
self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown)
|
self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown)
|
||||||
self.set_field("cacheMaxMessages", lambda config, *_: config.cache_max_messages)
|
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(
|
self.add_collection(
|
||||||
"featureFlag",
|
"featureFlag",
|
||||||
lambda config, *_: List(
|
lambda config, *_: List(
|
||||||
|
@@ -56,7 +56,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("birthday", lambda x, *_: None if x.birthday is None else x.birthday.strftime("%d.%m.%Y"))
|
||||||
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(
|
||||||
|
@@ -35,7 +35,7 @@ class AchievementOnMessageEvent(OnMessageABC):
|
|||||||
self._servers = servers
|
self._servers = servers
|
||||||
self._users = users
|
self._users = users
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
@EventChecks.check_is_ready
|
||||||
async def on_message(self, message: discord.Message):
|
async def on_message(self, message: discord.Message):
|
||||||
if message.guild is None:
|
if message.guild is None:
|
||||||
return
|
return
|
||||||
|
@@ -9,6 +9,7 @@ from cpl_discord.service import DiscordBotServiceABC
|
|||||||
|
|
||||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||||
|
from bot_core.helper.event_checks import EventChecks
|
||||||
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.model.server_config import ServerConfig
|
from bot_data.model.server_config import ServerConfig
|
||||||
@@ -36,6 +37,7 @@ class AchievementOnReactionAddEvent(OnReactionAddABC):
|
|||||||
self._servers = servers
|
self._servers = servers
|
||||||
self._users = users
|
self._users = users
|
||||||
|
|
||||||
|
@EventChecks.check_is_ready
|
||||||
async def on_reaction_add(
|
async def on_reaction_add(
|
||||||
self,
|
self,
|
||||||
reaction: discord.reaction.Reaction,
|
reaction: discord.reaction.Reaction,
|
||||||
|
@@ -9,6 +9,7 @@ from cpl_discord.service import DiscordBotServiceABC
|
|||||||
|
|
||||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||||
|
from bot_core.helper.event_checks import EventChecks
|
||||||
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.model.server_config import ServerConfig
|
from bot_data.model.server_config import ServerConfig
|
||||||
@@ -36,6 +37,7 @@ class AchievementOnReactionRemoveEvent(OnReactionRemoveABC):
|
|||||||
self._servers = servers
|
self._servers = servers
|
||||||
self._users = users
|
self._users = users
|
||||||
|
|
||||||
|
@EventChecks.check_is_ready
|
||||||
async def on_reaction_remove(
|
async def on_reaction_remove(
|
||||||
self,
|
self,
|
||||||
reaction: discord.reaction.Reaction,
|
reaction: discord.reaction.Reaction,
|
||||||
|
@@ -7,6 +7,7 @@ from cpl_discord.service import DiscordBotServiceABC
|
|||||||
|
|
||||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||||
|
from bot_core.helper.event_checks import EventChecks
|
||||||
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.model.server_config import ServerConfig
|
from bot_data.model.server_config import ServerConfig
|
||||||
@@ -34,6 +35,7 @@ class AchievementOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC):
|
|||||||
self._servers = servers
|
self._servers = servers
|
||||||
self._users = users
|
self._users = users
|
||||||
|
|
||||||
|
@EventChecks.check_is_ready
|
||||||
async def on_voice_state_update(
|
async def on_voice_state_update(
|
||||||
self,
|
self,
|
||||||
member: discord.member.Member,
|
member: discord.member.Member,
|
||||||
|
@@ -32,7 +32,7 @@ class AutoRoleOnRawReactionAddEvent(OnRawReactionAddABC):
|
|||||||
self._auto_roles = auto_roles
|
self._auto_roles = auto_roles
|
||||||
self._reaction_handler = reaction_handler
|
self._reaction_handler = reaction_handler
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
@EventChecks.check_is_ready
|
||||||
async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
|
async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")
|
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")
|
||||||
|
@@ -32,7 +32,7 @@ class AutoRoleOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
|
|||||||
self._auto_roles = auto_roles
|
self._auto_roles = auto_roles
|
||||||
self._reaction_handler = reaction_handler
|
self._reaction_handler = reaction_handler
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
@EventChecks.check_is_ready
|
||||||
async def on_raw_reaction_remove(self, payload: RawReactionActionEvent):
|
async def on_raw_reaction_remove(self, payload: RawReactionActionEvent):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")
|
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")
|
||||||
|
@@ -34,7 +34,8 @@ class BirthdayWatcher(TaskABC):
|
|||||||
self._message_service = message_service
|
self._message_service = message_service
|
||||||
self._t = t
|
self._t = t
|
||||||
|
|
||||||
self.watch.start()
|
if not self._is_maintenance():
|
||||||
|
self.watch.start()
|
||||||
|
|
||||||
@tasks.loop(time=datetime.time(hour=8, minute=0))
|
@tasks.loop(time=datetime.time(hour=8, minute=0))
|
||||||
async def watch(self):
|
async def watch(self):
|
||||||
|
@@ -11,6 +11,7 @@ from discord.ext.commands import Context, CommandError
|
|||||||
|
|
||||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||||
from bot_core.exception.check_error import CheckError
|
from bot_core.exception.check_error import CheckError
|
||||||
|
from bot_core.helper.event_checks import EventChecks
|
||||||
from bot_data.model.technician_config import TechnicianConfig
|
from bot_data.model.technician_config import TechnicianConfig
|
||||||
|
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ class BaseOnCommandErrorEvent(OnCommandErrorABC):
|
|||||||
self._time_format_settings = time_format_settings
|
self._time_format_settings = time_format_settings
|
||||||
self._t = translate
|
self._t = translate
|
||||||
|
|
||||||
|
@EventChecks.check_is_ready
|
||||||
async def on_command_error(self, ctx: Context, error: CommandError):
|
async def on_command_error(self, ctx: Context, error: CommandError):
|
||||||
if isinstance(error, CheckError):
|
if isinstance(error, CheckError):
|
||||||
return
|
return
|
||||||
|
@@ -10,6 +10,7 @@ from cpl_translation import TranslatePipe
|
|||||||
from discord.ext.commands import Context
|
from discord.ext.commands import Context
|
||||||
|
|
||||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
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_core.logging.command_logger import CommandLogger
|
||||||
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||||
@@ -78,6 +79,7 @@ class BaseOnCommandEvent(OnCommandABC):
|
|||||||
|
|
||||||
self._logger.debug(__name__, f"User {user} sent message. xp: from {old_xp} to {user.xp}")
|
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):
|
async def on_command(self, ctx: Context):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
self._logger.info(__name__, f"Received command: {ctx.command} from {ctx.channel}")
|
self._logger.info(__name__, f"Received command: {ctx.command} from {ctx.channel}")
|
||||||
|
@@ -4,6 +4,7 @@ from cpl_discord.events import OnGuildJoinABC
|
|||||||
from cpl_discord.service import DiscordBotServiceABC
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
from discord import Guild
|
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_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.model.server import Server
|
from bot_data.model.server import Server
|
||||||
@@ -29,6 +30,7 @@ class BaseOnGuildJoinEvent(OnGuildJoinABC):
|
|||||||
self._db = db
|
self._db = db
|
||||||
self._seeder = seeder
|
self._seeder = seeder
|
||||||
|
|
||||||
|
@EventChecks.check_is_ready
|
||||||
async def on_guild_join(self, guild: Guild):
|
async def on_guild_join(self, guild: Guild):
|
||||||
if self._servers.find_server_by_discord_id(guild.id) is None:
|
if self._servers.find_server_by_discord_id(guild.id) is None:
|
||||||
self._servers.add_server(Server(guild.id))
|
self._servers.add_server(Server(guild.id))
|
||||||
|
@@ -101,9 +101,11 @@ class BaseOnMemberJoinEvent(OnMemberJoinABC):
|
|||||||
)
|
)
|
||||||
self._logger.trace(__name__, f"Notified team that a member left")
|
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):
|
async def on_member_join(self, member: discord.Member):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
|
if member.bot:
|
||||||
|
return
|
||||||
await self._client_utils.check_default_role(member)
|
await self._client_utils.check_default_role(member)
|
||||||
self._check_for_known_user(member)
|
self._check_for_known_user(member)
|
||||||
await self._add_if_not_exists_user_async(member)
|
await self._add_if_not_exists_user_async(member)
|
||||||
|
@@ -69,7 +69,7 @@ class BaseOnMemberRemoveEvent(OnMemberRemoveABC):
|
|||||||
)
|
)
|
||||||
self._logger.trace(__name__, f"Notified team that a member left")
|
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):
|
async def on_member_remove(self, member: discord.Member):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
await self._remove_user(member)
|
await self._remove_user(member)
|
||||||
|
@@ -6,6 +6,7 @@ from cpl_core.database.context import DatabaseContextABC
|
|||||||
from cpl_discord.events import OnMessageDeleteABC
|
from cpl_discord.events import OnMessageDeleteABC
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
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.helper.log_message_helper import LogMessageHelper
|
||||||
from bot_core.logging.message_logger import MessageLogger
|
from bot_core.logging.message_logger import MessageLogger
|
||||||
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
||||||
@@ -72,6 +73,7 @@ class BaseOnMessageDeleteEvent(OnMessageDeleteABC):
|
|||||||
f"Removed message from user {user}. xp: from {old_xp} to {user.xp}",
|
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):
|
async def on_message_delete(self, message: discord.Message):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
if message is None or message.guild is None:
|
if message is None or message.guild is None:
|
||||||
|
@@ -79,7 +79,7 @@ class BaseOnMessageEvent(OnMessageABC):
|
|||||||
|
|
||||||
self._logger.debug(__name__, f"User {user} sent message. xp: from {old_xp} to {user.xp}")
|
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):
|
async def on_message(self, message: discord.Message):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
if message is None or message.guild is None:
|
if message is None or message.guild is None:
|
||||||
|
@@ -26,7 +26,7 @@ class BaseOnRawReactionAddEvent(OnRawReactionAddABC):
|
|||||||
self._auto_roles = auto_roles
|
self._auto_roles = auto_roles
|
||||||
self._reaction_handler = reaction_handler
|
self._reaction_handler = reaction_handler
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
@EventChecks.check_is_ready
|
||||||
async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
|
async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
|
|
||||||
|
@@ -26,7 +26,7 @@ class BaseOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
|
|||||||
self._auto_roles = auto_roles
|
self._auto_roles = auto_roles
|
||||||
self._reaction_handler = reaction_handler
|
self._reaction_handler = reaction_handler
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
@EventChecks.check_is_ready
|
||||||
async def on_raw_reaction_remove(self, payload: RawReactionActionEvent):
|
async def on_raw_reaction_remove(self, payload: RawReactionActionEvent):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
|
|
||||||
|
@@ -4,6 +4,7 @@ from cpl_discord.events.on_scheduled_event_update_abc import OnScheduledEventUpd
|
|||||||
from cpl_discord.service import DiscordBotServiceABC
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
from discord import EventStatus
|
from discord import EventStatus
|
||||||
|
|
||||||
|
from bot_core.helper.event_checks import EventChecks
|
||||||
from modules.base.model.active_event import ActiveEvent
|
from modules.base.model.active_event import ActiveEvent
|
||||||
from modules.base.service.event_service import EventService
|
from modules.base.service.event_service import EventService
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ class BaseOnScheduledEventUpdateEvent(OnScheduledEventUpdateABC):
|
|||||||
self._bot = bot
|
self._bot = bot
|
||||||
self._events = events
|
self._events = events
|
||||||
|
|
||||||
|
@EventChecks.check_is_ready
|
||||||
async def on_scheduled_event_update(self, before: discord.ScheduledEvent, after: discord.ScheduledEvent):
|
async def on_scheduled_event_update(self, before: discord.ScheduledEvent, after: discord.ScheduledEvent):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
|
|
||||||
|
@@ -83,7 +83,7 @@ class BaseOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._logger.error(__name__, f"Ontime validation failed", e)
|
self._logger.error(__name__, f"Ontime validation failed", e)
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
@EventChecks.check_is_ready
|
||||||
async def on_voice_state_update(
|
async def on_voice_state_update(
|
||||||
self,
|
self,
|
||||||
member: discord.Member,
|
member: discord.Member,
|
||||||
@@ -97,6 +97,8 @@ class BaseOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC):
|
|||||||
)
|
)
|
||||||
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{member.guild.id}")
|
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{member.guild.id}")
|
||||||
server = self._servers.get_server_by_discord_id(member.guild.id)
|
server = self._servers.get_server_by_discord_id(member.guild.id)
|
||||||
|
if member.bot:
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if before.channel == after.channel:
|
if before.channel == after.channel:
|
||||||
|
@@ -42,7 +42,7 @@ class BaseOnVoiceStateUpdateEventHelpChannel(OnVoiceStateUpdateABC):
|
|||||||
)
|
)
|
||||||
self._logger.trace(__name__, f"Notified team that a member need help")
|
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(
|
async def on_voice_state_update(
|
||||||
self,
|
self,
|
||||||
member: discord.Member,
|
member: discord.Member,
|
||||||
|
@@ -30,7 +30,7 @@ class BaseOnVoiceStateUpdateEventScheduledEventBonus(OnVoiceStateUpdateABC):
|
|||||||
|
|
||||||
self._logger.info(__name__, f"Module {type(self)} loaded")
|
self._logger.info(__name__, f"Module {type(self)} loaded")
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
@EventChecks.check_is_ready
|
||||||
async def on_voice_state_update(
|
async def on_voice_state_update(
|
||||||
self,
|
self,
|
||||||
member: discord.Member,
|
member: discord.Member,
|
||||||
|
@@ -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.info(__name__, "Bot is ready")
|
||||||
self._logger.trace(__name__, f"Module {type(self)} stopped")
|
self._logger.trace(__name__, f"Module {type(self)} stopped")
|
||||||
|
@@ -19,4 +19,4 @@ class ConfigExtension(ApplicationExtensionABC):
|
|||||||
logger: LoggerABC = services.get_service(LoggerABC)
|
logger: LoggerABC = services.get_service(LoggerABC)
|
||||||
logger.debug(__name__, "Config extension started")
|
logger.debug(__name__, "Config extension started")
|
||||||
config: ConfigService = services.get_service(ConfigService)
|
config: ConfigService = services.get_service(ConfigService)
|
||||||
config.reload_technician_config()
|
await config.reload_technician_config()
|
||||||
|
@@ -8,6 +8,7 @@ from cpl_core.logging import LoggerABC
|
|||||||
|
|
||||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||||
|
from bot_core.environment_variables import MIGRATION_ONLY
|
||||||
from bot_core.logging.database_logger import DatabaseLogger
|
from bot_core.logging.database_logger import DatabaseLogger
|
||||||
from bot_data.service.migration_service import MigrationService
|
from bot_data.service.migration_service import MigrationService
|
||||||
|
|
||||||
@@ -25,6 +26,6 @@ class DatabaseExtension(ApplicationExtensionABC):
|
|||||||
config.add_configuration("Database_StartTime", str(datetime.now()))
|
config.add_configuration("Database_StartTime", str(datetime.now()))
|
||||||
migrations: MigrationService = services.get_service(MigrationService)
|
migrations: MigrationService = services.get_service(MigrationService)
|
||||||
migrations.migrate()
|
migrations.migrate()
|
||||||
if config.get_configuration("MIGRATION_ONLY"):
|
if config.get_configuration(MIGRATION_ONLY):
|
||||||
logger.warn(__name__, "Migrations finished. Stopping application...")
|
logger.warn(__name__, "Migrations finished. Stopping application...")
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
31
bot/src/modules/level/config/default-level.development.json
Normal file
31
bot/src/modules/level/config/default-level.development.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
31
bot/src/modules/level/config/default-level.edrafts-lapi.json
Normal file
31
bot/src/modules/level/config/default-level.edrafts-lapi.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
31
bot/src/modules/level/config/default-level.edrafts-pc.json
Normal file
31
bot/src/modules/level/config/default-level.edrafts-pc.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
31
bot/src/modules/level/config/default-level.staging.json
Normal file
31
bot/src/modules/level/config/default-level.staging.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@@ -17,7 +17,7 @@ class LevelOnMemberJoinEvent(OnMemberJoinABC):
|
|||||||
self._logger = logger
|
self._logger = logger
|
||||||
self._level = level
|
self._level = level
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
@EventChecks.check_is_ready
|
||||||
async def on_member_join(self, member: discord.Member):
|
async def on_member_join(self, member: discord.Member):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{member.guild.id}")
|
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{member.guild.id}")
|
||||||
|
@@ -17,7 +17,7 @@ class LevelOnMessageEvent(OnMessageABC):
|
|||||||
self._logger = logger
|
self._logger = logger
|
||||||
self._level = level
|
self._level = level
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
@EventChecks.check_is_ready
|
||||||
async def on_message(self, message: discord.Message):
|
async def on_message(self, message: discord.Message):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
if message.guild is None:
|
if message.guild is None:
|
||||||
|
@@ -26,7 +26,7 @@ class LevelOnRawReactionAddEvent(OnRawReactionAddABC):
|
|||||||
self._bot = bot
|
self._bot = bot
|
||||||
self._level = level
|
self._level = level
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
@EventChecks.check_is_ready
|
||||||
async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
|
async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")
|
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")
|
||||||
|
@@ -26,7 +26,7 @@ class LevelOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
|
|||||||
self._bot = bot
|
self._bot = bot
|
||||||
self._level = level
|
self._level = level
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
@EventChecks.check_is_ready
|
||||||
async def on_raw_reaction_remove(self, payload: RawReactionActionEvent):
|
async def on_raw_reaction_remove(self, payload: RawReactionActionEvent):
|
||||||
self._logger.debug(__name__, f"Module {type(self)} started")
|
self._logger.debug(__name__, f"Module {type(self)} started")
|
||||||
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")
|
server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{payload.guild_id}")
|
||||||
|
@@ -19,7 +19,7 @@ class LevelOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC):
|
|||||||
|
|
||||||
self._logger.info(__name__, f"Module {type(self)} loaded")
|
self._logger.info(__name__, f"Module {type(self)} loaded")
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
@EventChecks.check_is_ready
|
||||||
async def on_voice_state_update(
|
async def on_voice_state_update(
|
||||||
self,
|
self,
|
||||||
member: discord.Member,
|
member: discord.Member,
|
||||||
|
@@ -32,7 +32,9 @@ class LevelModule(ModuleABC):
|
|||||||
def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
|
def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
|
||||||
cwd = env.working_directory
|
cwd = env.working_directory
|
||||||
env.set_working_directory(os.path.dirname(os.path.realpath(__file__)))
|
env.set_working_directory(os.path.dirname(os.path.realpath(__file__)))
|
||||||
config.add_json_file(f"default-level.json", optional=False)
|
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)
|
||||||
env.set_working_directory(cwd)
|
env.set_working_directory(cwd)
|
||||||
|
|
||||||
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
|
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import discord
|
import discord
|
||||||
from cpl_discord.events import OnMemberUpdateABC
|
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
|
from modules.short_role_name.service.short_role_name_service import ShortRoleNameService
|
||||||
|
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@ class ShortRoleNameOnMemberUpdateEvent(OnMemberUpdateABC):
|
|||||||
OnMemberUpdateABC.__init__(self)
|
OnMemberUpdateABC.__init__(self)
|
||||||
self._service = service
|
self._service = service
|
||||||
|
|
||||||
|
@EventChecks.check_is_ready
|
||||||
async def on_member_update(self, before: discord.member.Member, after: discord.member.Member):
|
async def on_member_update(self, before: discord.member.Member, after: discord.member.Member):
|
||||||
if before.roles != after.roles or before.name != after.name:
|
if before.roles != after.roles or before.name != after.name:
|
||||||
await self._service.check_short_role_names(after)
|
await self._service.check_short_role_names(after)
|
||||||
|
@@ -21,6 +21,7 @@ from bot_data.abc.steam_special_offer_repository_abc import (
|
|||||||
)
|
)
|
||||||
from bot_data.model.server_config import ServerConfig
|
from bot_data.model.server_config import ServerConfig
|
||||||
from bot_data.model.steam_special_offer import SteamSpecialOffer
|
from bot_data.model.steam_special_offer import SteamSpecialOffer
|
||||||
|
from bot_data.model.technician_config import TechnicianConfig
|
||||||
|
|
||||||
|
|
||||||
class SteamOfferWatcher(TaskABC):
|
class SteamOfferWatcher(TaskABC):
|
||||||
@@ -33,6 +34,7 @@ class SteamOfferWatcher(TaskABC):
|
|||||||
offers: SteamSpecialOfferRepositoryABC,
|
offers: SteamSpecialOfferRepositoryABC,
|
||||||
message_service: MessageService,
|
message_service: MessageService,
|
||||||
t: TranslatePipe,
|
t: TranslatePipe,
|
||||||
|
tech_config: TechnicianConfig,
|
||||||
):
|
):
|
||||||
TaskABC.__init__(self)
|
TaskABC.__init__(self)
|
||||||
|
|
||||||
@@ -43,12 +45,14 @@ class SteamOfferWatcher(TaskABC):
|
|||||||
self._bot = bot
|
self._bot = bot
|
||||||
self._message_service = message_service
|
self._message_service = message_service
|
||||||
self._t = t
|
self._t = t
|
||||||
|
self._tech_config = tech_config
|
||||||
|
|
||||||
self._is_new = False
|
self._is_new = False
|
||||||
self._urls = {}
|
self._urls = {}
|
||||||
self._image_urls = {}
|
self._image_urls = {}
|
||||||
|
|
||||||
self.watch.start()
|
if not self._is_maintenance():
|
||||||
|
self.watch.start()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_max_count() -> int:
|
def _get_max_count() -> int:
|
||||||
@@ -66,7 +70,7 @@ class SteamOfferWatcher(TaskABC):
|
|||||||
def _get_games_from_page(self, start: int, count: int) -> List[SteamSpecialOffer]:
|
def _get_games_from_page(self, start: int, count: int) -> List[SteamSpecialOffer]:
|
||||||
games = List(SteamSpecialOffer)
|
games = List(SteamSpecialOffer)
|
||||||
result = requests.get(
|
result = requests.get(
|
||||||
f"https://store.steampowered.com/search/results?query&start={start}&count={count}&force_infinite=1&specials=1"
|
f"https://store.steampowered.com/search/results?query&start={start}&count={count}&force_infinite=1&specials=1&filter=topsellers"
|
||||||
)
|
)
|
||||||
soup = bs4.BeautifulSoup(result.text, "lxml")
|
soup = bs4.BeautifulSoup(result.text, "lxml")
|
||||||
elements = soup.find_all("a", {"class": "search_result_row"})
|
elements = soup.find_all("a", {"class": "search_result_row"})
|
||||||
@@ -108,11 +112,12 @@ class SteamOfferWatcher(TaskABC):
|
|||||||
def _get_new_game_offers(self) -> List[SteamSpecialOffer]:
|
def _get_new_game_offers(self) -> List[SteamSpecialOffer]:
|
||||||
new_offers = List(SteamSpecialOffer)
|
new_offers = List(SteamSpecialOffer)
|
||||||
|
|
||||||
# sale_count = self._get_max_count() + 100
|
sale_count = self._tech_config.max_steam_offer_count
|
||||||
sale_count = 500 # only look at first 500
|
|
||||||
# todo: let admins change the value
|
# todo: let admins change the value
|
||||||
self._logger.debug(__name__, f"Get special offers from 0 to {sale_count}")
|
self._logger.debug(__name__, f"Get special offers from 0 to {sale_count}")
|
||||||
for i in range(0, sale_count, 100):
|
for i in range(0, sale_count, 100):
|
||||||
|
if i > sale_count:
|
||||||
|
break
|
||||||
new_offers.extend(self._get_games_from_page(i, 100))
|
new_offers.extend(self._get_games_from_page(i, 100))
|
||||||
|
|
||||||
self._logger.debug(__name__, f"Got {new_offers.count()} offers")
|
self._logger.debug(__name__, f"Got {new_offers.count()} offers")
|
||||||
@@ -182,7 +187,7 @@ class SteamOfferWatcher(TaskABC):
|
|||||||
self._logger.trace(__name__, "Finished watching")
|
self._logger.trace(__name__, "Finished watching")
|
||||||
return offers_for_notifications
|
return offers_for_notifications
|
||||||
|
|
||||||
@tasks.loop(time=datetime.time(hour=16, minute=30))
|
@tasks.loop(hours=4)
|
||||||
async def watch(self):
|
async def watch(self):
|
||||||
self._logger.info(__name__, "Watching steam special offers")
|
self._logger.info(__name__, "Watching steam special offers")
|
||||||
try:
|
try:
|
||||||
|
@@ -129,7 +129,7 @@ class SyncXpGroup(DiscordCommandABC):
|
|||||||
|
|
||||||
other_server = self._servers.get_server_by_id(server_id)
|
other_server = self._servers.get_server_by_id(server_id)
|
||||||
user = self._users.get_user_by_discord_id_and_server_id(
|
user = self._users.get_user_by_discord_id_and_server_id(
|
||||||
self._servers.get_server_by_discord_id(ctx.guild.id).id, member.id
|
member.id, self._servers.get_server_by_discord_id(ctx.guild.id).id
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
"build": "ng build",
|
"build": "ng build",
|
||||||
"watch": "ng build --watch --configuration development",
|
"watch": "ng build --watch --configuration development",
|
||||||
"test": "ng test",
|
"test": "ng test",
|
||||||
|
"gv": "echo $npm_package_version",
|
||||||
"predocker-build": "npm run update-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": "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-dev": "export VERSION=$npm_package_version; ng build --configuration development; docker build -t sh-edraft.de/sdb-web:$VERSION .",
|
||||||
@@ -52,4 +53,4 @@
|
|||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
"typescript": "~4.9.5"
|
"typescript": "~4.9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -4,7 +4,6 @@ export interface Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ComponentWithTable {
|
export class ComponentWithTable {
|
||||||
|
|
||||||
private _hiddenColumns: Column[] = [];
|
private _hiddenColumns: Column[] = [];
|
||||||
set hiddenColumns(value: Column[]) {
|
set hiddenColumns(value: Column[]) {
|
||||||
this._hiddenColumns = value;
|
this._hiddenColumns = value;
|
||||||
@@ -17,10 +16,19 @@ export class ComponentWithTable {
|
|||||||
|
|
||||||
public name: string = "";
|
public name: string = "";
|
||||||
public columns: Column[] = [];
|
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(
|
constructor(
|
||||||
name: string,
|
name: string,
|
||||||
columns: string[]
|
columns: string[],
|
||||||
|
validator?: (oldElement: any, newElement: any) => boolean
|
||||||
) {
|
) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.columns = columns.map(column => {
|
this.columns = columns.map(column => {
|
||||||
@@ -32,6 +40,9 @@ export class ComponentWithTable {
|
|||||||
hiddenColumns = localStorage.getItem("hiddenColumns") ?? JSON.stringify([{}]);
|
hiddenColumns = localStorage.getItem("hiddenColumns") ?? JSON.stringify([{}]);
|
||||||
}
|
}
|
||||||
this._hiddenColumns = JSON.parse(hiddenColumns);
|
this._hiddenColumns = JSON.parse(hiddenColumns);
|
||||||
|
if (validator) {
|
||||||
|
this.validator = validator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getKey(column: string): string {
|
private getKey(column: string): string {
|
||||||
@@ -41,4 +52,14 @@ export class ComponentWithTable {
|
|||||||
public isColumnVisible(column: string): boolean {
|
public isColumnVisible(column: string): boolean {
|
||||||
return !this._hiddenColumns.map(column => column.key).includes(this.getKey(column));
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,8 @@ export interface TechnicianConfig extends DataWithHistory {
|
|||||||
waitForRestart?: number;
|
waitForRestart?: number;
|
||||||
waitForShutdown?: number;
|
waitForShutdown?: number;
|
||||||
cacheMaxMessages?: number;
|
cacheMaxMessages?: number;
|
||||||
|
maxSteamOfferCount?: number;
|
||||||
|
maintenance?: boolean;
|
||||||
featureFlags: FeatureFlag[];
|
featureFlags: FeatureFlag[];
|
||||||
pingURLs: string[];
|
pingURLs: string[];
|
||||||
technicianIds: string[];
|
technicianIds: string[];
|
||||||
|
@@ -20,9 +20,11 @@ export interface Server extends Data {
|
|||||||
autoRoles?: AutoRole[];
|
autoRoles?: AutoRole[];
|
||||||
clientCount?: number;
|
clientCount?: number;
|
||||||
clients?: Client[];
|
clients?: Client[];
|
||||||
|
statistic?: ServerStatistic;
|
||||||
levelCount?: number;
|
levelCount?: number;
|
||||||
levels?: Level[];
|
levels?: Level[];
|
||||||
userCount?: number;
|
userCount?: number;
|
||||||
|
activeUserCount?: number;
|
||||||
users?: User[];
|
users?: User[];
|
||||||
config?: ServerConfig;
|
config?: ServerConfig;
|
||||||
hasFeatureFlag?: FeatureFlag;
|
hasFeatureFlag?: FeatureFlag;
|
||||||
@@ -34,3 +36,16 @@ export interface ServerFilter {
|
|||||||
discordId?: String;
|
discordId?: String;
|
||||||
name?: 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
|
||||||
|
}
|
||||||
|
@@ -216,7 +216,7 @@ export class Mutations {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
static updateTechnicianConfig = `
|
static updateTechnicianConfig = `
|
||||||
mutation updateTechnicianConfig($id: ID, $helpCommandReferenceUrl: String, $waitForRestart: Int, $waitForShutdown: Int, $cacheMaxMessages: Int, $featureFlags: [FeatureFlagInput], $pingURLs: [String], $technicianIds: [String]) {
|
mutation updateTechnicianConfig($id: ID, $helpCommandReferenceUrl: String, $waitForRestart: Int, $waitForShutdown: Int, $cacheMaxMessages: Int, $maxSteamOfferCount: Int, $maintenance: Boolean, $featureFlags: [FeatureFlagInput], $pingURLs: [String], $technicianIds: [String]) {
|
||||||
technicianConfig {
|
technicianConfig {
|
||||||
updateTechnicianConfig(input: {
|
updateTechnicianConfig(input: {
|
||||||
id: $id,
|
id: $id,
|
||||||
@@ -224,6 +224,8 @@ export class Mutations {
|
|||||||
waitForRestart: $waitForRestart,
|
waitForRestart: $waitForRestart,
|
||||||
waitForShutdown: $waitForShutdown,
|
waitForShutdown: $waitForShutdown,
|
||||||
cacheMaxMessages: $cacheMaxMessages,
|
cacheMaxMessages: $cacheMaxMessages,
|
||||||
|
maxSteamOfferCount: $maxSteamOfferCount,
|
||||||
|
maintenance: $maintenance,
|
||||||
featureFlags: $featureFlags,
|
featureFlags: $featureFlags,
|
||||||
pingURLs: $pingURLs,
|
pingURLs: $pingURLs,
|
||||||
technicianIds: $technicianIds
|
technicianIds: $technicianIds
|
||||||
@@ -233,6 +235,8 @@ export class Mutations {
|
|||||||
waitForRestart
|
waitForRestart
|
||||||
waitForShutdown
|
waitForShutdown
|
||||||
cacheMaxMessages
|
cacheMaxMessages
|
||||||
|
maxSteamOfferCount
|
||||||
|
maintenance
|
||||||
featureFlags {
|
featureFlags {
|
||||||
key
|
key
|
||||||
value
|
value
|
||||||
|
@@ -68,6 +68,20 @@ export class Queries {
|
|||||||
name
|
name
|
||||||
iconURL
|
iconURL
|
||||||
userCount
|
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 {
|
clients {
|
||||||
id
|
id
|
||||||
discordId
|
discordId
|
||||||
@@ -82,6 +96,19 @@ export class Queries {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
// statistic {
|
||||||
|
// achievementsAchieved
|
||||||
|
// messageCount
|
||||||
|
// userCount
|
||||||
|
// activeUserCount
|
||||||
|
// userJoinedVoiceChannelCount
|
||||||
|
// userJoinedVoiceChannelOntime
|
||||||
|
// userJoinedGameServerCount
|
||||||
|
// userJoinedGameServerOntime
|
||||||
|
// userWarningCount
|
||||||
|
// activityScore
|
||||||
|
// }
|
||||||
|
|
||||||
static hasServerFeatureFlag = `
|
static hasServerFeatureFlag = `
|
||||||
query HasServerFeatureFlag($filter: ServerFilter, $flag: String) {
|
query HasServerFeatureFlag($filter: ServerFilter, $flag: String) {
|
||||||
servers(filter: $filter) {
|
servers(filter: $filter) {
|
||||||
@@ -497,6 +524,8 @@ export class Queries {
|
|||||||
waitForRestart
|
waitForRestart
|
||||||
waitForShutdown
|
waitForShutdown
|
||||||
cacheMaxMessages
|
cacheMaxMessages
|
||||||
|
maxSteamOfferCount
|
||||||
|
maintenance
|
||||||
featureFlags {
|
featureFlags {
|
||||||
key
|
key
|
||||||
value
|
value
|
||||||
@@ -532,6 +561,7 @@ export class Queries {
|
|||||||
loginMessageChannelId
|
loginMessageChannelId
|
||||||
defaultRoleId
|
defaultRoleId
|
||||||
shortRoleNameOnlySetHighestRole
|
shortRoleNameOnlySetHighestRole
|
||||||
|
gameOfferNotificationChatId
|
||||||
featureFlags {
|
featureFlags {
|
||||||
key
|
key
|
||||||
value
|
value
|
||||||
|
@@ -225,7 +225,7 @@
|
|||||||
(click)="deleteUser(user)"></button>
|
(click)="deleteUser(user)"></button>
|
||||||
|
|
||||||
<button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn"
|
<button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn"
|
||||||
icon="pi pi-check-circle" (click)="onRowEditSave(dt, user, ri)"></button>
|
icon="pi pi-check-circle" (click)="onRowEditSave(user, ri)"></button>
|
||||||
<button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn"
|
<button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn"
|
||||||
icon="pi pi-times-circle" (click)="onRowEditCancel(user, ri)"></button>
|
icon="pi pi-times-circle" (click)="onRowEditCancel(user, ri)"></button>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -31,7 +31,6 @@ export class AuthUserComponent extends ComponentWithTable implements OnInit, OnD
|
|||||||
activityValues: number[] = [0, 100];
|
activityValues: number[] = [0, 100];
|
||||||
|
|
||||||
clonedUsers: { [s: string]: AuthUserDTO; } = {};
|
clonedUsers: { [s: string]: AuthUserDTO; } = {};
|
||||||
isEditingNew: boolean = false;
|
|
||||||
|
|
||||||
authRoles = [
|
authRoles = [
|
||||||
{ label: AuthRoles[AuthRoles.Normal].toString(), value: AuthRoles.Normal },
|
{ label: AuthRoles[AuthRoles.Normal].toString(), value: AuthRoles.Normal },
|
||||||
@@ -193,7 +192,7 @@ export class AuthUserComponent extends ComponentWithTable implements OnInit, OnD
|
|||||||
this.clonedUsers[index] = { ...user };
|
this.clonedUsers[index] = { ...user };
|
||||||
}
|
}
|
||||||
|
|
||||||
onRowEditSave(table: Table, newUser: AuthUserDTO, index: number) {
|
public override onRowEditSave(newUser: AuthUserDTO, index: number) {
|
||||||
const oldUser = this.clonedUsers[index];
|
const oldUser = this.clonedUsers[index];
|
||||||
delete this.clonedUsers[index];
|
delete this.clonedUsers[index];
|
||||||
|
|
||||||
@@ -219,7 +218,6 @@ export class AuthUserComponent extends ComponentWithTable implements OnInit, OnD
|
|||||||
newUser.email == ""
|
newUser.email == ""
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
table.initRowEdit(newUser);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,7 +237,6 @@ 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 }));
|
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;
|
error.error = null;
|
||||||
table.initRowEdit(newUser);
|
|
||||||
}
|
}
|
||||||
this.spinnerService.hideSpinner();
|
this.spinnerService.hideSpinner();
|
||||||
|
|
||||||
|
@@ -109,7 +109,8 @@
|
|||||||
<form [formGroup]="testMailForm" class="content-column">
|
<form [formGroup]="testMailForm" class="content-column">
|
||||||
<div class="content-data-name">
|
<div class="content-data-name">
|
||||||
<div class="input-field content-input-field">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -136,7 +137,8 @@
|
|||||||
<div class="content-column">
|
<div class="content-column">
|
||||||
<div class="content-data-name">{{'admin.settings.bot.help_url' | translate}}:</div>
|
<div class="content-data-name">{{'admin.settings.bot.help_url' | translate}}:</div>
|
||||||
<div class="content-data-value">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -145,7 +147,8 @@
|
|||||||
<div class="content-column">
|
<div class="content-column">
|
||||||
<div class="content-data-name">{{'admin.settings.bot.wait_for_restart' | translate}}:</div>
|
<div class="content-data-name">{{'admin.settings.bot.wait_for_restart' | translate}}:</div>
|
||||||
<div class="content-data-value">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -154,7 +157,8 @@
|
|||||||
<div class="content-column">
|
<div class="content-column">
|
||||||
<div class="content-data-name">{{'admin.settings.bot.wait_for_shutdown' | translate}}:</div>
|
<div class="content-data-name">{{'admin.settings.bot.wait_for_shutdown' | translate}}:</div>
|
||||||
<div class="content-data-value">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -163,14 +167,33 @@
|
|||||||
<div class="content-column">
|
<div class="content-column">
|
||||||
<div class="content-data-name">{{'admin.settings.bot.cache_max_messages' | translate}}:</div>
|
<div class="content-data-name">{{'admin.settings.bot.cache_max_messages' | translate}}:</div>
|
||||||
<div class="content-data-value">
|
<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>
|
||||||
</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>
|
<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.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>
|
[(data)]="config.technicianIds"></app-config-list>
|
||||||
<app-feature-flag-list [(data)]="config.featureFlags"></app-feature-flag-list>
|
<app-feature-flag-list [(data)]="config.featureFlags"></app-feature-flag-list>
|
||||||
|
|
||||||
|
@@ -56,6 +56,10 @@ export class SettingsComponent implements OnInit {
|
|||||||
};
|
};
|
||||||
|
|
||||||
possibleTechnicians?: DiscordUser[];
|
possibleTechnicians?: DiscordUser[];
|
||||||
|
stateOptions: any[] = [
|
||||||
|
{ label: this.translate.instant("common.state.off"), value: false },
|
||||||
|
{ label: this.translate.instant("common.state.on"), value: true }
|
||||||
|
];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
@@ -156,6 +160,8 @@ export class SettingsComponent implements OnInit {
|
|||||||
waitForRestart: this.config.waitForRestart,
|
waitForRestart: this.config.waitForRestart,
|
||||||
waitForShutdown: this.config.waitForShutdown,
|
waitForShutdown: this.config.waitForShutdown,
|
||||||
cacheMaxMessages: this.config.cacheMaxMessages,
|
cacheMaxMessages: this.config.cacheMaxMessages,
|
||||||
|
maxSteamOfferCount: this.config.maxSteamOfferCount,
|
||||||
|
maintenance: this.config.maintenance,
|
||||||
featureFlags: this.config.featureFlags,
|
featureFlags: this.config.featureFlags,
|
||||||
pingURLs: this.config.pingURLs,
|
pingURLs: this.config.pingURLs,
|
||||||
technicianIds: this.config.technicianIds
|
technicianIds: this.config.technicianIds
|
||||||
|
@@ -0,0 +1,10 @@
|
|||||||
|
<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>
|
@@ -0,0 +1,5 @@
|
|||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
@@ -0,0 +1,23 @@
|
|||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,86 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
@@ -33,6 +33,9 @@ import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-s
|
|||||||
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";
|
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 = [
|
const PrimeNGModules = [
|
||||||
@@ -61,6 +64,8 @@ const PrimeNGModules = [
|
|||||||
MultiSelectModule,
|
MultiSelectModule,
|
||||||
InputSwitchModule,
|
InputSwitchModule,
|
||||||
CalendarModule,
|
CalendarModule,
|
||||||
|
FileUploadModule,
|
||||||
|
SelectButtonModule,
|
||||||
]
|
]
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -74,6 +79,7 @@ const PrimeNGModules = [
|
|||||||
HideableHeaderComponent,
|
HideableHeaderComponent,
|
||||||
MultiSelectColumnsComponent,
|
MultiSelectColumnsComponent,
|
||||||
FeatureFlagListComponent,
|
FeatureFlagListComponent,
|
||||||
|
DataImportAndExportComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -91,6 +97,7 @@ const PrimeNGModules = [
|
|||||||
HideableHeaderComponent,
|
HideableHeaderComponent,
|
||||||
MultiSelectColumnsComponent,
|
MultiSelectColumnsComponent,
|
||||||
FeatureFlagListComponent,
|
FeatureFlagListComponent,
|
||||||
|
DataImportAndExportComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class SharedModule {
|
export class SharedModule {
|
||||||
|
@@ -40,6 +40,7 @@
|
|||||||
<i class="pi pi-users"></i>
|
<i class="pi pi-users"></i>
|
||||||
{{server.userCount}}
|
{{server.userCount}}
|
||||||
{{'view.dashboard.server.member_count' | translate}}
|
{{'view.dashboard.server.member_count' | translate}}
|
||||||
|
{{'view.dashboard.server.active_members' | translate}} {{server ? server.activeUserCount : ''}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -27,6 +27,8 @@
|
|||||||
<button pButton label="{{'common.reset_filters' | translate}}" icon="pi pi-undo"
|
<button pButton label="{{'common.reset_filters' | translate}}" icon="pi pi-undo"
|
||||||
class="icon-btn btn" (click)="resetFilters()">
|
class="icon-btn btn" (click)="resetFilters()">
|
||||||
</button>
|
</button>
|
||||||
|
<app-data-import-and-export name="achievements" [(data)]="achievements"
|
||||||
|
[callback]="callback" [validator]="validator"></app-data-import-and-export>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@@ -246,7 +248,7 @@
|
|||||||
(click)="deleteAchievement(achievement)" [disabled]="!user || !user.isModerator && !user.isAdmin"></button>
|
(click)="deleteAchievement(achievement)" [disabled]="!user || !user.isModerator && !user.isAdmin"></button>
|
||||||
|
|
||||||
<button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn"
|
<button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn"
|
||||||
icon="pi pi-check-circle" (click)="onRowEditSave(dt, achievement, ri)" [disabled]="!user || !user.isModerator && !user.isAdmin"></button>
|
icon="pi pi-check-circle" (click)="onRowEditSave(achievement, ri)" [disabled]="!user || !user.isModerator && !user.isAdmin"></button>
|
||||||
<button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn"
|
<button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn"
|
||||||
icon="pi pi-times-circle" (click)="onRowEditCancel(ri)" [disabled]="!user || !user.isModerator && !user.isAdmin"></button>
|
icon="pi pi-times-circle" (click)="onRowEditCancel(ri)" [disabled]="!user || !user.isModerator && !user.isAdmin"></button>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -15,7 +15,13 @@ import { TranslateService } from "@ngx-translate/core";
|
|||||||
import { DataService } from "../../../../../../services/data/data.service";
|
import { DataService } from "../../../../../../services/data/data.service";
|
||||||
import { SidebarService } from "../../../../../../services/sidebar/sidebar.service";
|
import { SidebarService } from "../../../../../../services/sidebar/sidebar.service";
|
||||||
import { ActivatedRoute } from "@angular/router";
|
import { ActivatedRoute } from "@angular/router";
|
||||||
import { AchievementListQuery, AchievementTypeQuery, GameServerListQuery, LevelListQuery, Query } from "../../../../../../models/graphql/query.model";
|
import {
|
||||||
|
AchievementListQuery,
|
||||||
|
AchievementTypeQuery,
|
||||||
|
GameServerListQuery,
|
||||||
|
LevelListQuery,
|
||||||
|
Query
|
||||||
|
} from "../../../../../../models/graphql/query.model";
|
||||||
import { catchError, debounceTime, takeUntil } from "rxjs/operators";
|
import { catchError, debounceTime, takeUntil } from "rxjs/operators";
|
||||||
import { LazyLoadEvent, MenuItem } from "primeng/api";
|
import { LazyLoadEvent, MenuItem } from "primeng/api";
|
||||||
import { Table } from "primeng/table";
|
import { Table } from "primeng/table";
|
||||||
@@ -33,8 +39,6 @@ export class AchievementComponent extends ComponentWithTable implements OnInit,
|
|||||||
public achievements: Achievement[] = [];
|
public achievements: Achievement[] = [];
|
||||||
public loading = true;
|
public loading = true;
|
||||||
|
|
||||||
public isEditingNew: boolean = false;
|
|
||||||
|
|
||||||
public filterForm!: FormGroup<{
|
public filterForm!: FormGroup<{
|
||||||
id: FormControl<number | null>,
|
id: FormControl<number | null>,
|
||||||
name: FormControl<string | null>,
|
name: FormControl<string | null>,
|
||||||
@@ -81,7 +85,10 @@ export class AchievementComponent extends ComponentWithTable implements OnInit,
|
|||||||
private data: DataService,
|
private data: DataService,
|
||||||
private sidebar: SidebarService,
|
private sidebar: SidebarService,
|
||||||
private route: ActivatedRoute) {
|
private route: ActivatedRoute) {
|
||||||
super("achievement", ["id", "name", "description", "attribute", "operator", "value"]);
|
super("achievement", ["id", "name", "description", "attribute", "operator", "value"],
|
||||||
|
(oldElement: Achievement, newElement: Achievement) => {
|
||||||
|
return oldElement.name === newElement.name;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
@@ -215,7 +222,7 @@ export class AchievementComponent extends ComponentWithTable implements OnInit,
|
|||||||
this.clonedAchievements[index] = { ...user };
|
this.clonedAchievements[index] = { ...user };
|
||||||
}
|
}
|
||||||
|
|
||||||
public onRowEditSave(table: Table, newAchievement: Achievement, index: number): void {
|
public override onRowEditSave(newAchievement: Achievement, index: number): void {
|
||||||
if (this.isEditingNew && JSON.stringify(newAchievement) === JSON.stringify(this.newAchievementTemplate)) {
|
if (this.isEditingNew && JSON.stringify(newAchievement) === JSON.stringify(this.newAchievementTemplate)) {
|
||||||
this.isEditingNew = false;
|
this.isEditingNew = false;
|
||||||
this.achievements.splice(index, 1);
|
this.achievements.splice(index, 1);
|
||||||
|
@@ -26,6 +26,8 @@
|
|||||||
<button pButton label="{{'common.reset_filters' | translate}}" icon="pi pi-undo"
|
<button pButton label="{{'common.reset_filters' | translate}}" icon="pi pi-undo"
|
||||||
class="icon-btn btn" (click)="resetFilters()">
|
class="icon-btn btn" (click)="resetFilters()">
|
||||||
</button>
|
</button>
|
||||||
|
<app-data-import-and-export name="achievements" [(data)]="rules"
|
||||||
|
[callback]="callback" [validator]="validator"></app-data-import-and-export>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@@ -174,7 +176,7 @@
|
|||||||
(click)="deleteAutoRoleRule(autoRoleRule)"></button>
|
(click)="deleteAutoRoleRule(autoRoleRule)"></button>
|
||||||
|
|
||||||
<button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn"
|
<button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn"
|
||||||
icon="pi pi-check-circle" (click)="onRowEditSave(dt, autoRoleRule, ri)"></button>
|
icon="pi pi-check-circle" (click)="onRowEditSave(autoRoleRule, ri)"></button>
|
||||||
<button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn"
|
<button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn"
|
||||||
icon="pi pi-times-circle" (click)="onRowEditCancel(ri)"></button>
|
icon="pi pi-times-circle" (click)="onRowEditCancel(ri)"></button>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||||
import { DataService } from "../../../../../../services/data/data.service";
|
import { DataService } from "../../../../../../services/data/data.service";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import { AutoRoleRule, AutoRoleRuleFilter } from "../../../../../../models/data/auto_role.model";
|
import { AutoRole, AutoRoleRule, AutoRoleRuleFilter } from "../../../../../../models/data/auto_role.model";
|
||||||
import { Guild } from "../../../../../../models/data/discord.model";
|
import { Guild } from "../../../../../../models/data/discord.model";
|
||||||
import { LazyLoadEvent, MenuItem } from "primeng/api";
|
import { LazyLoadEvent, MenuItem } from "primeng/api";
|
||||||
import { User } from "../../../../../../models/data/user.model";
|
import { User } from "../../../../../../models/data/user.model";
|
||||||
@@ -40,7 +40,6 @@ export class AutoRolesRulesComponent extends ComponentWithTable implements OnIni
|
|||||||
autoRoleId!: number;
|
autoRoleId!: number;
|
||||||
|
|
||||||
clonedUsers: { [s: string]: User; } = {};
|
clonedUsers: { [s: string]: User; } = {};
|
||||||
isEditingNew: boolean = false;
|
|
||||||
|
|
||||||
newAutoRoleTemplate: AutoRoleRule = {
|
newAutoRoleTemplate: AutoRoleRule = {
|
||||||
createdAt: "",
|
createdAt: "",
|
||||||
@@ -81,7 +80,10 @@ export class AutoRolesRulesComponent extends ComponentWithTable implements OnIni
|
|||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router
|
private router: Router
|
||||||
) {
|
) {
|
||||||
super("auto-role-rules", ["id", "role", "emoji"]);
|
super("auto-role-rules", ["id", "role", "emoji"], (oldElement: AutoRoleRule, newElement: AutoRoleRule) => {
|
||||||
|
return oldElement.autoRole?.id === newElement.autoRole?.id &&
|
||||||
|
oldElement.roleId === newElement.roleId;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getEmojiUrl(name: string): string {
|
public getEmojiUrl(name: string): string {
|
||||||
@@ -203,7 +205,7 @@ export class AutoRolesRulesComponent extends ComponentWithTable implements OnIni
|
|||||||
this.clonedUsers[index] = { ...autoRoleRule };
|
this.clonedUsers[index] = { ...autoRoleRule };
|
||||||
}
|
}
|
||||||
|
|
||||||
public onRowEditSave(table: Table, newAutoRoleRule: AutoRoleRule, index: number): void {
|
public override onRowEditSave(newAutoRoleRule: AutoRoleRule, index: number): void {
|
||||||
if (this.isEditingNew && JSON.stringify(newAutoRoleRule) === JSON.stringify(this.newAutoRoleTemplate)) {
|
if (this.isEditingNew && JSON.stringify(newAutoRoleRule) === JSON.stringify(this.newAutoRoleTemplate)) {
|
||||||
this.isEditingNew = false;
|
this.isEditingNew = false;
|
||||||
this.rules.splice(index, 1);
|
this.rules.splice(index, 1);
|
||||||
|
@@ -27,6 +27,8 @@
|
|||||||
<button pButton label="{{'common.reset_filters' | translate}}" icon="pi pi-undo"
|
<button pButton label="{{'common.reset_filters' | translate}}" icon="pi pi-undo"
|
||||||
class="icon-btn btn" (click)="resetFilters()">
|
class="icon-btn btn" (click)="resetFilters()">
|
||||||
</button>
|
</button>
|
||||||
|
<app-data-import-and-export name="achievements" [(data)]="auto_roles"
|
||||||
|
[callback]="callback" [validator]="validator"></app-data-import-and-export>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@@ -209,7 +211,7 @@
|
|||||||
(click)="deleteAutoRole(autoRole)"></button>
|
(click)="deleteAutoRole(autoRole)"></button>
|
||||||
|
|
||||||
<button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn"
|
<button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn"
|
||||||
icon="pi pi-check-circle" (click)="onRowEditSave(dt, autoRole, ri)"></button>
|
icon="pi pi-check-circle" (click)="onRowEditSave(autoRole, ri)"></button>
|
||||||
<button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn"
|
<button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn"
|
||||||
icon="pi pi-times-circle" (click)="onRowEditCancel(ri)"></button>
|
icon="pi pi-times-circle" (click)="onRowEditCancel(ri)"></button>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -36,7 +36,6 @@ export class AutoRolesComponent extends ComponentWithTable implements OnInit, On
|
|||||||
loading = true;
|
loading = true;
|
||||||
|
|
||||||
clonedUsers: { [s: string]: User; } = {};
|
clonedUsers: { [s: string]: User; } = {};
|
||||||
isEditingNew: boolean = false;
|
|
||||||
|
|
||||||
newAutoRoleTemplate: AutoRole = {
|
newAutoRoleTemplate: AutoRole = {
|
||||||
createdAt: "",
|
createdAt: "",
|
||||||
@@ -77,7 +76,10 @@ export class AutoRolesComponent extends ComponentWithTable implements OnInit, On
|
|||||||
private sidebar: SidebarService,
|
private sidebar: SidebarService,
|
||||||
private route: ActivatedRoute
|
private route: ActivatedRoute
|
||||||
) {
|
) {
|
||||||
super("auto-role", ["id", "channel_id", "channel_name", "message_id", "rule_count"]);
|
super("auto-role", ["id", "channel_id", "channel_name", "message_id", "rule_count"], (oldElement: AutoRole, newElement: AutoRole) => {
|
||||||
|
return oldElement.channelId === newElement.channelId &&
|
||||||
|
oldElement.messageId === newElement.messageId;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
@@ -192,7 +194,7 @@ export class AutoRolesComponent extends ComponentWithTable implements OnInit, On
|
|||||||
this.clonedUsers[index] = { ...autoRole };
|
this.clonedUsers[index] = { ...autoRole };
|
||||||
}
|
}
|
||||||
|
|
||||||
public onRowEditSave(table: Table, newAutoRole: AutoRole, index: number): void {
|
public override onRowEditSave(newAutoRole: AutoRole, index: number): void {
|
||||||
if (this.isEditingNew && JSON.stringify(newAutoRole) === JSON.stringify(this.newAutoRoleTemplate)) {
|
if (this.isEditingNew && JSON.stringify(newAutoRole) === JSON.stringify(this.newAutoRoleTemplate)) {
|
||||||
this.isEditingNew = false;
|
this.isEditingNew = false;
|
||||||
this.auto_roles.splice(index, 1);
|
this.auto_roles.splice(index, 1);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user