Compare commits
	
		
			4 Commits
		
	
	
		
			1.2.3
			...
			65a09c428d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 65a09c428d | |||
| 1125c83d13 | |||
| 76d94c0f60 | |||
| eb3eb24e81 | 
| @@ -8,56 +8,50 @@ 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: sh-edraft.de/act-runner:latest |     container: catthehacker/ubuntu:act-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: |  | ||||||
|           token: ${{ secrets.CI_ACCESS_TOKEN }} |       - name: Shutdown stack | ||||||
|           submodules: true |         run: docker stack rm kdb_staging | ||||||
|  |  | ||||||
|       - name: Prepare bot build |       - name: Prepare bot build | ||||||
|         run: | |         run: | | ||||||
|           cd bot |           cd kdb-bot | ||||||
|           python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli |           pip install --extra-index-url https://pip.sh-edraft.de cpl-cli | ||||||
|           cpl i |           cpl i | ||||||
|  |  | ||||||
|  |       - name: Build docker bot | ||||||
|  |         run: | | ||||||
|  |           cd kdb-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 | ||||||
|  |  | ||||||
|       - name: Prepare web build |       - name: Prepare web build | ||||||
|         run: | |         run: | | ||||||
|           cd web |           cd kdb-web | ||||||
|           npm install -g ts-node |           npm install -g ts-node | ||||||
|           npm ci |           npm i | ||||||
|  |  | ||||||
|       - 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 kdb-web | ||||||
|           docker image prune -f |           docker image prune -f | ||||||
|           cp src/favicon.dev.ico src/favicon.ico |           npm run docker-build | ||||||
|           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 | ||||||
| @@ -66,6 +60,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_dev |           name: kdb_staging | ||||||
|           file: bot/docker/docker-compose.dev.yml |           file: ./docker-compose.staging.yml | ||||||
|           variables: '{}' |           variables: '{}' | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| name: Deploy prod on push | name: Deploy dev on push | ||||||
| run-name: Deploy prod on push | run-name: Deploy dev on push | ||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|     branches: |     branches: | ||||||
| @@ -8,55 +8,50 @@ 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: sh-edraft.de/act-runner:latest |     container: catthehacker/ubuntu:act-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: |  | ||||||
|           token: ${{ secrets.CI_ACCESS_TOKEN }} |       - name: Shutdown stack | ||||||
|           submodules: true |         run: docker stack rm kdb_prod | ||||||
|  |  | ||||||
|       - name: Prepare bot build |       - name: Prepare bot build | ||||||
|         run: | |         run: | | ||||||
|           cd bot |           cd kdb-bot | ||||||
|           python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli |           pip install --extra-index-url https://pip.sh-edraft.de cpl-cli | ||||||
|           cpl i |           cpl i | ||||||
|  |  | ||||||
|  |       - name: Build docker bot | ||||||
|  |         run: | | ||||||
|  |           cd kdb-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 | ||||||
|  |  | ||||||
|       - name: Prepare web build |       - name: Prepare web build | ||||||
|         run: | |         run: | | ||||||
|           cd web |           cd kdb-web | ||||||
|           npm install -g ts-node |           npm install -g ts-node | ||||||
|           npm ci |           npm i | ||||||
|  |  | ||||||
|       - 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 kdb-web | ||||||
|           docker image prune -f |           docker image prune -f | ||||||
|           npm run build |           npm run docker-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 | ||||||
| @@ -65,6 +60,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_prod |           name: kdb_prod | ||||||
|           file: bot/docker/docker-compose.yml |           file: ./docker-compose.yml | ||||||
|           variables: '{}' |           variables: '{}' | ||||||
|   | |||||||
| @@ -1,71 +0,0 @@ | |||||||
| name: Deploy staging on push |  | ||||||
| run-name: Deploy staging on push |  | ||||||
| on: |  | ||||||
|   push: |  | ||||||
|     branches: |  | ||||||
|       - staging |  | ||||||
|  |  | ||||||
| jobs: |  | ||||||
|   on-push-deploy_sh-edraft: |  | ||||||
|     runs-on: [ dobby.sh-edraft.de, ubuntu-latest ] |  | ||||||
|     container: sh-edraft.de/act-runner:latest |  | ||||||
|     steps: |  | ||||||
|       - name: Setup docker |  | ||||||
|         uses: https://github.com/papodaca/install-docker-action@main |  | ||||||
|       - run: docker -v |  | ||||||
|  |  | ||||||
|       - name: Clone Repository |  | ||||||
|         uses: https://github.com/actions/checkout@v3 |  | ||||||
|         with: |  | ||||||
|           token: ${{ secrets.CI_ACCESS_TOKEN }} |  | ||||||
|           submodules: true |  | ||||||
|  |  | ||||||
|       - name: Prepare bot build |  | ||||||
|         run: | |  | ||||||
|           cd bot |  | ||||||
|           python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli |  | ||||||
|           cpl i |  | ||||||
|  |  | ||||||
|       - name: Setup node |  | ||||||
|         uses: https://github.com/actions/setup-node@v3 |  | ||||||
|  |  | ||||||
|       - name: Prepare web build |  | ||||||
|         run: | |  | ||||||
|           cd web |  | ||||||
|           npm install -g ts-node |  | ||||||
|           npm ci |  | ||||||
|  |  | ||||||
|       - name: Shutdown stack |  | ||||||
|         run: docker stack rm sdb_staging |  | ||||||
|  |  | ||||||
|       - name: Build docker bot |  | ||||||
|         run: | |  | ||||||
|           cd bot |  | ||||||
|           docker image prune -f |  | ||||||
|           cpl build |  | ||||||
|           docker build -t sh-edraft.de/sdb-bot:$(cpl gv)-staging . |  | ||||||
|  |  | ||||||
|       - name: Build docker web |  | ||||||
|         run: | |  | ||||||
|           cd web |  | ||||||
|           docker image prune -f |  | ||||||
|           cp src/favicon.staging.ico src/favicon.ico |  | ||||||
|           npm run build |  | ||||||
|           docker build -t sh-edraft.de/sdb-web:$(npm run -s gv)-staging . |  | ||||||
|  |  | ||||||
|       - name: Set version |  | ||||||
|         run: | |  | ||||||
|           cd bot/docker |  | ||||||
|           chmod +x ./set-docker-compose-image-version.sh |  | ||||||
|           ./set-docker-compose-image-version.sh sh-edraft.de/sdb-bot:$(cd ../; cpl gv)-staging sh-edraft.de/sdb-web:$(cd ../../web; npm run -s gv;)-staging |  | ||||||
|  |  | ||||||
|       - name: Deploy Stack to sh-edraft.de |  | ||||||
|         uses: https://github.com/kgierke/portainer-stack-deployment@v1 |  | ||||||
|         with: |  | ||||||
|           portainer-url: "https://docker.sh-edraft.de" |  | ||||||
|           portainer-username: "gitea_job" |  | ||||||
|           portainer-password: "${{ secrets.docker_job }}" |  | ||||||
|           portainer-endpoint: 2 |  | ||||||
|           name: sdb_staging |  | ||||||
|           file: bot/docker/docker-compose.staging.yml |  | ||||||
|           variables: '{}' |  | ||||||
							
								
								
									
										18
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -1,9 +1,9 @@ | |||||||
| [submodule "bot/src/bot/config"] | [submodule "kdb-bot/src/bot/config"] | ||||||
| 	path = bot/src/bot/config | 	path = kdb-bot/src/bot/config | ||||||
| 	url = https://git.sh-edraft.de/sh-edraft.de/sh_discord_bot.config.git | 	url = https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot.config.git | ||||||
| [submodule "bot/src/bot_api/config"] | [submodule "kdb-bot/src/bot_api/config"] | ||||||
| 	path = bot/src/bot_api/config | 	path = kdb-bot/src/bot_api/config | ||||||
| 	url = https://git.sh-edraft.de/sh-edraft.de/sh_discord_bot.api.config.git | 	url = https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot.api.config.git | ||||||
| [submodule "bot/docker"] | [submodule "kdb-bot/docker"] | ||||||
| 	path = bot/docker | 	path = kdb-bot/docker | ||||||
| 	url = https://git.sh-edraft.de/sh-edraft.de/sh_discord_bot.docker.git | 	url = https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot.docker.git | ||||||
|   | |||||||
 Submodule bot/docker deleted from b0bacce9f6
									
								
							 Submodule bot/src/bot/config deleted from c11ca6f2e8
									
								
							| @@ -1,22 +0,0 @@ | |||||||
| import os |  | ||||||
| import shutil |  | ||||||
| from datetime import datetime |  | ||||||
|  |  | ||||||
| from cpl_core.application.application_extension_abc import ApplicationExtensionABC |  | ||||||
| from cpl_core.configuration import ConfigurationABC |  | ||||||
| from cpl_core.dependency_injection import ServiceProviderABC |  | ||||||
| from cpl_query.extension import List |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class CleanLogsExtension(ApplicationExtensionABC): |  | ||||||
|     def __init__(self): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     async def run(self, config: ConfigurationABC, services: ServiceProviderABC): |  | ||||||
|         ( |  | ||||||
|             List(str, os.listdir("logs/")) |  | ||||||
|             .where(lambda x: os.path.isdir(f"logs/{x}")) |  | ||||||
|             .order_by() |  | ||||||
|             .where(lambda x: (datetime.now() - datetime.strptime(x, "%Y-%m-%d")).days >= 7) |  | ||||||
|             .for_each(lambda x: shutil.rmtree(f"logs/{x}")) |  | ||||||
|         ) |  | ||||||
 Submodule bot/src/bot_api/config deleted from 521951b8ab
									
								
							| @@ -1,33 +0,0 @@ | |||||||
| import asyncio |  | ||||||
| from abc import abstractmethod |  | ||||||
|  |  | ||||||
| from cpl_core.configuration import ConfigurationABC |  | ||||||
| from cpl_core.dependency_injection import ServiceProviderABC |  | ||||||
| from cpl_discord.service import DiscordBotServiceABC |  | ||||||
| from discord.ext import commands |  | ||||||
|  |  | ||||||
| from bot_core.environment_variables import MAINTENANCE |  | ||||||
| from bot_core.logging.task_logger import TaskLogger |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class TaskABC(commands.Cog): |  | ||||||
|     @abstractmethod |  | ||||||
|     def __init__(self): |  | ||||||
|         commands.Cog.__init__(self) |  | ||||||
|  |  | ||||||
|     @ServiceProviderABC.inject |  | ||||||
|     def _is_maintenance(self, config: ConfigurationABC) -> bool: |  | ||||||
|         return config.get_configuration(MAINTENANCE) is True |  | ||||||
|  |  | ||||||
|     @ServiceProviderABC.inject |  | ||||||
|     async def _wait_until_ready(self, config: ConfigurationABC, logger: TaskLogger, bot: DiscordBotServiceABC): |  | ||||||
|         logger.debug(__name__, f"Waiting before ready {type(self).__name__}") |  | ||||||
|         await bot.wait_until_ready() |  | ||||||
|  |  | ||||||
|         async def wait(): |  | ||||||
|             is_ready = config.get_configuration("IS_READY") is True |  | ||||||
|             if not is_ready: |  | ||||||
|                 await asyncio.sleep(1) |  | ||||||
|                 await wait() |  | ||||||
|  |  | ||||||
|         await wait() |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| MIGRATION_ONLY = "MIGRATION_ONLY" |  | ||||||
| MAINTENANCE = "MAINTENANCE" |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| from cpl_core.configuration import ConfigurationABC |  | ||||||
| from cpl_core.environment import ApplicationEnvironmentABC |  | ||||||
| from cpl_core.time import TimeFormatSettings |  | ||||||
|  |  | ||||||
| from bot_core.abc.custom_file_logger_abc import CustomFileLoggerABC |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class TaskLogger(CustomFileLoggerABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         config: ConfigurationABC, |  | ||||||
|         time_format: TimeFormatSettings, |  | ||||||
|         env: ApplicationEnvironmentABC, |  | ||||||
|     ): |  | ||||||
|         CustomFileLoggerABC.__init__(self, "Task", config, time_format, env) |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| from abc import ABC, abstractmethod |  | ||||||
|  |  | ||||||
| from cpl_query.extension import List |  | ||||||
|  |  | ||||||
| from bot_data.model.scheduled_event import ScheduledEvent |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ScheduledEventRepositoryABC(ABC): |  | ||||||
|     @abstractmethod |  | ||||||
|     def __init__(self): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     @abstractmethod |  | ||||||
|     def get_scheduled_events(self) -> List[ScheduledEvent]: |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     @abstractmethod |  | ||||||
|     def get_scheduled_event_by_id(self, id: int) -> ScheduledEvent: |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     @abstractmethod |  | ||||||
|     def get_scheduled_events_by_server_id(self, id: int) -> List[ScheduledEvent]: |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     @abstractmethod |  | ||||||
|     def add_scheduled_event(self, scheduled_event: ScheduledEvent): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     @abstractmethod |  | ||||||
|     def update_scheduled_event(self, scheduled_event: ScheduledEvent): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     @abstractmethod |  | ||||||
|     def delete_scheduled_event(self, scheduled_event: ScheduledEvent): |  | ||||||
|         pass |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| from abc import ABC, abstractmethod |  | ||||||
| from typing import Optional |  | ||||||
|  |  | ||||||
| from cpl_query.extension import List |  | ||||||
|  |  | ||||||
| from bot_data.model.steam_special_offer import SteamSpecialOffer |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class SteamSpecialOfferRepositoryABC(ABC): |  | ||||||
|     @abstractmethod |  | ||||||
|     def __init__(self): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     @abstractmethod |  | ||||||
|     def get_steam_special_offers(self) -> List[SteamSpecialOffer]: |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     @abstractmethod |  | ||||||
|     def get_steam_special_offer_by_name(self, name: str) -> SteamSpecialOffer: |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     @abstractmethod |  | ||||||
|     def add_steam_special_offer(self, steam_special_offer: SteamSpecialOffer): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     @abstractmethod |  | ||||||
|     def update_steam_special_offer(self, steam_special_offer: SteamSpecialOffer): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     @abstractmethod |  | ||||||
|     def delete_steam_special_offer(self, steam_special_offer: SteamSpecialOffer): |  | ||||||
|         pass |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| class Migration: |  | ||||||
|     def __init__(self, name: str, version: str, script: str): |  | ||||||
|         self._name = name |  | ||||||
|         self._version = version |  | ||||||
|         self._script = script |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def name(self) -> str: |  | ||||||
|         return self._name |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def version(self) -> str: |  | ||||||
|         return self._version |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def script(self) -> str: |  | ||||||
|         return self._script |  | ||||||
| @@ -1,188 +0,0 @@ | |||||||
| from datetime import datetime |  | ||||||
| from typing import Optional |  | ||||||
|  |  | ||||||
| import discord |  | ||||||
| from cpl_core.database import TableABC |  | ||||||
|  |  | ||||||
| from bot_data.model.scheduled_event_interval_enum import ScheduledEventIntervalEnum |  | ||||||
| from bot_data.model.server import Server |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ScheduledEvent(TableABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         interval: ScheduledEventIntervalEnum, |  | ||||||
|         name: str, |  | ||||||
|         description: str, |  | ||||||
|         channel_id: int, |  | ||||||
|         start_time: datetime, |  | ||||||
|         end_time: Optional[datetime], |  | ||||||
|         entity_type: discord.EntityType, |  | ||||||
|         location: Optional[str], |  | ||||||
|         server: Optional[Server], |  | ||||||
|         created_at: datetime = None, |  | ||||||
|         modified_at: datetime = None, |  | ||||||
|         id=0, |  | ||||||
|     ): |  | ||||||
|         self._id = id |  | ||||||
|         self._interval = interval |  | ||||||
|         self._name = name |  | ||||||
|         self._description = description |  | ||||||
|         self._channel_id = channel_id |  | ||||||
|         self._start_time = start_time |  | ||||||
|         self._end_time = end_time |  | ||||||
|         self._entity_type = entity_type |  | ||||||
|         self._location = location |  | ||||||
|         self._server = server |  | ||||||
|  |  | ||||||
|         TableABC.__init__(self) |  | ||||||
|         self._created_at = created_at if created_at is not None else self._created_at |  | ||||||
|         self._modified_at = modified_at if modified_at is not None else self._modified_at |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def id(self) -> int: |  | ||||||
|         return self._id |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def interval(self) -> ScheduledEventIntervalEnum: |  | ||||||
|         return self._interval |  | ||||||
|  |  | ||||||
|     @interval.setter |  | ||||||
|     def interval(self, value: ScheduledEventIntervalEnum): |  | ||||||
|         self._interval = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def name(self) -> str: |  | ||||||
|         return self._name |  | ||||||
|  |  | ||||||
|     @name.setter |  | ||||||
|     def name(self, value: str): |  | ||||||
|         self._name = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def description(self) -> str: |  | ||||||
|         return self._description |  | ||||||
|  |  | ||||||
|     @description.setter |  | ||||||
|     def description(self, value: str): |  | ||||||
|         self._description = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def channel_id(self) -> int: |  | ||||||
|         return self._channel_id |  | ||||||
|  |  | ||||||
|     @channel_id.setter |  | ||||||
|     def channel_id(self, value: int): |  | ||||||
|         self._channel_id = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def start_time(self) -> datetime: |  | ||||||
|         return self._start_time |  | ||||||
|  |  | ||||||
|     @start_time.setter |  | ||||||
|     def start_time(self, value: datetime): |  | ||||||
|         self._start_time = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def end_time(self) -> datetime: |  | ||||||
|         return self._end_time |  | ||||||
|  |  | ||||||
|     @end_time.setter |  | ||||||
|     def end_time(self, value: datetime): |  | ||||||
|         self._end_time = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def entity_type(self) -> discord.EntityType: |  | ||||||
|         return self._entity_type |  | ||||||
|  |  | ||||||
|     @entity_type.setter |  | ||||||
|     def entity_type(self, value: discord.EntityType): |  | ||||||
|         self._entity_type = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def location(self) -> str: |  | ||||||
|         return self._location |  | ||||||
|  |  | ||||||
|     @location.setter |  | ||||||
|     def location(self, value: str): |  | ||||||
|         self._location = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def server(self) -> Server: |  | ||||||
|         return self._server |  | ||||||
|  |  | ||||||
|     @server.setter |  | ||||||
|     def server(self, value: Server): |  | ||||||
|         self._server = value |  | ||||||
|  |  | ||||||
|     @staticmethod |  | ||||||
|     def get_select_all_string() -> str: |  | ||||||
|         return str( |  | ||||||
|             f""" |  | ||||||
|             SELECT * FROM `ScheduledEvents`; |  | ||||||
|         """ |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     @staticmethod |  | ||||||
|     def get_select_by_id_string(id: int) -> str: |  | ||||||
|         return str( |  | ||||||
|             f""" |  | ||||||
|             SELECT * FROM `ScheduledEvents` |  | ||||||
|             WHERE `Id` = {id}; |  | ||||||
|         """ |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     @staticmethod |  | ||||||
|     def get_select_by_server_id_string(s_id: int) -> str: |  | ||||||
|         return str( |  | ||||||
|             f""" |  | ||||||
|             SELECT * FROM `ScheduledEvents` |  | ||||||
|             WHERE `ServerId` = {s_id}; |  | ||||||
|         """ |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def insert_string(self) -> str: |  | ||||||
|         return str( |  | ||||||
|             f""" |  | ||||||
|             INSERT INTO `ScheduledEvents` ( |  | ||||||
|                 `Interval`, `Name`, `Description`, `ChannelId`, `StartTime`, `EndTime`, `EntityType`, `Location`, `ServerId` |  | ||||||
|             ) VALUES ( |  | ||||||
|                 '{self._interval.value}', |  | ||||||
|                 '{self._name}', |  | ||||||
|                 {"NULL" if self._description is None else f"'{self._description}'"}, |  | ||||||
|                 {"NULL" if self._channel_id is None else f"'{self._channel_id}'"}, |  | ||||||
|                 '{self._start_time}', |  | ||||||
|                 {"NULL" if self._end_time is None else f"'{self._end_time}'"}, |  | ||||||
|                 '{self._entity_type.value}', |  | ||||||
|                 {"NULL" if self._location is None else f"'{self._location}'"}, |  | ||||||
|                 {self._server.id} |  | ||||||
|             ); |  | ||||||
|         """ |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def udpate_string(self) -> str: |  | ||||||
|         return str( |  | ||||||
|             f""" |  | ||||||
|             UPDATE `ScheduledEvents` |  | ||||||
|             SET `Interval` = '{self._interval.value}',  |  | ||||||
|             `Name` = '{self._name}', |  | ||||||
|             `Description` = {"NULL" if self._description is None else f"'{self._description}'"}, |  | ||||||
|             `ChannelId` = {"NULL" if self._channel_id is None else f"'{self._channel_id}'"}, |  | ||||||
|             `StartTime` = '{self._start_time}', |  | ||||||
|             `EndTime` = {"NULL" if self._end_time is None else f"'{self._end_time}'"},  |  | ||||||
|             `EntityType` = '{self._entity_type.value}', |  | ||||||
|             `Location` = {"NULL" if self._location is None else f"'{self._location}'"} |  | ||||||
|             WHERE `Id` = {self._id}; |  | ||||||
|         """ |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def delete_string(self) -> str: |  | ||||||
|         return str( |  | ||||||
|             f""" |  | ||||||
|             DELETE FROM `ScheduledEvents` |  | ||||||
|             WHERE `Id` = {self._id}; |  | ||||||
|         """ |  | ||||||
|         ) |  | ||||||
| @@ -1,118 +0,0 @@ | |||||||
| from datetime import datetime |  | ||||||
| from typing import Optional |  | ||||||
|  |  | ||||||
| import discord |  | ||||||
| from cpl_core.database import TableABC |  | ||||||
|  |  | ||||||
| from bot_data.abc.history_table_abc import HistoryTableABC |  | ||||||
| from bot_data.model.server import Server |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ScheduledEventHistory(HistoryTableABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         interval: str, |  | ||||||
|         name: str, |  | ||||||
|         description: str, |  | ||||||
|         channel_id: int, |  | ||||||
|         start_time: datetime, |  | ||||||
|         end_time: Optional[datetime], |  | ||||||
|         entity_type: discord.EntityType, |  | ||||||
|         location: Optional[str], |  | ||||||
|         server: Optional[Server], |  | ||||||
|         deleted: bool, |  | ||||||
|         date_from: str, |  | ||||||
|         date_to: str, |  | ||||||
|         id=0, |  | ||||||
|     ): |  | ||||||
|         HistoryTableABC.__init__(self) |  | ||||||
|         self._id = id |  | ||||||
|         self._interval = interval |  | ||||||
|         self._name = name |  | ||||||
|         self._description = description |  | ||||||
|         self._channel_id = channel_id |  | ||||||
|         self._start_time = start_time |  | ||||||
|         self._end_time = end_time |  | ||||||
|         self._entity_type = entity_type |  | ||||||
|         self._location = location |  | ||||||
|         self._server = server |  | ||||||
|  |  | ||||||
|         self._deleted = deleted |  | ||||||
|         self._date_from = date_from |  | ||||||
|         self._date_to = date_to |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def id(self) -> int: |  | ||||||
|         return self._id |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def interval(self) -> str: |  | ||||||
|         return self._interval |  | ||||||
|  |  | ||||||
|     @interval.setter |  | ||||||
|     def interval(self, value: str): |  | ||||||
|         self._interval = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def name(self) -> str: |  | ||||||
|         return self._name |  | ||||||
|  |  | ||||||
|     @name.setter |  | ||||||
|     def name(self, value: str): |  | ||||||
|         self._name = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def description(self) -> str: |  | ||||||
|         return self._description |  | ||||||
|  |  | ||||||
|     @description.setter |  | ||||||
|     def description(self, value: str): |  | ||||||
|         self._description = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def channel_id(self) -> int: |  | ||||||
|         return self._channel_id |  | ||||||
|  |  | ||||||
|     @channel_id.setter |  | ||||||
|     def channel_id(self, value: int): |  | ||||||
|         self._channel_id = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def start_time(self) -> datetime: |  | ||||||
|         return self._start_time |  | ||||||
|  |  | ||||||
|     @start_time.setter |  | ||||||
|     def start_time(self, value: datetime): |  | ||||||
|         self._start_time = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def end_time(self) -> datetime: |  | ||||||
|         return self._end_time |  | ||||||
|  |  | ||||||
|     @end_time.setter |  | ||||||
|     def end_time(self, value: datetime): |  | ||||||
|         self._end_time = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def entity_type(self) -> discord.EntityType: |  | ||||||
|         return self._entity_type |  | ||||||
|  |  | ||||||
|     @entity_type.setter |  | ||||||
|     def entity_type(self, value: discord.EntityType): |  | ||||||
|         self._entity_type = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def location(self) -> str: |  | ||||||
|         return self._location |  | ||||||
|  |  | ||||||
|     @location.setter |  | ||||||
|     def location(self, value: str): |  | ||||||
|         self._location = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def server(self) -> Server: |  | ||||||
|         return self._server |  | ||||||
|  |  | ||||||
|     @server.setter |  | ||||||
|     def server(self, value: Server): |  | ||||||
|         self._server = value |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| from enum import Enum |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ScheduledEventIntervalEnum(Enum): |  | ||||||
|     daily = "daily" |  | ||||||
|     weekly = "weekly" |  | ||||||
|     monthly = "monthly" |  | ||||||
|     yearly = "yearly" |  | ||||||
| @@ -1,115 +0,0 @@ | |||||||
| from datetime import datetime |  | ||||||
|  |  | ||||||
| from cpl_core.database import TableABC |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class SteamSpecialOffer(TableABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         name: str, |  | ||||||
|         original_price: float, |  | ||||||
|         discount_price: float, |  | ||||||
|         discount_pct: int, |  | ||||||
|         created_at: datetime = None, |  | ||||||
|         modified_at: datetime = None, |  | ||||||
|         id=0, |  | ||||||
|     ): |  | ||||||
|         self._id = id |  | ||||||
|         self._name = name |  | ||||||
|         self._original_price = original_price |  | ||||||
|         self._discount_price = discount_price |  | ||||||
|         self._discount_pct = discount_pct |  | ||||||
|  |  | ||||||
|         TableABC.__init__(self) |  | ||||||
|         self._created_at = created_at if created_at is not None else self._created_at |  | ||||||
|         self._modified_at = modified_at if modified_at is not None else self._modified_at |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def id(self) -> int: |  | ||||||
|         return self._id |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def name(self) -> str: |  | ||||||
|         return self._name |  | ||||||
|  |  | ||||||
|     @name.setter |  | ||||||
|     def name(self, value: str): |  | ||||||
|         self._name = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def original_price(self) -> float: |  | ||||||
|         return self._original_price |  | ||||||
|  |  | ||||||
|     @original_price.setter |  | ||||||
|     def original_price(self, value: float): |  | ||||||
|         self._original_price = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def discount_price(self) -> float: |  | ||||||
|         return self._discount_price |  | ||||||
|  |  | ||||||
|     @discount_price.setter |  | ||||||
|     def discount_price(self, value: float): |  | ||||||
|         self._discount_price = value |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def discount_pct(self) -> int: |  | ||||||
|         return self._discount_pct |  | ||||||
|  |  | ||||||
|     @discount_pct.setter |  | ||||||
|     def discount_pct(self, value: int): |  | ||||||
|         self._discount_pct = value |  | ||||||
|  |  | ||||||
|     @staticmethod |  | ||||||
|     def get_select_all_string() -> str: |  | ||||||
|         return str( |  | ||||||
|             f""" |  | ||||||
|             SELECT * FROM `SteamSpecialOffers`; |  | ||||||
|         """ |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     @staticmethod |  | ||||||
|     def get_select_by_name_string(name: str) -> str: |  | ||||||
|         return str( |  | ||||||
|             f""" |  | ||||||
|             SELECT * FROM `SteamSpecialOffers` |  | ||||||
|             WHERE `Game` = '{name}'; |  | ||||||
|         """ |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def insert_string(self) -> str: |  | ||||||
|         return str( |  | ||||||
|             f""" |  | ||||||
|             INSERT INTO `SteamSpecialOffers` ( |  | ||||||
|                 `Game`, `OriginalPrice`, `DiscountPrice`, `DiscountPct` |  | ||||||
|             ) VALUES ( |  | ||||||
|                 '{self._name}', |  | ||||||
|                 {self._original_price}, |  | ||||||
|                 {self._discount_price}, |  | ||||||
|                 {self._discount_pct} |  | ||||||
|             ); |  | ||||||
|         """ |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def udpate_string(self) -> str: |  | ||||||
|         return str( |  | ||||||
|             f""" |  | ||||||
|             UPDATE `SteamSpecialOffers` |  | ||||||
|             SET `Game` = '{self._name}', |  | ||||||
|             `OriginalPrice` = {self._original_price}, |  | ||||||
|             `DiscountPrice` = {self._discount_price}, |  | ||||||
|             `DiscountPct` = {self._discount_pct} |  | ||||||
|             WHERE `Id` = {self._id}; |  | ||||||
|         """ |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def delete_string(self) -> str: |  | ||||||
|         return str( |  | ||||||
|             f""" |  | ||||||
|             DELETE FROM `SteamSpecialOffers` |  | ||||||
|             WHERE `Id` = {self._id}; |  | ||||||
|         """ |  | ||||||
|         ) |  | ||||||
| @@ -1,43 +0,0 @@ | |||||||
| from typing import Optional |  | ||||||
|  |  | ||||||
| from bot_data.abc.history_table_abc import HistoryTableABC |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # had to name it UserWarnings instead of UserWarning because UserWarning is a builtin class |  | ||||||
| class UserWarningsHistory(HistoryTableABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         description: str, |  | ||||||
|         user: int, |  | ||||||
|         author: Optional[int], |  | ||||||
|         deleted: bool, |  | ||||||
|         date_from: str, |  | ||||||
|         date_to: str, |  | ||||||
|         id=0, |  | ||||||
|     ): |  | ||||||
|         HistoryTableABC.__init__(self) |  | ||||||
|  |  | ||||||
|         self._id = id |  | ||||||
|         self._description = description |  | ||||||
|         self._user = user |  | ||||||
|         self._author = author |  | ||||||
|  |  | ||||||
|         self._deleted = deleted |  | ||||||
|         self._date_from = date_from |  | ||||||
|         self._date_to = date_to |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def id(self) -> int: |  | ||||||
|         return self._id |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def description(self) -> str: |  | ||||||
|         return self._description |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def user(self) -> int: |  | ||||||
|         return self._user |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def author(self) -> Optional[int]: |  | ||||||
|         return self._author |  | ||||||
| @@ -1,12 +0,0 @@ | |||||||
| DROP TABLE `Servers`; |  | ||||||
|  |  | ||||||
| DROP TABLE `Users`; |  | ||||||
|  |  | ||||||
| DROP TABLE `Clients`; |  | ||||||
|  |  | ||||||
| DROP TABLE `KnownUsers`; |  | ||||||
|  |  | ||||||
| DROP TABLE `UserJoinedServers`; |  | ||||||
|  |  | ||||||
| DROP TABLE `UserJoinedVoiceChannel`; |  | ||||||
|  |  | ||||||
| @@ -1,80 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `MigrationHistory` |  | ||||||
| ( |  | ||||||
|     `MigrationId`    VARCHAR(255), |  | ||||||
|     `CreatedAt`      DATETIME(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6), |  | ||||||
|     PRIMARY KEY (`MigrationId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `Servers` |  | ||||||
| ( |  | ||||||
|     `ServerId`        BIGINT NOT NULL AUTO_INCREMENT, |  | ||||||
|     `DiscordServerId` BIGINT NOT NULL, |  | ||||||
|     `CreatedAt`       DATETIME(6), |  | ||||||
|     `LastModifiedAt`  DATETIME(6), |  | ||||||
|     PRIMARY KEY (`ServerId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `Users` |  | ||||||
| ( |  | ||||||
|     `UserId`         BIGINT NOT NULL AUTO_INCREMENT, |  | ||||||
|     `DiscordId`      BIGINT NOT NULL, |  | ||||||
|     `XP`             BIGINT NOT NULL DEFAULT 0, |  | ||||||
|     `ServerId`       BIGINT, |  | ||||||
|     `CreatedAt`      DATETIME(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6), |  | ||||||
|     FOREIGN KEY (`ServerId`) REFERENCES Servers (`ServerId`), |  | ||||||
|     PRIMARY KEY (`UserId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `Clients` |  | ||||||
| ( |  | ||||||
|     `ClientId`              BIGINT NOT NULL AUTO_INCREMENT, |  | ||||||
|     `DiscordClientId`       BIGINT NOT NULL, |  | ||||||
|     `SentMessageCount`      BIGINT NOT NULL DEFAULT 0, |  | ||||||
|     `ReceivedMessageCount`  BIGINT NOT NULL DEFAULT 0, |  | ||||||
|     `DeletedMessageCount`   BIGINT NOT NULL DEFAULT 0, |  | ||||||
|     `ReceivedCommandsCount` BIGINT NOT NULL DEFAULT 0, |  | ||||||
|     `MovedUsersCount`       BIGINT NOT NULL DEFAULT 0, |  | ||||||
|     `ServerId`              BIGINT, |  | ||||||
|     `CreatedAt`             DATETIME(6), |  | ||||||
|     `LastModifiedAt`        DATETIME(6), |  | ||||||
|     FOREIGN KEY (`ServerId`) REFERENCES Servers (`ServerId`), |  | ||||||
|     PRIMARY KEY (`ClientId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `KnownUsers` |  | ||||||
| ( |  | ||||||
|     `KnownUserId`    BIGINT NOT NULL AUTO_INCREMENT, |  | ||||||
|     `DiscordId`      BIGINT NOT NULL, |  | ||||||
|     `CreatedAt`      DATETIME(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6), |  | ||||||
|     PRIMARY KEY (`KnownUserId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `UserJoinedServers` |  | ||||||
| ( |  | ||||||
|     `JoinId`         BIGINT      NOT NULL AUTO_INCREMENT, |  | ||||||
|     `UserId`         BIGINT      NOT NULL, |  | ||||||
|     `JoinedOn`       DATETIME(6) NOT NULL, |  | ||||||
|     `LeavedOn`       DATETIME(6), |  | ||||||
|     `CreatedAt`      DATETIME(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6), |  | ||||||
|     FOREIGN KEY (`UserId`) REFERENCES Users (`UserId`), |  | ||||||
|     PRIMARY KEY (`JoinId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `UserJoinedVoiceChannel` |  | ||||||
| ( |  | ||||||
|     `JoinId`           BIGINT      NOT NULL AUTO_INCREMENT, |  | ||||||
|     `UserId`           BIGINT      NOT NULL, |  | ||||||
|     `DiscordChannelId` BIGINT      NOT NULL, |  | ||||||
|     `JoinedOn`         DATETIME(6) NOT NULL, |  | ||||||
|     `LeavedOn`         DATETIME(6), |  | ||||||
|     `CreatedAt`        DATETIME(6), |  | ||||||
|     `LastModifiedAt`   DATETIME(6), |  | ||||||
|     FOREIGN KEY (`UserId`) REFERENCES Users (`UserId`), |  | ||||||
|     PRIMARY KEY (`JoinId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| DROP TABLE `AutoRoleRules`; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| DROP TABLE `AutoRoles`; |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `AutoRoles` |  | ||||||
| ( |  | ||||||
|     `AutoRoleId`       BIGINT NOT NULL AUTO_INCREMENT, |  | ||||||
|     `ServerId`         BIGINT, |  | ||||||
|     `DiscordMessageId` BIGINT NOT NULL, |  | ||||||
|     `CreatedAt`        DATETIME(6), |  | ||||||
|     `LastModifiedAt`   DATETIME(6), |  | ||||||
|     PRIMARY KEY (`AutoRoleId`), |  | ||||||
|     FOREIGN KEY (`ServerId`) REFERENCES `Servers` (`ServerId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `AutoRoleRules` |  | ||||||
| ( |  | ||||||
|     `AutoRoleRuleId`   BIGINT NOT NULL AUTO_INCREMENT, |  | ||||||
|     `AutoRoleId`       BIGINT, |  | ||||||
|     `DiscordEmojiName` VARCHAR(64), |  | ||||||
|     `DiscordRoleId`    BIGINT NOT NULL, |  | ||||||
|     `CreatedAt`        DATETIME(6), |  | ||||||
|     `LastModifiedAt`   DATETIME(6), |  | ||||||
|     PRIMARY KEY (`AutoRoleRuleId`), |  | ||||||
|     FOREIGN KEY (`AutoRoleId`) REFERENCES `AutoRoles` (`AutoRoleId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| DROP TABLE `AuthUserUsersRelations`; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| DROP TABLE `AuthUsers`; |  | ||||||
| @@ -1,34 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `AuthUsers` |  | ||||||
| ( |  | ||||||
|     `Id`                     BIGINT      NOT NULL AUTO_INCREMENT, |  | ||||||
|     `FirstName`              VARCHAR(255), |  | ||||||
|     `LastName`               VARCHAR(255), |  | ||||||
|     `EMail`                  VARCHAR(255), |  | ||||||
|     `Password`               VARCHAR(255), |  | ||||||
|     `PasswordSalt`           VARCHAR(255), |  | ||||||
|     `RefreshToken`           VARCHAR(255), |  | ||||||
|     `ConfirmationId`         VARCHAR(255)         DEFAULT NULL, |  | ||||||
|     `ForgotPasswordId`       VARCHAR(255)         DEFAULT NULL, |  | ||||||
|     `OAuthId`                VARCHAR(255)         DEFAULT NULL, |  | ||||||
|     `RefreshTokenExpiryTime` DATETIME(6) NOT NULL, |  | ||||||
|     `AuthRole`               INT         NOT NULL DEFAULT 0, |  | ||||||
|     `CreatedAt`              DATETIME(6) NOT NULL, |  | ||||||
|     `LastModifiedAt`         DATETIME(6) NOT NULL, |  | ||||||
|     PRIMARY KEY (`Id`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `AuthUserUsersRelations` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT      NOT NULL AUTO_INCREMENT, |  | ||||||
|     `AuthUserId`     BIGINT DEFAULT NULL, |  | ||||||
|     `UserId`         BIGINT DEFAULT NULL, |  | ||||||
|     `CreatedAt`      DATETIME(6) NOT NULL, |  | ||||||
|     `LastModifiedAt` DATETIME(6) NOT NULL, |  | ||||||
|     PRIMARY KEY (`Id`), |  | ||||||
|     FOREIGN KEY (`AuthUserId`) REFERENCES `AuthUsers` (`Id`), |  | ||||||
|     FOREIGN KEY (`UserId`) REFERENCES `Users` (`UserId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| DROP TABLE `Levels`; |  | ||||||
|  |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `Levels` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT       NOT NULL AUTO_INCREMENT, |  | ||||||
|     `Name`           VARCHAR(255) NOT NULL, |  | ||||||
|     `Color`          VARCHAR(8)   NOT NULL, |  | ||||||
|     `MinXp`          BIGINT       NOT NULL, |  | ||||||
|     `PermissionInt`  BIGINT       NOT NULL, |  | ||||||
|     `ServerId`       BIGINT, |  | ||||||
|     `CreatedAt`      DATETIME(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6), |  | ||||||
|     PRIMARY KEY (`Id`), |  | ||||||
|     FOREIGN KEY (`ServerId`) REFERENCES `Servers` (`ServerId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| DROP TABLE `Statistics`; |  | ||||||
|  |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `Statistics` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT       NOT NULL AUTO_INCREMENT, |  | ||||||
|     `Name`           VARCHAR(255) NOT NULL, |  | ||||||
|     `Description`    VARCHAR(255) NOT NULL, |  | ||||||
|     `Code`           LONGTEXT     NOT NULL, |  | ||||||
|     `ServerId`       BIGINT, |  | ||||||
|     `CreatedAt`      DATETIME(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6), |  | ||||||
|     PRIMARY KEY (`Id`), |  | ||||||
|     FOREIGN KEY (`ServerId`) REFERENCES `Servers` (`ServerId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| ALTER TABLE AutoRoles |  | ||||||
|     DROP COLUMN DiscordChannelId; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| ALTER TABLE AutoRoles |  | ||||||
|     ADD DiscordChannelId BIGINT NOT NULL AFTER ServerId; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| DROP TABLE `UserMessageCountPerHour`; |  | ||||||
|  |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `UserMessageCountPerHour` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT      NOT NULL AUTO_INCREMENT, |  | ||||||
|     `Date`           DATETIME(6) NOT NULL, |  | ||||||
|     `Hour`           BIGINT, |  | ||||||
|     `XPCount`        BIGINT, |  | ||||||
|     `UserId`         BIGINT, |  | ||||||
|     `CreatedAt`      DATETIME(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6), |  | ||||||
|     PRIMARY KEY (`Id`), |  | ||||||
|     FOREIGN KEY (`UserId`) REFERENCES `Users` (`UserId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| DROP TABLE `ApiKeys`; |  | ||||||
|  |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `ApiKeys` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT       NOT NULL AUTO_INCREMENT, |  | ||||||
|     `Identifier`     VARCHAR(255) NOT NULL, |  | ||||||
|     `Key`            VARCHAR(255) NOT NULL, |  | ||||||
|     `CreatorId`      BIGINT       NULL, |  | ||||||
|     `CreatedAt`      DATETIME(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6), |  | ||||||
|     PRIMARY KEY (`Id`), |  | ||||||
|     FOREIGN KEY (`CreatorId`) REFERENCES `Users` (`UserId`), |  | ||||||
|     CONSTRAINT UC_Identifier_Key UNIQUE (`Identifier`, `Key`), |  | ||||||
|     CONSTRAINT UC_Key UNIQUE (`Key`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| DROP TABLE `UserJoinedGameServer`; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| DROP TABLE `UserGameIdents`; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| DROP TABLE `GameServers`; |  | ||||||
|  |  | ||||||
| @@ -1,46 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `GameServers` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT       NOT NULL AUTO_INCREMENT, |  | ||||||
|     `Name`           VARCHAR(255) NOT NULL, |  | ||||||
|     `ServerId`       BIGINT       NOT NULL, |  | ||||||
|     `ApiKeyId`       BIGINT       NOT NULL, |  | ||||||
|     `CreatedAt`      DATETIME(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6), |  | ||||||
|     FOREIGN KEY (`ServerId`) REFERENCES Servers (`ServerId`), |  | ||||||
|     FOREIGN KEY (`ApiKeyId`) REFERENCES ApiKeys (`Id`), |  | ||||||
|     PRIMARY KEY (`Id`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `UserJoinedGameServer` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT      NOT NULL AUTO_INCREMENT, |  | ||||||
|     `UserId`         BIGINT      NOT NULL, |  | ||||||
|     `GameServerId`   BIGINT      NOT NULL, |  | ||||||
|     `JoinedOn`       DATETIME(6) NOT NULL, |  | ||||||
|     `LeavedOn`       DATETIME(6), |  | ||||||
|     `CreatedAt`      DATETIME(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6), |  | ||||||
|     FOREIGN KEY (`UserId`) REFERENCES Users (`UserId`), |  | ||||||
|     FOREIGN KEY (`GameServerId`) REFERENCES GameServers (`Id`), |  | ||||||
|     PRIMARY KEY (`Id`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `UserGameIdents` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT       NOT NULL AUTO_INCREMENT, |  | ||||||
|     `UserId`         BIGINT       NOT NULL, |  | ||||||
|     `GameServerId`   BIGINT       NOT NULL, |  | ||||||
|     `Ident`          VARCHAR(255) NOT NULL, |  | ||||||
|     `CreatedAt`      DATETIME(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6), |  | ||||||
|     FOREIGN KEY (`UserId`) REFERENCES Users (`UserId`), |  | ||||||
|     FOREIGN KEY (`GameServerId`) REFERENCES GameServers (`Id`), |  | ||||||
|     CONSTRAINT UC_UserGameIdent UNIQUE (`GameServerId`, `Ident`), |  | ||||||
|     PRIMARY KEY (`Id`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `Statistics` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT       NOT NULL AUTO_INCREMENT, |  | ||||||
|     `Name`           VARCHAR(255) NOT NULL, |  | ||||||
|     `Description`    VARCHAR(255) NOT NULL, |  | ||||||
|     `Code`           LONGTEXT     NOT NULL, |  | ||||||
|     `ServerId`       BIGINT, |  | ||||||
|     `CreatedAt`      DATETIME(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6), |  | ||||||
|     PRIMARY KEY (`Id`), |  | ||||||
|     FOREIGN KEY (`ServerId`) REFERENCES `Servers` (`ServerId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,3 +0,0 @@ | |||||||
| DROP TABLE IF EXISTS `Statistics`; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| DROP TABLE `UserWarnings`; |  | ||||||
|  |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `UserWarnings` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT       NOT NULL AUTO_INCREMENT, |  | ||||||
|     `Description`    VARCHAR(255) NOT NULL, |  | ||||||
|     `UserId`         BIGINT       NOT NULL, |  | ||||||
|     `Author`         BIGINT       NULL, |  | ||||||
|     `CreatedAt`      DATETIME(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6), |  | ||||||
|     PRIMARY KEY (`Id`), |  | ||||||
|     FOREIGN KEY (`UserId`) REFERENCES `Users` (`UserId`), |  | ||||||
|     FOREIGN KEY (`Author`) REFERENCES `Users` (`UserId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,34 +0,0 @@ | |||||||
| DROP TABLE `ApiKeysHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `AuthUsersHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `AuthUserUsersRelationsHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `AutoRoleRulesHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `AutoRolesHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `ClientsHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `GameServersHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `KnownUsersHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `LevelsHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `ServersHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `UserGameIdentsHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `UserJoinedGameServerHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `UserJoinedServersHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `UserJoinedVoiceChannelHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `UserMessageCountPerHourHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `UsersHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `UserWarningsHistory`; |  | ||||||
|  |  | ||||||
| @@ -1,711 +0,0 @@ | |||||||
| ALTER TABLE `ApiKeys` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `ApiKeys` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `ApiKeysHistory` |  | ||||||
| ( |  | ||||||
|     `Id`         BIGINT(20)   NOT NULL, |  | ||||||
|     `Identifier` VARCHAR(255) NOT NULL, |  | ||||||
|     `Key`        VARCHAR(255) NOT NULL, |  | ||||||
|     `CreatorId`  BIGINT(20) DEFAULT NULL, |  | ||||||
|     `Deleted`    BOOL       DEFAULT FALSE, |  | ||||||
|     `DateFrom`   DATETIME(6)  NOT NULL, |  | ||||||
|     `DateTo`     DATETIME(6)  NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_ApiKeysUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_ApiKeysUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `ApiKeys` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `ApiKeysHistory` (`Id`, `Identifier`, `Key`, `CreatorId`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.Identifier, OLD.Key, OLD.CreatorId, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_ApiKeysDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_ApiKeysDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `ApiKeys` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `ApiKeysHistory` (`Id`, `Identifier`, `Key`, `CreatorId`, `Deleted`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.Identifier, OLD.Key, OLD.CreatorId, TRUE, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `AuthUsers` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `AuthUsers` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `AuthUsersHistory` |  | ||||||
| ( |  | ||||||
|     `Id`                     BIGINT(20)  NOT NULL, |  | ||||||
|     `FirstName`              VARCHAR(255)         DEFAULT NULL, |  | ||||||
|     `LastName`               VARCHAR(255)         DEFAULT NULL, |  | ||||||
|     `EMail`                  VARCHAR(255)         DEFAULT NULL, |  | ||||||
|     `Password`               VARCHAR(255)         DEFAULT NULL, |  | ||||||
|     `PasswordSalt`           VARCHAR(255)         DEFAULT NULL, |  | ||||||
|     `RefreshToken`           VARCHAR(255)         DEFAULT NULL, |  | ||||||
|     `ConfirmationId`         VARCHAR(255)         DEFAULT NULL, |  | ||||||
|     `ForgotPasswordId`       VARCHAR(255)         DEFAULT NULL, |  | ||||||
|     `OAuthId`                VARCHAR(255)         DEFAULT NULL, |  | ||||||
|     `RefreshTokenExpiryTime` DATETIME(6) NOT NULL, |  | ||||||
|     `AuthRole`               BIGINT(11)  NOT NULL DEFAULT 0, |  | ||||||
|     `Deleted`                BOOL                 DEFAULT FALSE, |  | ||||||
|     `DateFrom`               DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`                 DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_AuthUsersUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_AuthUsersUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `AuthUsers` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `AuthUsersHistory` (`Id`, `FirstName`, `LastName`, `EMail`, `Password`, `PasswordSalt`, |  | ||||||
|                                     `RefreshToken`, `ConfirmationId`, `ForgotPasswordId`, `OAuthId`, |  | ||||||
|                                     `RefreshTokenExpiryTime`, `AuthRole`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.FirstName, OLD.LastName, OLD.EMail, OLD.Password, OLD.PasswordSalt, OLD.RefreshToken, |  | ||||||
|             OLD.ConfirmationId, OLD.ForgotPasswordId, OLD.OAuthId, OLD.RefreshTokenExpiryTime, OLD.AuthRole, |  | ||||||
|             OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_AuthUsersDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_AuthUsersDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `AuthUsers` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `AuthUsersHistory` (`Id`, `FirstName`, `LastName`, `EMail`, `Password`, `PasswordSalt`, `RefreshToken`, |  | ||||||
|                                     `ConfirmationId`, `ForgotPasswordId`, `OAuthId`, `RefreshTokenExpiryTime`, |  | ||||||
|                                     `AuthRole`, `Deleted`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.FirstName, OLD.LastName, OLD.EMail, OLD.Password, OLD.PasswordSalt, OLD.RefreshToken, |  | ||||||
|             OLD.ConfirmationId, OLD.ForgotPasswordId, OLD.OAuthId, OLD.RefreshTokenExpiryTime, OLD.AuthRole, TRUE, |  | ||||||
|             OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `AuthUserUsersRelations` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `AuthUserUsersRelations` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `AuthUserUsersRelationsHistory` |  | ||||||
| ( |  | ||||||
|     `Id`         BIGINT(20)  NOT NULL, |  | ||||||
|     `AuthUserId` BIGINT(20) DEFAULT NULL, |  | ||||||
|     `UserId`     BIGINT(20) DEFAULT NULL, |  | ||||||
|     `Deleted`    BOOL       DEFAULT FALSE, |  | ||||||
|     `DateFrom`   DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`     DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_AuthUserUsersRelationsUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_AuthUserUsersRelationsUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `AuthUserUsersRelations` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `AuthUserUsersRelationsHistory` (`Id`, `AuthUserId`, `UserId`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.AuthUserId, OLD.UserId, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_AuthUserUsersRelationsDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_AuthUserUsersRelationsDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `AuthUserUsersRelations` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `AuthUserUsersRelationsHistory` (`Id`, `AuthUserId`, `UserId`, `Deleted`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.AuthUserId, OLD.UserId, TRUE, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `AutoRoleRules` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `AutoRoleRules` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `AutoRoleRulesHistory` |  | ||||||
| ( |  | ||||||
|     `Id`               BIGINT(20)  NOT NULL, |  | ||||||
|     `AutoRoleId`       BIGINT(20)  DEFAULT NULL, |  | ||||||
|     `DiscordEmojiName` VARCHAR(64) DEFAULT NULL, |  | ||||||
|     `DiscordRoleId`    BIGINT(20)  NOT NULL, |  | ||||||
|     `Deleted`          BOOL        DEFAULT FALSE, |  | ||||||
|     `DateFrom`         DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`           DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_AutoRoleRulesUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_AutoRoleRulesUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `AutoRoleRules` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `AutoRoleRulesHistory` (`Id`, `AutoRoleId`, `DiscordEmojiName`, `DiscordRoleId`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.AutoRoleRuleId, OLD.AutoRoleId, OLD.DiscordEmojiName, OLD.DiscordRoleId, OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_AutoRoleRulesDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_AutoRoleRulesDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `AutoRoleRules` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `AutoRoleRulesHistory` (`Id`, `AutoRoleId`, `DiscordEmojiName`, `DiscordRoleId`, `Deleted`, `DateFrom`, |  | ||||||
|                                         `DateTo`) |  | ||||||
|     VALUES (OLD.AutoRoleRuleId, OLD.AutoRoleId, OLD.DiscordEmojiName, OLD.DiscordRoleId, TRUE, OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `AutoRoles` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `AutoRoles` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `AutoRolesHistory` |  | ||||||
| ( |  | ||||||
|     `Id`               BIGINT(20)  NOT NULL, |  | ||||||
|     `ServerId`         BIGINT(20) DEFAULT NULL, |  | ||||||
|     `DiscordChannelId` BIGINT(20)  NOT NULL, |  | ||||||
|     `DiscordMessageId` BIGINT(20)  NOT NULL, |  | ||||||
|     `Deleted`          BOOL       DEFAULT FALSE, |  | ||||||
|     `DateFrom`         DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`           DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_AutoRolesUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_AutoRolesUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `AutoRoles` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `AutoRolesHistory` (`Id`, `ServerId`, `DiscordChannelId`, `DiscordMessageId`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.AutoRoleId, OLD.ServerId, OLD.DiscordChannelId, OLD.DiscordMessageId, OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_AutoRolesDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_AutoRolesDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `AutoRoles` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `AutoRolesHistory` (`Id`, `ServerId`, `DiscordChannelId`, `DiscordMessageId`, `Deleted`, `DateFrom`, |  | ||||||
|                                     `DateTo`) |  | ||||||
|     VALUES (OLD.AutoRoleId, OLD.ServerId, OLD.DiscordChannelId, OLD.DiscordMessageId, TRUE, OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `Clients` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `Clients` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `ClientsHistory` |  | ||||||
| ( |  | ||||||
|     `Id`                    BIGINT(20)  NOT NULL, |  | ||||||
|     `DiscordId`             BIGINT(20)  NOT NULL, |  | ||||||
|     `SentMessageCount`      BIGINT(20)  NOT NULL DEFAULT 0, |  | ||||||
|     `ReceivedMessageCount`  BIGINT(20)  NOT NULL DEFAULT 0, |  | ||||||
|     `DeletedMessageCount`   BIGINT(20)  NOT NULL DEFAULT 0, |  | ||||||
|     `ReceivedCommandsCount` BIGINT(20)  NOT NULL DEFAULT 0, |  | ||||||
|     `MovedUsersCount`       BIGINT(20)  NOT NULL DEFAULT 0, |  | ||||||
|     `ServerId`              BIGINT(20)           DEFAULT NULL, |  | ||||||
|     `Deleted`               BOOL                 DEFAULT FALSE, |  | ||||||
|     `DateFrom`              DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`                DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_ClientsUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_ClientsUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `Clients` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `ClientsHistory` (`Id`, `DiscordId`, `SentMessageCount`, `ReceivedMessageCount`, `DeletedMessageCount`, |  | ||||||
|                                   `ReceivedCommandsCount`, `MovedUsersCount`, `ServerId`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.ClientId, OLD.DiscordClientId, OLD.SentMessageCount, OLD.ReceivedMessageCount, OLD.DeletedMessageCount, |  | ||||||
|             OLD.ReceivedCommandsCount, OLD.MovedUsersCount, OLD.ServerId, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_ClientsDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_ClientsDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `Clients` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `ClientsHistory` (`Id`, `DiscordId`, `SentMessageCount`, `ReceivedMessageCount`, `DeletedMessageCount`, |  | ||||||
|                                   `ReceivedCommandsCount`, `MovedUsersCount`, `ServerId`, `Deleted`, `DateFrom`, |  | ||||||
|                                   `DateTo`) |  | ||||||
|     VALUES (OLD.ClientId, OLD.DiscordClientId, OLD.SentMessageCount, OLD.ReceivedMessageCount, OLD.DeletedMessageCount, |  | ||||||
|             OLD.ReceivedCommandsCount, OLD.MovedUsersCount, OLD.ServerId, TRUE, OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `GameServers` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `GameServers` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `GameServersHistory` |  | ||||||
| ( |  | ||||||
|     `Id`       BIGINT(20)   NOT NULL, |  | ||||||
|     `Name`     VARCHAR(255) NOT NULL, |  | ||||||
|     `ServerId` BIGINT(20)   NOT NULL, |  | ||||||
|     `ApiKeyId` BIGINT(20)   NOT NULL, |  | ||||||
|     `Deleted`  BOOL DEFAULT FALSE, |  | ||||||
|     `DateFrom` DATETIME(6)  NOT NULL, |  | ||||||
|     `DateTo`   DATETIME(6)  NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_GameServersUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_GameServersUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `GameServers` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `GameServersHistory` (`Id`, `Name`, `ServerId`, `ApiKeyId`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.Name, OLD.ServerId, OLD.ApiKeyId, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_GameServersDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_GameServersDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `GameServers` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `GameServersHistory` (`Id`, `Name`, `ServerId`, `ApiKeyId`, `Deleted`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.Name, OLD.ServerId, OLD.ApiKeyId, TRUE, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `KnownUsers` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `KnownUsers` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `KnownUsersHistory` |  | ||||||
| ( |  | ||||||
|     `Id`        BIGINT(20)  NOT NULL, |  | ||||||
|     `DiscordId` BIGINT(20)  NOT NULL, |  | ||||||
|     `Deleted`   BOOL DEFAULT FALSE, |  | ||||||
|     `DateFrom`  DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`    DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_KnownUsersUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_KnownUsersUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `KnownUsers` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `KnownUsersHistory` (`Id`, `DiscordId`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.KnownUserId, OLD.DiscordId, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_KnownUsersDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_KnownUsersDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `KnownUsers` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `KnownUsersHistory` (`Id`, `DiscordId`, `Deleted`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.KnownUserId, OLD.DiscordId, TRUE, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `Levels` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `Levels` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `LevelsHistory` |  | ||||||
| ( |  | ||||||
|     `Id`            BIGINT(20)   NOT NULL, |  | ||||||
|     `Name`          VARCHAR(255) NOT NULL, |  | ||||||
|     `Color`         VARCHAR(8)   NOT NULL, |  | ||||||
|     `MinXp`         BIGINT(20)   NOT NULL, |  | ||||||
|     `PermissionInt` BIGINT(20)   NOT NULL, |  | ||||||
|     `ServerId`      BIGINT(20) DEFAULT NULL, |  | ||||||
|     `Deleted`       BOOL       DEFAULT FALSE, |  | ||||||
|     `DateFrom`      DATETIME(6)  NOT NULL, |  | ||||||
|     `DateTo`        DATETIME(6)  NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_LevelsUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_LevelsUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `Levels` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `LevelsHistory` (`Id`, `Name`, `Color`, `MinXp`, `PermissionInt`, `ServerId`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.Name, OLD.Color, OLD.MinXp, OLD.PermissionInt, OLD.ServerId, OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_LevelsDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_LevelsDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `Levels` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `LevelsHistory` (`Id`, `Name`, `Color`, `MinXp`, `PermissionInt`, `ServerId`, `Deleted`, `DateFrom`, |  | ||||||
|                                  `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.Name, OLD.Color, OLD.MinXp, OLD.PermissionInt, OLD.ServerId, TRUE, OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `Servers` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `Servers` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `ServersHistory` |  | ||||||
| ( |  | ||||||
|     `Id`        BIGINT(20)  NOT NULL, |  | ||||||
|     `DiscordId` BIGINT(20)  NOT NULL, |  | ||||||
|     `Deleted`   BOOL DEFAULT FALSE, |  | ||||||
|     `DateFrom`  DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`    DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_ServersUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_ServersUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `Servers` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `ServersHistory` (`Id`, `DiscordId`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.ServerId, OLD.DiscordServerId, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_ServersDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_ServersDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `Servers` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `ServersHistory` (`Id`, `DiscordId`, `Deleted`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.ServerId, OLD.DiscordServerId, TRUE, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `UserGameIdents` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `UserGameIdents` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `UserGameIdentsHistory` |  | ||||||
| ( |  | ||||||
|     `Id`           BIGINT(20)   NOT NULL, |  | ||||||
|     `UserId`       BIGINT(20)   NOT NULL, |  | ||||||
|     `GameServerId` BIGINT(20)   NOT NULL, |  | ||||||
|     `Ident`        VARCHAR(255) NOT NULL, |  | ||||||
|     `Deleted`      BOOL DEFAULT FALSE, |  | ||||||
|     `DateFrom`     DATETIME(6)  NOT NULL, |  | ||||||
|     `DateTo`       DATETIME(6)  NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UserGameIdentsUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UserGameIdentsUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `UserGameIdents` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UserGameIdentsHistory` (`Id`, `UserId`, `GameServerId`, `Ident`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.UserId, OLD.GameServerId, OLD.Ident, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UserGameIdentsDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UserGameIdentsDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `UserGameIdents` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UserGameIdentsHistory` (`Id`, `UserId`, `GameServerId`, `Ident`, `Deleted`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.UserId, OLD.GameServerId, OLD.Ident, TRUE, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `UserJoinedGameServer` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `UserJoinedGameServer` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `UserJoinedGameServerHistory` |  | ||||||
| ( |  | ||||||
|     `Id`           BIGINT(20)  NOT NULL, |  | ||||||
|     `UserId`       BIGINT(20)  NOT NULL, |  | ||||||
|     `GameServerId` BIGINT(20)  NOT NULL, |  | ||||||
|     `JoinedOn`     DATETIME(6) NOT NULL, |  | ||||||
|     `LeavedOn`     DATETIME(6) DEFAULT NULL, |  | ||||||
|     `Deleted`      BOOL        DEFAULT FALSE, |  | ||||||
|     `DateFrom`     DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`       DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UserJoinedGameServerUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UserJoinedGameServerUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `UserJoinedGameServer` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UserJoinedGameServerHistory` (`Id`, `UserId`, `GameServerId`, `JoinedOn`, `LeavedOn`, `DateFrom`, |  | ||||||
|                                                `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.UserId, OLD.GameServerId, OLD.JoinedOn, OLD.LeavedOn, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UserJoinedGameServerDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UserJoinedGameServerDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `UserJoinedGameServer` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UserJoinedGameServerHistory` (`Id`, `UserId`, `GameServerId`, `JoinedOn`, `LeavedOn`, `Deleted`, |  | ||||||
|                                                `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.UserId, OLD.GameServerId, OLD.JoinedOn, OLD.LeavedOn, TRUE, OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `UserJoinedServers` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `UserJoinedServers` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `UserJoinedServersHistory` |  | ||||||
| ( |  | ||||||
|     `Id`       BIGINT(20)  NOT NULL, |  | ||||||
|     `UserId`   BIGINT(20)  NOT NULL, |  | ||||||
|     `JoinedOn` DATETIME(6) NOT NULL, |  | ||||||
|     `LeavedOn` DATETIME(6) DEFAULT NULL, |  | ||||||
|     `Deleted`  BOOL        DEFAULT FALSE, |  | ||||||
|     `DateFrom` DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`   DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UserJoinedServersUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UserJoinedServersUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `UserJoinedServers` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UserJoinedServersHistory` (`Id`, `UserId`, `JoinedOn`, `LeavedOn`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.JoinId, OLD.UserId, OLD.JoinedOn, OLD.LeavedOn, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UserJoinedServersDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UserJoinedServersDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `UserJoinedServers` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UserJoinedServersHistory` (`Id`, `UserId`, `JoinedOn`, `LeavedOn`, `Deleted`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.JoinId, OLD.UserId, OLD.JoinedOn, OLD.LeavedOn, TRUE, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `UserJoinedVoiceChannel` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `UserJoinedVoiceChannel` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `UserJoinedVoiceChannelHistory` |  | ||||||
| ( |  | ||||||
|     `Id`               BIGINT(20)  NOT NULL, |  | ||||||
|     `UserId`           BIGINT(20)  NOT NULL, |  | ||||||
|     `DiscordChannelId` BIGINT(20)  NOT NULL, |  | ||||||
|     `JoinedOn`         DATETIME(6) NOT NULL, |  | ||||||
|     `LeavedOn`         DATETIME(6) DEFAULT NULL, |  | ||||||
|     `Deleted`          BOOL        DEFAULT FALSE, |  | ||||||
|     `DateFrom`         DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`           DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UserJoinedVoiceChannelUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UserJoinedVoiceChannelUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `UserJoinedVoiceChannel` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UserJoinedVoiceChannelHistory` (`Id`, `UserId`, `DiscordChannelId`, `JoinedOn`, `LeavedOn`, `DateFrom`, |  | ||||||
|                                                  `DateTo`) |  | ||||||
|     VALUES (OLD.JoinId, OLD.UserId, OLD.DiscordChannelId, OLD.JoinedOn, OLD.LeavedOn, OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UserJoinedVoiceChannelDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UserJoinedVoiceChannelDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `UserJoinedVoiceChannel` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UserJoinedVoiceChannelHistory` (`Id`, `UserId`, `DiscordChannelId`, `JoinedOn`, `LeavedOn`, `Deleted`, |  | ||||||
|                                                  `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.JoinId, OLD.UserId, OLD.DiscordChannelId, OLD.JoinedOn, OLD.LeavedOn, TRUE, OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `UserMessageCountPerHour` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `UserMessageCountPerHour` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `UserMessageCountPerHourHistory` |  | ||||||
| ( |  | ||||||
|     `Id`       BIGINT(20)  NOT NULL, |  | ||||||
|     `Date`     DATETIME(6) NOT NULL, |  | ||||||
|     `Hour`     BIGINT(20) DEFAULT NULL, |  | ||||||
|     `XPCount`  BIGINT(20) DEFAULT NULL, |  | ||||||
|     `UserId`   BIGINT(20) DEFAULT NULL, |  | ||||||
|     `Deleted`  BOOL       DEFAULT FALSE, |  | ||||||
|     `DateFrom` DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`   DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UserMessageCountPerHourUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UserMessageCountPerHourUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `UserMessageCountPerHour` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UserMessageCountPerHourHistory` (`Id`, `UserId`, `Date`, `Hour`, `XPCount`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.UserId, OLD.Date, OLD.Hour, OLD.XPCount, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UserMessageCountPerHourDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UserMessageCountPerHourDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `UserMessageCountPerHour` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UserMessageCountPerHourHistory` (`Id`, `UserId`, `Date`, `Hour`, `XPCount`, `Deleted`, `DateFrom`, |  | ||||||
|                                                   `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.UserId, OLD.Date, OLD.Hour, OLD.XPCount, TRUE, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `Users` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `Users` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `UsersHistory` |  | ||||||
| ( |  | ||||||
|     `Id`            BIGINT(20)  NOT NULL, |  | ||||||
|     `DiscordId`     BIGINT(20)  NOT NULL, |  | ||||||
|     `XP`            BIGINT(20)  NOT NULL DEFAULT 0, |  | ||||||
|     `ServerId`      BIGINT(20)           DEFAULT NULL, |  | ||||||
|     `Deleted`       BOOL                 DEFAULT FALSE, |  | ||||||
|     `DateFrom`      DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`        DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UsersUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UsersUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `Users` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UsersHistory` (`Id`, `DiscordId`, `XP`, `ServerId`, |  | ||||||
|                                 `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.UserId, OLD.DiscordId, OLD.XP, OLD.ServerId, |  | ||||||
|             OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UsersDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UsersDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `Users` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UsersHistory` (`Id`, `DiscordId`, `XP`, `ServerId`, |  | ||||||
|                                 `Deleted`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.UserId, OLD.DiscordId, OLD.XP, OLD.ServerId, TRUE, |  | ||||||
|             OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| ALTER TABLE `UserWarnings` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `UserWarnings` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `UserWarningsHistory` |  | ||||||
| ( |  | ||||||
|     `Id`          BIGINT(20)   NOT NULL, |  | ||||||
|     `Description` VARCHAR(255) NOT NULL, |  | ||||||
|     `UserId`      BIGINT(20)   NOT NULL, |  | ||||||
|     `Author`      BIGINT(20) DEFAULT NULL, |  | ||||||
|     `Deleted`     BOOL       DEFAULT FALSE, |  | ||||||
|     `DateFrom`    DATETIME(6)  NOT NULL, |  | ||||||
|     `DateTo`      DATETIME(6)  NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UserWarningsUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UserWarningsUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `UserWarnings` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UserWarningsHistory` (`Id`, `Description`, `UserId`, `Author`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.Description, OLD.UserId, OLD.Author, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UserWarningsDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UserWarningsDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `UserWarnings` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UserWarningsHistory` (`Id`, `Description`, `UserId`, `Author`, `Deleted`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.Description, OLD.UserId, OLD.Author, TRUE, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| DROP TABLE `UserGotAchievements`; |  | ||||||
|  |  | ||||||
| DROP TABLE `Achievements`; |  | ||||||
|  |  | ||||||
| ALTER TABLE Users DROP COLUMN MessageCount; |  | ||||||
|  |  | ||||||
| ALTER TABLE Users DROP COLUMN ReactionCount; |  | ||||||
|  |  | ||||||
| DROP TABLE `AchievementsHistory`; |  | ||||||
|  |  | ||||||
| @@ -1,88 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `Achievements` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT       NOT NULL AUTO_INCREMENT, |  | ||||||
|     `Name`           VARCHAR(255) NOT NULL, |  | ||||||
|     `Description`    VARCHAR(255) NOT NULL, |  | ||||||
|     `Attribute`      VARCHAR(255) NOT NULL, |  | ||||||
|     `Operator`       VARCHAR(255) NOT NULL, |  | ||||||
|     `Value`          VARCHAR(255) NOT NULL, |  | ||||||
|     `ServerId`       BIGINT, |  | ||||||
|     `CreatedAt`      DATETIME(6)  NULL DEFAULT CURRENT_TIMESTAMP(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6)  NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), |  | ||||||
|     PRIMARY KEY (`Id`), |  | ||||||
|     FOREIGN KEY (`ServerId`) REFERENCES `Servers` (`ServerId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `AchievementsHistory` |  | ||||||
| ( |  | ||||||
|     `Id`          BIGINT(20)   NOT NULL, |  | ||||||
|     `Name`        VARCHAR(255) NOT NULL, |  | ||||||
|     `Description` VARCHAR(255) NOT NULL, |  | ||||||
|     `Attribute`   VARCHAR(255) NOT NULL, |  | ||||||
|     `Operator`    VARCHAR(255) NOT NULL, |  | ||||||
|     `Value`       VARCHAR(255) NOT NULL, |  | ||||||
|     `ServerId`    BIGINT, |  | ||||||
|     `Deleted`     BOOL DEFAULT FALSE, |  | ||||||
|     `DateFrom`    DATETIME(6)  NOT NULL, |  | ||||||
|     `DateTo`      DATETIME(6)  NOT NULL |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `UserGotAchievements` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT      NOT NULL AUTO_INCREMENT, |  | ||||||
|     `UserId`         BIGINT, |  | ||||||
|     `AchievementId`  BIGINT, |  | ||||||
|     `CreatedAt`      DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), |  | ||||||
|     PRIMARY KEY (`Id`), |  | ||||||
|     FOREIGN KEY (`UserId`) REFERENCES `Users` (`UserId`), |  | ||||||
|     FOREIGN KEY (`AchievementId`) REFERENCES `Achievements` (`Id`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE Users |  | ||||||
|     ADD MessageCount BIGINT NOT NULL DEFAULT 0 AFTER XP; |  | ||||||
|  |  | ||||||
| ALTER TABLE Users |  | ||||||
|     ADD ReactionCount BIGINT NOT NULL DEFAULT 0 AFTER XP; |  | ||||||
|  |  | ||||||
| ALTER TABLE UsersHistory |  | ||||||
|     ADD MessageCount BIGINT NOT NULL DEFAULT 0 AFTER XP; |  | ||||||
|  |  | ||||||
| ALTER TABLE UsersHistory |  | ||||||
|     ADD ReactionCount BIGINT NOT NULL DEFAULT 0 AFTER XP; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_AchievementsUpdate`; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_AchievementsUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `Achievements` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `AchievementsHistory` (`Id`, `Name`, `Description`, `Attribute`, `Operator`, `Value`, `ServerId`, |  | ||||||
|                                        `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.Name, OLD.Description, OLD.Attribute, OLD.Operator, OLD.Value, OLD.ServerId, OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_AchievementsDelete`; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_AchievementsDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `Achievements` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `AchievementsHistory` (`Id`, `Name`, `Description`, `Attribute`, `Operator`, `Value`, `ServerId`, |  | ||||||
|                                        `Deleted`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.Name, OLD.Description, OLD.Attribute, OLD.Operator, OLD.Value, OLD.ServerId, TRUE, |  | ||||||
|             OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,24 +0,0 @@ | |||||||
| DROP TABLE `CFG_ServerTeamRoleIds`; |  | ||||||
|  |  | ||||||
| DROP TABLE `CFG_ServerTeamRoleIdsHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `CFG_ServerAFKChannelIds`; |  | ||||||
|  |  | ||||||
| DROP TABLE `CFG_ServerAFKChannelIdsHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `CFG_Server`; |  | ||||||
|  |  | ||||||
| DROP TABLE `CFG_ServerHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `CFG_TechnicianPingUrls`; |  | ||||||
|  |  | ||||||
| DROP TABLE `CFG_TechnicianPingUrlsHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `CFG_TechnicianIds`; |  | ||||||
|  |  | ||||||
| DROP TABLE `CFG_TechnicianIdsHistory`; |  | ||||||
|  |  | ||||||
| DROP TABLE `CFG_Technician`; |  | ||||||
|  |  | ||||||
| DROP TABLE `CFG_TechnicianHistory`; |  | ||||||
|  |  | ||||||
| @@ -1,452 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `CFG_Server` |  | ||||||
| ( |  | ||||||
|     `Id`                      BIGINT      NOT NULL AUTO_INCREMENT, |  | ||||||
|     `MessageDeleteTimer`      BIGINT      NOT NULL DEFAULT 6, |  | ||||||
|     `NotificationChatId`      BIGINT      NOT NULL, |  | ||||||
|     `MaxVoiceStateHours`      BIGINT      NOT NULL DEFAULT 6, |  | ||||||
|     `XpPerMessage`            BIGINT      NOT NULL DEFAULT 1, |  | ||||||
|     `XpPerReaction`           BIGINT      NOT NULL DEFAULT 1, |  | ||||||
|     `MaxMessageXpPerHour`     BIGINT      NOT NULL DEFAULT 20, |  | ||||||
|     `XpPerOntimeHour`         BIGINT      NOT NULL DEFAULT 10, |  | ||||||
|     `XpPerEventParticipation` BIGINT      NOT NULL DEFAULT 10, |  | ||||||
|     `XpPerAchievement`        BIGINT      NOT NULL DEFAULT 10, |  | ||||||
|     `AFKCommandChannelId`     BIGINT      NOT NULL, |  | ||||||
|     `HelpVoiceChannelId`      BIGINT      NOT NULL, |  | ||||||
|     `TeamChannelId`           BIGINT      NOT NULL, |  | ||||||
|     `LoginMessageChannelId`   BIGINT      NOT NULL, |  | ||||||
|     `ServerId`                BIGINT      NOT NULL, |  | ||||||
|     `CreatedAt`               DATETIME(6) NULL     DEFAULT CURRENT_TIMESTAMP(6), |  | ||||||
|     `LastModifiedAt`          DATETIME(6) NULL     DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), |  | ||||||
|     PRIMARY KEY (`Id`), |  | ||||||
|     FOREIGN KEY (`ServerId`) REFERENCES `Servers` (`ServerId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `CFG_ServerAFKChannelIds` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT      NOT NULL AUTO_INCREMENT, |  | ||||||
|     `ChannelId`      BIGINT      NOT NULL, |  | ||||||
|     `ServerId`       BIGINT      NOT NULL, |  | ||||||
|     `CreatedAt`      DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), |  | ||||||
|     PRIMARY KEY (`Id`), |  | ||||||
|     FOREIGN KEY (`ServerId`) REFERENCES `Servers` (`ServerId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `CFG_ServerTeamRoleIds` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT                      NOT NULL AUTO_INCREMENT, |  | ||||||
|     `RoleId`         BIGINT                      NOT NULL, |  | ||||||
|     `TeamMemberType` ENUM ('Moderator', 'Admin') NOT NULL, |  | ||||||
|     `ServerId`       BIGINT                      NOT NULL, |  | ||||||
|     `CreatedAt`      DATETIME(6)                 NULL DEFAULT CURRENT_TIMESTAMP(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6)                 NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), |  | ||||||
|     PRIMARY KEY (`Id`), |  | ||||||
|     FOREIGN KEY (`ServerId`) REFERENCES `Servers` (`ServerId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `CFG_Technician` |  | ||||||
| ( |  | ||||||
|     `Id`                      BIGINT       NOT NULL AUTO_INCREMENT, |  | ||||||
|     `HelpCommandReferenceUrl` VARCHAR(255) NOT NULL, |  | ||||||
|     `WaitForRestart`          BIGINT       NOT NULL DEFAULT 8, |  | ||||||
|     `WaitForShutdown`         BIGINT       NOT NULL DEFAULT 8, |  | ||||||
|     `CacheMaxMessages`        BIGINT       NOT NULL DEFAULT 1000000, |  | ||||||
|     `CreatedAt`               DATETIME(6)  NULL     DEFAULT CURRENT_TIMESTAMP(6), |  | ||||||
|     `LastModifiedAt`          DATETIME(6)  NULL     DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), |  | ||||||
|     PRIMARY KEY (`Id`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `CFG_TechnicianPingUrls` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT       NOT NULL AUTO_INCREMENT, |  | ||||||
|     `URL`            VARCHAR(255) NOT NULL, |  | ||||||
|     `CreatedAt`      DATETIME(6)  NULL DEFAULT CURRENT_TIMESTAMP(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6)  NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), |  | ||||||
|     PRIMARY KEY (`Id`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `CFG_TechnicianIds` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT      NOT NULL AUTO_INCREMENT, |  | ||||||
|     `TechnicianId`   BIGINT      NOT NULL, |  | ||||||
|     `CreatedAt`      DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), |  | ||||||
|     PRIMARY KEY (`Id`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `CFG_ServerHistory` |  | ||||||
| ( |  | ||||||
|     `Id`                          BIGINT(20)  NOT NULL, |  | ||||||
|     `MessageDeleteTimer`          BIGINT      NOT NULL DEFAULT 6, |  | ||||||
|     `NotificationChatId`          BIGINT      NOT NULL, |  | ||||||
|     `MaxVoiceStateHours`          BIGINT      NOT NULL DEFAULT 6, |  | ||||||
|     `XpPerMessage`                BIGINT      NOT NULL DEFAULT 1, |  | ||||||
|     `XpPerReaction`               BIGINT      NOT NULL DEFAULT 1, |  | ||||||
|     `MaxMessageXpPerHour`         BIGINT      NOT NULL DEFAULT 20, |  | ||||||
|     `XpPerOntimeHour`             BIGINT      NOT NULL DEFAULT 10, |  | ||||||
|     `XpPerEventParticipation`     BIGINT      NOT NULL DEFAULT 10, |  | ||||||
|     `XpPerAchievement`            BIGINT      NOT NULL DEFAULT 10, |  | ||||||
|     `AFKCommandChannelId`         BIGINT      NOT NULL, |  | ||||||
|     `HelpVoiceChannelId`          BIGINT      NOT NULL, |  | ||||||
|     `TeamChannelId`               BIGINT      NOT NULL, |  | ||||||
|     `LoginMessageChannelId`       BIGINT      NOT NULL, |  | ||||||
|     `ServerId`                    BIGINT      NOT NULL, |  | ||||||
|     `Deleted`                     BOOL                 DEFAULT FALSE, |  | ||||||
|     `DateFrom`                    DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`                      DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_ServerUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_ServerUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `CFG_Server` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_ServerHistory` (`Id`, |  | ||||||
|                                      `MessageDeleteTimer`, |  | ||||||
|                                      `NotificationChatId`, |  | ||||||
|                                      `MaxVoiceStateHours`, |  | ||||||
|                                      `XpPerMessage`, |  | ||||||
|                                      `XpPerReaction`, |  | ||||||
|                                      `MaxMessageXpPerHour`, |  | ||||||
|                                      `XpPerOntimeHour`, |  | ||||||
|                                      `XpPerEventParticipation`, |  | ||||||
|                                      `XpPerAchievement`, |  | ||||||
|                                      `AFKCommandChannelId`, |  | ||||||
|                                      `HelpVoiceChannelId`, |  | ||||||
|                                      `TeamChannelId`, |  | ||||||
|                                      `LoginMessageChannelId`, |  | ||||||
|                                      `ServerId`, |  | ||||||
|                                      `DateFrom`, |  | ||||||
|                                      `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.MessageDeleteTimer, |  | ||||||
|             OLD.NotificationChatId, |  | ||||||
|             OLD.MaxVoiceStateHours, |  | ||||||
|             OLD.XpPerMessage, |  | ||||||
|             OLD.XpPerReaction, |  | ||||||
|             OLD.MaxMessageXpPerHour, |  | ||||||
|             OLD.XpPerOntimeHour, |  | ||||||
|             OLD.XpPerEventParticipation, |  | ||||||
|             OLD.XpPerAchievement, |  | ||||||
|             OLD.AFKCommandChannelId, |  | ||||||
|             OLD.HelpVoiceChannelId, |  | ||||||
|             OLD.TeamChannelId, |  | ||||||
|             OLD.LoginMessageChannelId, |  | ||||||
|             OLD.ServerId, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_ServerDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_ServerDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `CFG_Server` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_ServerHistory` (`Id`, |  | ||||||
|                                      `MessageDeleteTimer`, |  | ||||||
|                                      `NotificationChatId`, |  | ||||||
|                                      `MaxVoiceStateHours`, |  | ||||||
|                                      `XpPerMessage`, |  | ||||||
|                                      `XpPerReaction`, |  | ||||||
|                                      `MaxMessageXpPerHour`, |  | ||||||
|                                      `XpPerOntimeHour`, |  | ||||||
|                                      `XpPerEventParticipation`, |  | ||||||
|                                      `XpPerAchievement`, |  | ||||||
|                                      `AFKCommandChannelId`, |  | ||||||
|                                      `HelpVoiceChannelId`, |  | ||||||
|                                      `TeamChannelId`, |  | ||||||
|                                      `LoginMessageChannelId`, |  | ||||||
|                                      `ServerId`, |  | ||||||
|                                      `Deleted`, |  | ||||||
|                                      `DateFrom`, |  | ||||||
|                                      `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.MessageDeleteTimer, |  | ||||||
|             OLD.NotificationChatId, |  | ||||||
|             OLD.MaxVoiceStateHours, |  | ||||||
|             OLD.XpPerMessage, |  | ||||||
|             OLD.XpPerReaction, |  | ||||||
|             OLD.MaxMessageXpPerHour, |  | ||||||
|             OLD.XpPerOntimeHour, |  | ||||||
|             OLD.XpPerEventParticipation, |  | ||||||
|             OLD.XpPerAchievement, |  | ||||||
|             OLD.AFKCommandChannelId, |  | ||||||
|             OLD.HelpVoiceChannelId, |  | ||||||
|             OLD.TeamChannelId, |  | ||||||
|             OLD.LoginMessageChannelId, |  | ||||||
|             OLD.ServerId, |  | ||||||
|             TRUE, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `CFG_ServerAFKChannelIdsHistory` |  | ||||||
| ( |  | ||||||
|     `Id`        BIGINT(20)  NOT NULL, |  | ||||||
|     `ChannelId` BIGINT      NOT NULL, |  | ||||||
|     `ServerId`  BIGINT      NOT NULL, |  | ||||||
|     `Deleted`   BOOL DEFAULT FALSE, |  | ||||||
|     `DateFrom`  DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`    DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_ServerAFKChannelIdsUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_ServerAFKChannelIdsUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `CFG_ServerAFKChannelIds` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_ServerAFKChannelIdsHistory` (`Id`, |  | ||||||
|                                                   `ChannelId`, |  | ||||||
|                                                   `ServerId`, |  | ||||||
|                                                   `DateFrom`, |  | ||||||
|                                                   `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.ChannelId, |  | ||||||
|             OLD.ServerId, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_ServerAFKChannelIdsDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_ServerAFKChannelIdsDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `CFG_ServerAFKChannelIds` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_ServerAFKChannelIdsHistory` (`Id`, |  | ||||||
|                                                   `ChannelId`, |  | ||||||
|                                                   `ServerId`, |  | ||||||
|                                                   `Deleted`, |  | ||||||
|                                                   `DateFrom`, |  | ||||||
|                                                   `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.ChannelId, |  | ||||||
|             OLD.ServerId, |  | ||||||
|             TRUE, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `CFG_ServerTeamRoleIdsHistory` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT(20)                  NOT NULL, |  | ||||||
|     `RoleId`         BIGINT                      NOT NULL, |  | ||||||
|     `TeamMemberType` ENUM ('Moderator', 'Admin') NOT NULL, |  | ||||||
|     `ServerId`       BIGINT                      NOT NULL, |  | ||||||
|     `Deleted`        BOOL DEFAULT FALSE, |  | ||||||
|     `DateFrom`       DATETIME(6)                 NOT NULL, |  | ||||||
|     `DateTo`         DATETIME(6)                 NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_ServerTeamRoleIdsUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_ServerTeamRoleIdsUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `CFG_ServerTeamRoleIds` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_ServerTeamRoleIdsHistory` (`Id`, |  | ||||||
|                                                 `RoleId`, |  | ||||||
|                                                 `TeamMemberType`, |  | ||||||
|                                                 `ServerId`, |  | ||||||
|                                                 `DateFrom`, |  | ||||||
|                                                 `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.RoleId, |  | ||||||
|             OLD.TeamMemberType, |  | ||||||
|             OLD.ServerId, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_ServerTeamRoleIdsDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_ServerTeamRoleIdsDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `CFG_ServerTeamRoleIds` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_ServerTeamRoleIdsHistory` (`Id`, |  | ||||||
|                                                 `RoleId`, |  | ||||||
|                                                 `TeamMemberType`, |  | ||||||
|                                                 `ServerId`, |  | ||||||
|                                                 `Deleted`, |  | ||||||
|                                                 `DateFrom`, |  | ||||||
|                                                 `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.RoleId, |  | ||||||
|             OLD.TeamMemberType, |  | ||||||
|             OLD.ServerId, |  | ||||||
|             TRUE, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `CFG_TechnicianHistory` |  | ||||||
| ( |  | ||||||
|     `Id`                      BIGINT(20)   NOT NULL, |  | ||||||
|     `HelpCommandReferenceUrl` VARCHAR(255) NOT NULL, |  | ||||||
|     `WaitForRestart`          BIGINT       NOT NULL DEFAULT 8, |  | ||||||
|     `WaitForShutdown`         BIGINT       NOT NULL DEFAULT 8, |  | ||||||
|     `CacheMaxMessages`        BIGINT       NOT NULL DEFAULT 1000000, |  | ||||||
|     `Deleted`                 BOOL                  DEFAULT FALSE, |  | ||||||
|     `DateFrom`                DATETIME(6)  NOT NULL, |  | ||||||
|     `DateTo`                  DATETIME(6)  NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_TechnicianUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_TechnicianUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `CFG_Technician` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_TechnicianHistory` (`Id`, |  | ||||||
|                                          `HelpCommandReferenceUrl`, |  | ||||||
|                                          `WaitForRestart`, |  | ||||||
|                                          `WaitForShutdown`, |  | ||||||
|                                          `CacheMaxMessages`, |  | ||||||
|                                          `DateFrom`, |  | ||||||
|                                          `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.HelpCommandReferenceUrl, |  | ||||||
|             OLD.WaitForRestart, |  | ||||||
|             OLD.WaitForShutdown, |  | ||||||
|             OLD.CacheMaxMessages, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_TechnicianDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_TechnicianDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `CFG_Technician` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_TechnicianHistory` (`Id`, |  | ||||||
|                                          `HelpCommandReferenceUrl`, |  | ||||||
|                                          `WaitForRestart`, |  | ||||||
|                                          `WaitForShutdown`, |  | ||||||
|                                          `CacheMaxMessages`, |  | ||||||
|                                          `Deleted`, |  | ||||||
|                                          `DateFrom`, |  | ||||||
|                                          `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.HelpCommandReferenceUrl, |  | ||||||
|             OLD.WaitForRestart, |  | ||||||
|             OLD.WaitForShutdown, |  | ||||||
|             OLD.CacheMaxMessages, |  | ||||||
|             TRUE, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `CFG_TechnicianIdsHistory` |  | ||||||
| ( |  | ||||||
|     `Id`           BIGINT(20)  NOT NULL, |  | ||||||
|     `TechnicianId` BIGINT      NOT NULL, |  | ||||||
|     `Deleted`      BOOL DEFAULT FALSE, |  | ||||||
|     `DateFrom`     DATETIME(6) NOT NULL, |  | ||||||
|     `DateTo`       DATETIME(6) NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_TechnicianIdsUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_TechnicianIdsUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `CFG_TechnicianIds` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_TechnicianIdsHistory` (`Id`, |  | ||||||
|                                             `TechnicianId`, |  | ||||||
|                                             `DateFrom`, |  | ||||||
|                                             `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.TechnicianId, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_TechnicianIdsDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_TechnicianIdsDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `CFG_TechnicianIds` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_TechnicianIdsHistory` (`Id`, |  | ||||||
|                                             `TechnicianId`, |  | ||||||
|                                             `Deleted`, |  | ||||||
|                                             `DateFrom`, |  | ||||||
|                                             `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.TechnicianId, |  | ||||||
|             TRUE, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `CFG_TechnicianPingUrlsHistory` |  | ||||||
| ( |  | ||||||
|     `Id`       BIGINT(20)   NOT NULL, |  | ||||||
|     `URL`      VARCHAR(255) NOT NULL, |  | ||||||
|     `Deleted`  BOOL DEFAULT FALSE, |  | ||||||
|     `DateFrom` DATETIME(6)  NOT NULL, |  | ||||||
|     `DateTo`   DATETIME(6)  NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_TechnicianPingUrlsUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_TechnicianPingUrlsUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `CFG_TechnicianPingUrls` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_TechnicianPingUrlsHistory` (`Id`, |  | ||||||
|                                                  `URL`, |  | ||||||
|                                                  `DateFrom`, |  | ||||||
|                                                  `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.URL, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_TechnicianPingUrlsDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_TechnicianPingUrlsDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `CFG_TechnicianPingUrls` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_TechnicianPingUrlsHistory` (`Id`, |  | ||||||
|                                                  `URL`, |  | ||||||
|                                                  `Deleted`, |  | ||||||
|                                                  `DateFrom`, |  | ||||||
|                                                  `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.URL, |  | ||||||
|             TRUE, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| ALTER TABLE CFG_Technician DROP COLUMN FeatureFlags; |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_Server DROP COLUMN FeatureFlags; |  | ||||||
|  |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| ALTER TABLE CFG_Technician |  | ||||||
|     ADD FeatureFlags JSON NULL DEFAULT ('{}') AFTER CacheMaxMessages; |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_Server |  | ||||||
|     ADD FeatureFlags JSON NULL DEFAULT ('{}') AFTER LoginMessageChannelId; |  | ||||||
|  |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| ALTER TABLE CFG_Server |  | ||||||
|     DROP COLUMN DefaultRoleId; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| ALTER TABLE CFG_Server |  | ||||||
|     ADD DefaultRoleId BIGINT NULL AFTER LoginMessageChannelId; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| DROP TABLE `ShortRoleNames`; |  | ||||||
|  |  | ||||||
| DROP TABLE `ShortRoleNamesHistory`; |  | ||||||
|  |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| ALTER TABLE CFG_ServerHistory |  | ||||||
|     DROP COLUMN DefaultRoleId; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_TechnicianHistory |  | ||||||
|     DROP COLUMN FeatureFlags; |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_ServerHistory |  | ||||||
|     DROP COLUMN FeatureFlags; |  | ||||||
|  |  | ||||||
| @@ -1,171 +0,0 @@ | |||||||
| ALTER TABLE CFG_ServerHistory |  | ||||||
|     ADD DefaultRoleId BIGINT NULL AFTER LoginMessageChannelId; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_TechnicianHistory |  | ||||||
|     ADD FeatureFlags JSON NULL DEFAULT ('{}') AFTER CacheMaxMessages; |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_ServerHistory |  | ||||||
|     ADD FeatureFlags JSON NULL DEFAULT ('{}') AFTER LoginMessageChannelId; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_ServerUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_ServerUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `CFG_Server` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_ServerHistory` (`Id`, |  | ||||||
|                                      `MessageDeleteTimer`, |  | ||||||
|                                      `NotificationChatId`, |  | ||||||
|                                      `MaxVoiceStateHours`, |  | ||||||
|                                      `XpPerMessage`, |  | ||||||
|                                      `XpPerReaction`, |  | ||||||
|                                      `MaxMessageXpPerHour`, |  | ||||||
|                                      `XpPerOntimeHour`, |  | ||||||
|                                      `XpPerEventParticipation`, |  | ||||||
|                                      `XpPerAchievement`, |  | ||||||
|                                      `AFKCommandChannelId`, |  | ||||||
|                                      `HelpVoiceChannelId`, |  | ||||||
|                                      `TeamChannelId`, |  | ||||||
|                                      `LoginMessageChannelId`, |  | ||||||
|                                      `DefaultRoleId`, |  | ||||||
|                                      `FeatureFlags`, |  | ||||||
|                                      `ServerId`, |  | ||||||
|                                      `DateFrom`, |  | ||||||
|                                      `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.MessageDeleteTimer, |  | ||||||
|             OLD.NotificationChatId, |  | ||||||
|             OLD.MaxVoiceStateHours, |  | ||||||
|             OLD.XpPerMessage, |  | ||||||
|             OLD.XpPerReaction, |  | ||||||
|             OLD.MaxMessageXpPerHour, |  | ||||||
|             OLD.XpPerOntimeHour, |  | ||||||
|             OLD.XpPerEventParticipation, |  | ||||||
|             OLD.XpPerAchievement, |  | ||||||
|             OLD.AFKCommandChannelId, |  | ||||||
|             OLD.HelpVoiceChannelId, |  | ||||||
|             OLD.TeamChannelId, |  | ||||||
|             OLD.LoginMessageChannelId, |  | ||||||
|             OLD.DefaultRoleId, |  | ||||||
|             OLD.FeatureFlags, |  | ||||||
|             OLD.ServerId, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_ServerDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_ServerDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `CFG_Server` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_ServerHistory` (`Id`, |  | ||||||
|                                      `MessageDeleteTimer`, |  | ||||||
|                                      `NotificationChatId`, |  | ||||||
|                                      `MaxVoiceStateHours`, |  | ||||||
|                                      `XpPerMessage`, |  | ||||||
|                                      `XpPerReaction`, |  | ||||||
|                                      `MaxMessageXpPerHour`, |  | ||||||
|                                      `XpPerOntimeHour`, |  | ||||||
|                                      `XpPerEventParticipation`, |  | ||||||
|                                      `XpPerAchievement`, |  | ||||||
|                                      `AFKCommandChannelId`, |  | ||||||
|                                      `HelpVoiceChannelId`, |  | ||||||
|                                      `TeamChannelId`, |  | ||||||
|                                      `LoginMessageChannelId`, |  | ||||||
|                                      `DefaultRoleId`, |  | ||||||
|                                      `ServerId`, |  | ||||||
|                                      `FeatureFlags`, |  | ||||||
|                                      `Deleted`, |  | ||||||
|                                      `DateFrom`, |  | ||||||
|                                      `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.MessageDeleteTimer, |  | ||||||
|             OLD.NotificationChatId, |  | ||||||
|             OLD.MaxVoiceStateHours, |  | ||||||
|             OLD.XpPerMessage, |  | ||||||
|             OLD.XpPerReaction, |  | ||||||
|             OLD.MaxMessageXpPerHour, |  | ||||||
|             OLD.XpPerOntimeHour, |  | ||||||
|             OLD.XpPerEventParticipation, |  | ||||||
|             OLD.XpPerAchievement, |  | ||||||
|             OLD.AFKCommandChannelId, |  | ||||||
|             OLD.HelpVoiceChannelId, |  | ||||||
|             OLD.TeamChannelId, |  | ||||||
|             OLD.LoginMessageChannelId, |  | ||||||
|             OLD.DefaultRoleId, |  | ||||||
|             OLD.FeatureFlags, |  | ||||||
|             OLD.ServerId, |  | ||||||
|             TRUE, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `CFG_TechnicianHistory` |  | ||||||
| ( |  | ||||||
|     `Id`                      BIGINT(20)   NOT NULL, |  | ||||||
|     `HelpCommandReferenceUrl` VARCHAR(255) NOT NULL, |  | ||||||
|     `WaitForRestart`          BIGINT       NOT NULL DEFAULT 8, |  | ||||||
|     `WaitForShutdown`         BIGINT       NOT NULL DEFAULT 8, |  | ||||||
|     `CacheMaxMessages`        BIGINT       NOT NULL DEFAULT 1000000, |  | ||||||
|     `FeatureFlags`            JSON         NULL     DEFAULT ('{}'), |  | ||||||
|     `Deleted`                 BOOL                  DEFAULT FALSE, |  | ||||||
|     `DateFrom`                DATETIME(6)  NOT NULL, |  | ||||||
|     `DateTo`                  DATETIME(6)  NOT NULL |  | ||||||
| );; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_TechnicianUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_TechnicianUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `CFG_Technician` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_TechnicianHistory` (`Id`, |  | ||||||
|                                          `HelpCommandReferenceUrl`, |  | ||||||
|                                          `WaitForRestart`, |  | ||||||
|                                          `WaitForShutdown`, |  | ||||||
|                                          `CacheMaxMessages`, |  | ||||||
|                                          `FeatureFlags`, |  | ||||||
|                                          `DateFrom`, |  | ||||||
|                                          `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.HelpCommandReferenceUrl, |  | ||||||
|             OLD.WaitForRestart, |  | ||||||
|             OLD.WaitForShutdown, |  | ||||||
|             OLD.CacheMaxMessages, |  | ||||||
|             OLD.FeatureFlags, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_TechnicianDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_TechnicianDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `CFG_Technician` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_TechnicianHistory` (`Id`, |  | ||||||
|                                          `HelpCommandReferenceUrl`, |  | ||||||
|                                          `WaitForRestart`, |  | ||||||
|                                          `WaitForShutdown`, |  | ||||||
|                                          `CacheMaxMessages`, |  | ||||||
|                                          `FeatureFlags`, |  | ||||||
|                                          `Deleted`, |  | ||||||
|                                          `DateFrom`, |  | ||||||
|                                          `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.HelpCommandReferenceUrl, |  | ||||||
|             OLD.WaitForRestart, |  | ||||||
|             OLD.WaitForShutdown, |  | ||||||
|             OLD.CacheMaxMessages, |  | ||||||
|             OLD.FeatureFlags, |  | ||||||
|             TRUE, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| ALTER TABLE CFG_Server |  | ||||||
|     DROP COLUMN ShortRoleNameSetOnlyHighest; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_ServerHistory |  | ||||||
|     DROP COLUMN ShortRoleNameSetOnlyHighest; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| ALTER TABLE UsersHistory |  | ||||||
|     DROP COLUMN MessageCount; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE UsersHistory |  | ||||||
|     DROP COLUMN ReactionCount; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| ALTER TABLE `Users` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `Users` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UsersUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UsersUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `Users` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UsersHistory` (`Id`, `DiscordId`, `XP`, `ReactionCount`, `MessageCount`, `ServerId`, |  | ||||||
|                                 `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.UserId, OLD.DiscordId, OLD.XP, OLD.ReactionCount, OLD.MessageCount, OLD.ServerId, |  | ||||||
|             OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UsersDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UsersDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `Users` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UsersHistory` (`Id`, `DiscordId`, `XP`, `ReactionCount`, `MessageCount`, `ServerId`, |  | ||||||
|                                 `Deleted`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.UserId, OLD.DiscordId, OLD.XP, OLD.ReactionCount, OLD.MessageCount, OLD.ServerId, TRUE, |  | ||||||
|             OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| @@ -1,19 +0,0 @@ | |||||||
| ALTER TABLE Users |  | ||||||
|     DROP COLUMN Birthday; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE UsersHistory |  | ||||||
|     DROP COLUMN Birthday; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_Server |  | ||||||
|     DROP COLUMN XpForBirthday; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_ServerHistory |  | ||||||
|     DROP COLUMN XpForBirthday; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,150 +0,0 @@ | |||||||
| ALTER TABLE Users |  | ||||||
|     ADD Birthday DATE NULL AFTER MessageCount; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE UsersHistory |  | ||||||
|     ADD Birthday DATE NULL AFTER MessageCount; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE `Users` |  | ||||||
|     CHANGE `CreatedAt` `CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| ALTER TABLE `Users` |  | ||||||
|     CHANGE `LastModifiedAt` `LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UsersUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UsersUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `Users` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UsersHistory` (`Id`, `DiscordId`, `XP`, `ReactionCount`, `MessageCount`, `Birthday`, `ServerId`, |  | ||||||
|                                 `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.UserId, OLD.DiscordId, OLD.XP, OLD.ReactionCount, OLD.MessageCount, OLD.Birthday, OLD.ServerId, |  | ||||||
|             OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_UsersDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_UsersDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `Users` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `UsersHistory` (`Id`, `DiscordId`, `XP`, `ReactionCount`, `MessageCount`, `Birthday`, `ServerId`, |  | ||||||
|                                 `Deleted`, `DateFrom`, `DateTo`) |  | ||||||
|     VALUES (OLD.UserId, OLD.DiscordId, OLD.XP, OLD.ReactionCount, OLD.MessageCount, OLD.Birthday, OLD.ServerId, TRUE, |  | ||||||
|             OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_Server |  | ||||||
|     ADD XpForBirthday BIGINT(20) NOT NULL DEFAULT 0 AFTER XpPerAchievement; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_ServerHistory |  | ||||||
|     ADD XpForBirthday BIGINT(20) NOT NULL DEFAULT 0 AFTER XpPerAchievement; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_ServerUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_ServerUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `CFG_Server` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_ServerHistory` (`Id`, |  | ||||||
|                                      `MessageDeleteTimer`, |  | ||||||
|                                      `NotificationChatId`, |  | ||||||
|                                      `MaxVoiceStateHours`, |  | ||||||
|                                      `XpPerMessage`, |  | ||||||
|                                      `XpPerReaction`, |  | ||||||
|                                      `MaxMessageXpPerHour`, |  | ||||||
|                                      `XpPerOntimeHour`, |  | ||||||
|                                      `XpPerEventParticipation`, |  | ||||||
|                                      `XpPerAchievement`, |  | ||||||
|                                      `AFKCommandChannelId`, |  | ||||||
|                                      `HelpVoiceChannelId`, |  | ||||||
|                                      `TeamChannelId`, |  | ||||||
|                                      `LoginMessageChannelId`, |  | ||||||
|                                      `DefaultRoleId`, |  | ||||||
|                                      `ShortRoleNameSetOnlyHighest`, |  | ||||||
|                                      `FeatureFlags`, |  | ||||||
|                                      `ServerId`, |  | ||||||
|                                      `DateFrom`, |  | ||||||
|                                      `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.MessageDeleteTimer, |  | ||||||
|             OLD.NotificationChatId, |  | ||||||
|             OLD.MaxVoiceStateHours, |  | ||||||
|             OLD.XpPerMessage, |  | ||||||
|             OLD.XpPerReaction, |  | ||||||
|             OLD.MaxMessageXpPerHour, |  | ||||||
|             OLD.XpPerOntimeHour, |  | ||||||
|             OLD.XpPerEventParticipation, |  | ||||||
|             OLD.XpPerAchievement, |  | ||||||
|             OLD.AFKCommandChannelId, |  | ||||||
|             OLD.HelpVoiceChannelId, |  | ||||||
|             OLD.TeamChannelId, |  | ||||||
|             OLD.LoginMessageChannelId, |  | ||||||
|             OLD.DefaultRoleId, |  | ||||||
|             OLD.ShortRoleNameSetOnlyHighest, |  | ||||||
|             OLD.FeatureFlags, |  | ||||||
|             OLD.ServerId, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_ServerDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_ServerDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `CFG_Server` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_ServerHistory` (`Id`, |  | ||||||
|                                      `MessageDeleteTimer`, |  | ||||||
|                                      `NotificationChatId`, |  | ||||||
|                                      `MaxVoiceStateHours`, |  | ||||||
|                                      `XpPerMessage`, |  | ||||||
|                                      `XpPerReaction`, |  | ||||||
|                                      `MaxMessageXpPerHour`, |  | ||||||
|                                      `XpPerOntimeHour`, |  | ||||||
|                                      `XpPerEventParticipation`, |  | ||||||
|                                      `XpPerAchievement`, |  | ||||||
|                                      `AFKCommandChannelId`, |  | ||||||
|                                      `HelpVoiceChannelId`, |  | ||||||
|                                      `TeamChannelId`, |  | ||||||
|                                      `LoginMessageChannelId`, |  | ||||||
|                                      `DefaultRoleId`, |  | ||||||
|                                      `ShortRoleNameSetOnlyHighest`, |  | ||||||
|                                      `ServerId`, |  | ||||||
|                                      `FeatureFlags`, |  | ||||||
|                                      `Deleted`, |  | ||||||
|                                      `DateFrom`, |  | ||||||
|                                      `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.MessageDeleteTimer, |  | ||||||
|             OLD.NotificationChatId, |  | ||||||
|             OLD.MaxVoiceStateHours, |  | ||||||
|             OLD.XpPerMessage, |  | ||||||
|             OLD.XpPerReaction, |  | ||||||
|             OLD.MaxMessageXpPerHour, |  | ||||||
|             OLD.XpPerOntimeHour, |  | ||||||
|             OLD.XpPerEventParticipation, |  | ||||||
|             OLD.XpPerAchievement, |  | ||||||
|             OLD.AFKCommandChannelId, |  | ||||||
|             OLD.HelpVoiceChannelId, |  | ||||||
|             OLD.TeamChannelId, |  | ||||||
|             OLD.LoginMessageChannelId, |  | ||||||
|             OLD.DefaultRoleId, |  | ||||||
|             OLD.ShortRoleNameSetOnlyHighest, |  | ||||||
|             OLD.FeatureFlags, |  | ||||||
|             OLD.ServerId, |  | ||||||
|             TRUE, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| @@ -1,11 +0,0 @@ | |||||||
| DROP TABLE `SteamSpecialOffers`; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_Server |  | ||||||
|     DROP COLUMN GameOfferNotificationChatId; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_ServerHistory |  | ||||||
|     DROP COLUMN GameOfferNotificationChatId; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `SteamSpecialOffers` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT       NOT NULL AUTO_INCREMENT, |  | ||||||
|     `Game`           VARCHAR(255) NOT NULL, |  | ||||||
|     `OriginalPrice`  FLOAT        NOT NULL, |  | ||||||
|     `DiscountPrice`  FLOAT        NOT NULL, |  | ||||||
|     `DiscountPct`    BIGINT       NOT NULL, |  | ||||||
|     `CreatedAt`      DATETIME(6)  NULL DEFAULT CURRENT_TIMESTAMP(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6)  NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), |  | ||||||
|     PRIMARY KEY (`Id`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_Server |  | ||||||
|     ADD COLUMN GameOfferNotificationChatId BIGINT NULL AFTER ShortRoleNameSetOnlyHighest; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_ServerHistory |  | ||||||
|     ADD COLUMN GameOfferNotificationChatId BIGINT NULL AFTER ShortRoleNameSetOnlyHighest; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| ALTER TABLE CFG_Technician |  | ||||||
|     DROP COLUMN MaxSteamOfferCount; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_TechnicianHistory |  | ||||||
|     DROP COLUMN MaxSteamOfferCount; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| ALTER TABLE CFG_Technician |  | ||||||
|     DROP COLUMN Maintenance; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_TechnicianHistory |  | ||||||
|     DROP COLUMN Maintenance; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,66 +0,0 @@ | |||||||
| ALTER TABLE CFG_Technician |  | ||||||
|     ADD Maintenance BOOLEAN DEFAULT FALSE AFTER MaxSteamOfferCount; |  | ||||||
|  |  | ||||||
| ALTER TABLE CFG_TechnicianHistory |  | ||||||
|     ADD Maintenance BOOLEAN DEFAULT FALSE AFTER MaxSteamOfferCount; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_TechnicianUpdate`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_TechnicianUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `CFG_Technician` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_TechnicianHistory` (`Id`, |  | ||||||
|                                          `HelpCommandReferenceUrl`, |  | ||||||
|                                          `WaitForRestart`, |  | ||||||
|                                          `WaitForShutdown`, |  | ||||||
|                                          `CacheMaxMessages`, |  | ||||||
|                                          `MaxSteamOfferCount`, |  | ||||||
|                                          `Maintenance`, |  | ||||||
|                                          `FeatureFlags`, |  | ||||||
|                                          `DateFrom`, |  | ||||||
|                                          `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.HelpCommandReferenceUrl, |  | ||||||
|             OLD.WaitForRestart, |  | ||||||
|             OLD.WaitForShutdown, |  | ||||||
|             OLD.CacheMaxMessages, |  | ||||||
|             OLD.MaxSteamOfferCount, |  | ||||||
|             OLD.Maintenance, |  | ||||||
|             OLD.FeatureFlags, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_CFG_TechnicianDelete`;; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_CFG_TechnicianDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `CFG_Technician` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `CFG_TechnicianHistory` (`Id`, |  | ||||||
|                                          `HelpCommandReferenceUrl`, |  | ||||||
|                                          `WaitForRestart`, |  | ||||||
|                                          `WaitForShutdown`, |  | ||||||
|                                          `CacheMaxMessages`, |  | ||||||
|                                          `MaxSteamOfferCount`, |  | ||||||
|                                          `Maintenance`, |  | ||||||
|                                          `FeatureFlags`, |  | ||||||
|                                          `Deleted`, |  | ||||||
|                                          `DateFrom`, |  | ||||||
|                                          `DateTo`) |  | ||||||
|     VALUES (OLD.Id, |  | ||||||
|             OLD.HelpCommandReferenceUrl, |  | ||||||
|             OLD.WaitForRestart, |  | ||||||
|             OLD.WaitForShutdown, |  | ||||||
|             OLD.CacheMaxMessages, |  | ||||||
|             OLD.MaxSteamOfferCount, |  | ||||||
|             OLD.Maintenance, |  | ||||||
|             OLD.FeatureFlags, |  | ||||||
|             TRUE, |  | ||||||
|             OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END;; |  | ||||||
|  |  | ||||||
| @@ -1,3 +0,0 @@ | |||||||
| DROP TABLE `ShortRoleNames`; |  | ||||||
|  |  | ||||||
| DROP TABLE `ShortRoleNamesHistory`; |  | ||||||
| @@ -1,83 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS `ScheduledEvents` |  | ||||||
| ( |  | ||||||
|     `Id`             BIGINT             NOT NULL AUTO_INCREMENT, |  | ||||||
|     `Interval`    ENUM ('daily', 'weekly', 'monthly', 'yearly') NOT NULL, |  | ||||||
|     `Name`           VARCHAR(255)       NOT NULL, |  | ||||||
|     `Description` VARCHAR(255)                                  NULL, |  | ||||||
|     `ChannelId`      BIGINT             NULL, |  | ||||||
|     `StartTime`      DATETIME(6)        NOT NULL, |  | ||||||
|     `EndTime`        DATETIME(6)        NULL, |  | ||||||
|     `EntityType`     ENUM ('1','2','3') NOT NULL, |  | ||||||
|     `Location`       VARCHAR(255)       NULL, |  | ||||||
|     `ServerId`       BIGINT, |  | ||||||
|     `CreatedAt`      DATETIME(6)        NULL DEFAULT CURRENT_TIMESTAMP(6), |  | ||||||
|     `LastModifiedAt` DATETIME(6)        NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), |  | ||||||
|     PRIMARY KEY (`Id`), |  | ||||||
|     FOREIGN KEY (`ServerId`) REFERENCES `Servers` (`ServerId`) |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `ScheduledEventsHistory` |  | ||||||
| ( |  | ||||||
|     `Id`          BIGINT(20)         NOT NULL, |  | ||||||
|     `Interval`    ENUM ('daily', 'weekly', 'monthly', 'yearly') NOT NULL, |  | ||||||
|     `Name`        VARCHAR(255)       NOT NULL, |  | ||||||
|     `Description` VARCHAR(255)                                  NULL, |  | ||||||
|     `ChannelId`   BIGINT             NULL, |  | ||||||
|     `StartTime`   DATETIME(6)        NOT NULL, |  | ||||||
|     `EndTime`     DATETIME(6)        NULL, |  | ||||||
|     `EntityType`  ENUM ('1','2','3') NOT NULL, |  | ||||||
|     `Location`    VARCHAR(255)       NULL, |  | ||||||
|     `ServerId`    BIGINT(20) DEFAULT NULL, |  | ||||||
|     `Deleted`     BOOL       DEFAULT FALSE, |  | ||||||
|     `DateFrom`    DATETIME(6)        NOT NULL, |  | ||||||
|     `DateTo`      DATETIME(6)        NOT NULL |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_ScheduledEventsUpdate`; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_ScheduledEventsUpdate` |  | ||||||
|     AFTER UPDATE |  | ||||||
|     ON `ScheduledEvents` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `ScheduledEventsHistory` (`Id`, |  | ||||||
|                                           `Interval`, |  | ||||||
|                                           `Name`, |  | ||||||
|                                           `Description`, |  | ||||||
|                                           `ChannelId`, |  | ||||||
|                                           `StartTime`, |  | ||||||
|                                           `EndTime`, |  | ||||||
|                                           `EntityType`, |  | ||||||
|                                           `Location`, |  | ||||||
|                                           `ServerId`, |  | ||||||
|                                           `DateFrom`, |  | ||||||
|                                           `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.Interval, OLD.Name, OLD.Description, OLD.ChannelId, OLD.StartTime, OLD.EndTime, OLD.EntityType, |  | ||||||
|             OLD.Location, OLD.ServerId, OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END; |  | ||||||
|  |  | ||||||
| DROP TRIGGER IF EXISTS `TR_ScheduledEventsDelete`; |  | ||||||
|  |  | ||||||
| CREATE TRIGGER `TR_ScheduledEventsDelete` |  | ||||||
|     AFTER DELETE |  | ||||||
|     ON `ScheduledEvents` |  | ||||||
|     FOR EACH ROW |  | ||||||
| BEGIN |  | ||||||
|     INSERT INTO `ScheduledEventsHistory` (`Id`, |  | ||||||
|                                           `Interval`, |  | ||||||
|                                           `Name`, |  | ||||||
|                                           `Description`, |  | ||||||
|                                           `ChannelId`, |  | ||||||
|                                           `StartTime`, |  | ||||||
|                                           `EndTime`, |  | ||||||
|                                           `EntityType`, |  | ||||||
|                                           `Location`, |  | ||||||
|                                           `ServerId`, |  | ||||||
|                                           `Deleted`, |  | ||||||
|                                           `DateFrom`, |  | ||||||
|                                           `DateTo`) |  | ||||||
|     VALUES (OLD.Id, OLD.Interval, OLD.Name, OLD.Description, OLD.ChannelId, OLD.StartTime, OLD.EndTime, OLD.EntityType, |  | ||||||
|             OLD.Location, OLD.ServerId, TRUE, OLD.LastModifiedAt, |  | ||||||
|             CURRENT_TIMESTAMP(6)); |  | ||||||
| END; |  | ||||||
| @@ -1,161 +0,0 @@ | |||||||
| import glob |  | ||||||
| import os |  | ||||||
|  |  | ||||||
| from cpl_core.database.context import DatabaseContextABC |  | ||||||
| from cpl_core.dependency_injection import ServiceProviderABC |  | ||||||
| from cpl_query.extension import List |  | ||||||
| from packaging import version |  | ||||||
|  |  | ||||||
| import bot |  | ||||||
| from bot_core.logging.database_logger import DatabaseLogger |  | ||||||
| from bot_data.model.migration import Migration |  | ||||||
| from bot_data.model.migration_history import MigrationHistory |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class MigrationService: |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         logger: DatabaseLogger, |  | ||||||
|         services: ServiceProviderABC, |  | ||||||
|         db: DatabaseContextABC, |  | ||||||
|     ): |  | ||||||
|         self._logger = logger |  | ||||||
|         self._services = services |  | ||||||
|  |  | ||||||
|         self._db = db |  | ||||||
|         self._cursor = db.cursor |  | ||||||
|  |  | ||||||
|     def _get_migration_history(self) -> List[MigrationHistory]: |  | ||||||
|         results = self._db.select( |  | ||||||
|             """ |  | ||||||
|             SELECT * FROM `MigrationHistory` |  | ||||||
|         """ |  | ||||||
|         ) |  | ||||||
|         applied_migrations = List(MigrationHistory) |  | ||||||
|         for result in results: |  | ||||||
|             applied_migrations.add(MigrationHistory(result[0], result[1])) |  | ||||||
|  |  | ||||||
|         return applied_migrations |  | ||||||
|  |  | ||||||
|     def _migration_migrations_to_old(self, migration: MigrationHistory): |  | ||||||
|         if migration.migration_id.endswith("Migration"): |  | ||||||
|             return |  | ||||||
|  |  | ||||||
|         self._logger.debug(__name__, f"Migrate new migration {migration.migration_id} to old method") |  | ||||||
|         self._cursor.execute(migration.change_id_string(f"{migration.migration_id}Migration")) |  | ||||||
|         self._db.save_changes() |  | ||||||
|  |  | ||||||
|     def _migration_migrations_to_new(self, migration: MigrationHistory): |  | ||||||
|         if not migration.migration_id.endswith("Migration"): |  | ||||||
|             return |  | ||||||
|  |  | ||||||
|         self._logger.debug(__name__, f"Migrate old migration {migration.migration_id} to new method") |  | ||||||
|         self._cursor.execute(migration.change_id_string(migration.migration_id.replace("Migration", ""))) |  | ||||||
|         self._db.save_changes() |  | ||||||
|  |  | ||||||
|     def _migrate_from_old_to_new(self): |  | ||||||
|         self._cursor.execute("SHOW TABLES LIKE 'MigrationHistory'") |  | ||||||
|         result = self._cursor.fetchone() |  | ||||||
|         if not result: |  | ||||||
|             return |  | ||||||
|  |  | ||||||
|         for migration in self._get_migration_history(): |  | ||||||
|             if version.Version(bot.__version__) < version.Version("1.2.2"): |  | ||||||
|                 self._migration_migrations_to_old(migration) |  | ||||||
|             else: |  | ||||||
|                 self._migration_migrations_to_new(migration) |  | ||||||
|  |  | ||||||
|     def _load_scripts(self, upgrade: bool = True) -> List[Migration]: |  | ||||||
|         migrations = List(Migration) |  | ||||||
|         path = "../bot_data/scripts" |  | ||||||
|  |  | ||||||
|         if not os.path.exists(path): |  | ||||||
|             raise Exception("Migration path not found") |  | ||||||
|  |  | ||||||
|         folders = List(str, glob.glob(f"{path}/*")) |  | ||||||
|         if upgrade: |  | ||||||
|             folders = folders.order_by() |  | ||||||
|         else: |  | ||||||
|             folders = folders.order_by_descending() |  | ||||||
|  |  | ||||||
|         for folder in folders: |  | ||||||
|             splitted = folder.split("/") |  | ||||||
|             version_str = splitted[len(splitted) - 1] |  | ||||||
|  |  | ||||||
|             # upgrade do not run migrations from higher versions |  | ||||||
|             if upgrade and version.Version(version_str) > version.Version(bot.__version__): |  | ||||||
|                 break |  | ||||||
|             # downgrade run migrations from higher versions |  | ||||||
|             if not upgrade and version.Version(version_str) <= version.Version(bot.__version__): |  | ||||||
|                 continue |  | ||||||
|  |  | ||||||
|             files = List(str, os.listdir(folder)).where(lambda x: x.endswith(f"_{'up' if upgrade else 'down'}.sql")) |  | ||||||
|             if upgrade: |  | ||||||
|                 files = files.order_by() |  | ||||||
|             else: |  | ||||||
|                 files = files.order_by_descending() |  | ||||||
|  |  | ||||||
|             for file in files.to_list(): |  | ||||||
|                 if not file.endswith(".sql"): |  | ||||||
|                     continue |  | ||||||
|  |  | ||||||
|                 name = str(file.split(".sql")[0]) |  | ||||||
|                 if name.endswith("_up"): |  | ||||||
|                     name = name.replace("_up", "") |  | ||||||
|                 elif name.endswith("_down"): |  | ||||||
|                     name = name.replace("_down", "") |  | ||||||
|  |  | ||||||
|                 name = name.split("_")[1] |  | ||||||
|  |  | ||||||
|                 with open(f"{folder}/{file}", "r") as f: |  | ||||||
|                     script = f.read() |  | ||||||
|                     f.close() |  | ||||||
|  |  | ||||||
|                 migrations.add(Migration(name, version_str, script)) |  | ||||||
|  |  | ||||||
|         return migrations |  | ||||||
|  |  | ||||||
|     def _execute(self, migrations: List[Migration], upgrade: bool = True): |  | ||||||
|         for migration in migrations: |  | ||||||
|             active_statement = "" |  | ||||||
|             try: |  | ||||||
|                 # check if table exists |  | ||||||
|                 self._cursor.execute("SHOW TABLES LIKE 'MigrationHistory'") |  | ||||||
|                 result = self._cursor.fetchone() |  | ||||||
|                 if result: |  | ||||||
|                     # there is a table named "tableName" |  | ||||||
|                     self._logger.trace( |  | ||||||
|                         __name__, |  | ||||||
|                         f"Running SQL Command: {MigrationHistory.get_select_by_id_string(migration.name)}", |  | ||||||
|                     ) |  | ||||||
|                     migration_from_db = self._db.select(MigrationHistory.get_select_by_id_string(migration.name)) |  | ||||||
|                     if upgrade and migration_from_db is not None and len(migration_from_db) > 0: |  | ||||||
|                         continue |  | ||||||
|                     elif not upgrade and (migration_from_db is None or len(migration_from_db) == 0): |  | ||||||
|                         continue |  | ||||||
|  |  | ||||||
|                 self._logger.debug( |  | ||||||
|                     __name__, f"Running {'upgrade' if upgrade else 'downgrade'} migration: {migration.name}" |  | ||||||
|                 ) |  | ||||||
|  |  | ||||||
|                 for statement in migration.script.split("\n\n"): |  | ||||||
|                     if statement in ["", "\n"]: |  | ||||||
|                         continue |  | ||||||
|                     active_statement = statement |  | ||||||
|                     self._cursor.execute(statement + ";") |  | ||||||
|  |  | ||||||
|                 self._cursor.execute( |  | ||||||
|                     MigrationHistory(migration.name).insert_string |  | ||||||
|                     if upgrade |  | ||||||
|                     else MigrationHistory(migration.name).delete_string |  | ||||||
|                 ) |  | ||||||
|                 self._db.save_changes() |  | ||||||
|             except Exception as e: |  | ||||||
|                 self._logger.fatal( |  | ||||||
|                     __name__, f"Migration failed: {migration.version}-{migration.name}\n{active_statement}", e |  | ||||||
|                 ) |  | ||||||
|  |  | ||||||
|     def migrate(self): |  | ||||||
|         self._migrate_from_old_to_new() |  | ||||||
|         self._execute(self._load_scripts()) |  | ||||||
|         self._execute(self._load_scripts(False), False) |  | ||||||
| @@ -1,91 +0,0 @@ | |||||||
| from typing import Optional |  | ||||||
|  |  | ||||||
| from cpl_core.database.context import DatabaseContextABC |  | ||||||
| from cpl_query.extension import List |  | ||||||
| from discord import EntityType |  | ||||||
|  |  | ||||||
| from bot_core.logging.database_logger import DatabaseLogger |  | ||||||
| from bot_data.abc.server_repository_abc import ServerRepositoryABC |  | ||||||
| from bot_data.abc.scheduled_event_repository_abc import ScheduledEventRepositoryABC |  | ||||||
| from bot_data.model.scheduled_event import ScheduledEvent |  | ||||||
| from bot_data.model.scheduled_event_interval_enum import ScheduledEventIntervalEnum |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ScheduledEventRepositoryService(ScheduledEventRepositoryABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         logger: DatabaseLogger, |  | ||||||
|         db_context: DatabaseContextABC, |  | ||||||
|         servers: ServerRepositoryABC, |  | ||||||
|     ): |  | ||||||
|         self._logger = logger |  | ||||||
|         self._context = db_context |  | ||||||
|  |  | ||||||
|         self._servers = servers |  | ||||||
|  |  | ||||||
|         ScheduledEventRepositoryABC.__init__(self) |  | ||||||
|  |  | ||||||
|     @staticmethod |  | ||||||
|     def _get_value_from_result(value: any) -> Optional[any]: |  | ||||||
|         if isinstance(value, str) and "NULL" in value: |  | ||||||
|             return None |  | ||||||
|  |  | ||||||
|         return value |  | ||||||
|  |  | ||||||
|     def _scheduled_event_from_result(self, sql_result: tuple) -> ScheduledEvent: |  | ||||||
|         return ScheduledEvent( |  | ||||||
|             self._get_value_from_result(ScheduledEventIntervalEnum(sql_result[1])),  # interval |  | ||||||
|             self._get_value_from_result(sql_result[2]),  # name |  | ||||||
|             self._get_value_from_result(sql_result[3]),  # description |  | ||||||
|             int(self._get_value_from_result(sql_result[4])),  # channel_id |  | ||||||
|             self._get_value_from_result(sql_result[5]),  # start_time |  | ||||||
|             self._get_value_from_result(sql_result[6]),  # end_time |  | ||||||
|             EntityType(int(self._get_value_from_result(sql_result[7]))),  # entity_type |  | ||||||
|             self._get_value_from_result(sql_result[8]),  # location |  | ||||||
|             self._servers.get_server_by_id((sql_result[9])),  # server |  | ||||||
|             self._get_value_from_result(sql_result[10]),  # created_at |  | ||||||
|             self._get_value_from_result(sql_result[11]),  # modified_at |  | ||||||
|             id=self._get_value_from_result(sql_result[0]), |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     def get_scheduled_events(self) -> List[ScheduledEvent]: |  | ||||||
|         scheduled_events = List(ScheduledEvent) |  | ||||||
|         self._logger.trace(__name__, f"Send SQL command: {ScheduledEvent.get_select_all_string()}") |  | ||||||
|         results = self._context.select(ScheduledEvent.get_select_all_string()) |  | ||||||
|         for result in results: |  | ||||||
|             self._logger.trace(__name__, f"Get scheduled_event with id {result[0]}") |  | ||||||
|             scheduled_events.append(self._scheduled_event_from_result(result)) |  | ||||||
|  |  | ||||||
|         return scheduled_events |  | ||||||
|  |  | ||||||
|     def get_scheduled_event_by_id(self, id: int) -> ScheduledEvent: |  | ||||||
|         self._logger.trace(__name__, f"Send SQL command: {ScheduledEvent.get_select_by_id_string(id)}") |  | ||||||
|         result = self._context.select(ScheduledEvent.get_select_by_id_string(id))[0] |  | ||||||
|  |  | ||||||
|         return self._scheduled_event_from_result(result) |  | ||||||
|  |  | ||||||
|     def get_scheduled_events_by_server_id(self, server_id: int) -> List[ScheduledEvent]: |  | ||||||
|         scheduled_events = List(ScheduledEvent) |  | ||||||
|         self._logger.trace( |  | ||||||
|             __name__, |  | ||||||
|             f"Send SQL command: {ScheduledEvent.get_select_by_server_id_string(server_id)}", |  | ||||||
|         ) |  | ||||||
|         results = self._context.select(ScheduledEvent.get_select_by_server_id_string(server_id)) |  | ||||||
|  |  | ||||||
|         for result in results: |  | ||||||
|             self._logger.trace(__name__, f"Get scheduled_event with id {result[0]}") |  | ||||||
|             scheduled_events.append(self._scheduled_event_from_result(result)) |  | ||||||
|  |  | ||||||
|         return scheduled_events |  | ||||||
|  |  | ||||||
|     def add_scheduled_event(self, scheduled_event: ScheduledEvent): |  | ||||||
|         self._logger.trace(__name__, f"Send SQL command: {scheduled_event.insert_string}") |  | ||||||
|         self._context.cursor.execute(scheduled_event.insert_string) |  | ||||||
|  |  | ||||||
|     def update_scheduled_event(self, scheduled_event: ScheduledEvent): |  | ||||||
|         self._logger.trace(__name__, f"Send SQL command: {scheduled_event.udpate_string}") |  | ||||||
|         self._context.cursor.execute(scheduled_event.udpate_string) |  | ||||||
|  |  | ||||||
|     def delete_scheduled_event(self, scheduled_event: ScheduledEvent): |  | ||||||
|         self._logger.trace(__name__, f"Send SQL command: {scheduled_event.delete_string}") |  | ||||||
|         self._context.cursor.execute(scheduled_event.delete_string) |  | ||||||
| @@ -1,73 +0,0 @@ | |||||||
| from typing import Optional |  | ||||||
|  |  | ||||||
| from cpl_core.database.context import DatabaseContextABC |  | ||||||
| from cpl_query.extension import List |  | ||||||
|  |  | ||||||
| from bot_core.logging.database_logger import DatabaseLogger |  | ||||||
| from bot_data.abc.server_repository_abc import ServerRepositoryABC |  | ||||||
| from bot_data.abc.steam_special_offer_repository_abc import ( |  | ||||||
|     SteamSpecialOfferRepositoryABC, |  | ||||||
| ) |  | ||||||
| from bot_data.model.steam_special_offer import SteamSpecialOffer |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class SteamSpecialOfferRepositoryService(SteamSpecialOfferRepositoryABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         logger: DatabaseLogger, |  | ||||||
|         db_context: DatabaseContextABC, |  | ||||||
|         servers: ServerRepositoryABC, |  | ||||||
|     ): |  | ||||||
|         self._logger = logger |  | ||||||
|         self._context = db_context |  | ||||||
|  |  | ||||||
|         self._servers = servers |  | ||||||
|  |  | ||||||
|         SteamSpecialOfferRepositoryABC.__init__(self) |  | ||||||
|  |  | ||||||
|     @staticmethod |  | ||||||
|     def _get_value_from_result(value: any) -> Optional[any]: |  | ||||||
|         if isinstance(value, str) and "NULL" in value: |  | ||||||
|             return None |  | ||||||
|  |  | ||||||
|         return value |  | ||||||
|  |  | ||||||
|     def _steam_special_offer_from_result(self, sql_result: tuple) -> SteamSpecialOffer: |  | ||||||
|         return SteamSpecialOffer( |  | ||||||
|             self._get_value_from_result(sql_result[1]),  # name |  | ||||||
|             float(self._get_value_from_result(sql_result[2])),  # original_price |  | ||||||
|             float(self._get_value_from_result(sql_result[3])),  # discount_price |  | ||||||
|             int(self._get_value_from_result(sql_result[4])),  # discount_pct |  | ||||||
|             id=self._get_value_from_result(sql_result[0]),  # id |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     def get_steam_special_offers(self) -> List[SteamSpecialOffer]: |  | ||||||
|         steam_special_offers = List(SteamSpecialOffer) |  | ||||||
|         self._logger.trace(__name__, f"Send SQL command: {SteamSpecialOffer.get_select_all_string()}") |  | ||||||
|         results = self._context.select(SteamSpecialOffer.get_select_all_string()) |  | ||||||
|         for result in results: |  | ||||||
|             self._logger.trace(__name__, f"Get steam_special_offer with id {result[0]}") |  | ||||||
|             steam_special_offers.append(self._steam_special_offer_from_result(result)) |  | ||||||
|  |  | ||||||
|         return steam_special_offers |  | ||||||
|  |  | ||||||
|     def get_steam_special_offer_by_name(self, name: str) -> SteamSpecialOffer: |  | ||||||
|         self._logger.trace( |  | ||||||
|             __name__, |  | ||||||
|             f"Send SQL command: {SteamSpecialOffer.get_select_by_name_string(name)}", |  | ||||||
|         ) |  | ||||||
|         result = self._context.select(SteamSpecialOffer.get_select_by_name_string(name))[0] |  | ||||||
|  |  | ||||||
|         return self._steam_special_offer_from_result(result) |  | ||||||
|  |  | ||||||
|     def add_steam_special_offer(self, steam_special_offer: SteamSpecialOffer): |  | ||||||
|         self._logger.trace(__name__, f"Send SQL command: {steam_special_offer.insert_string}") |  | ||||||
|         self._context.cursor.execute(steam_special_offer.insert_string) |  | ||||||
|  |  | ||||||
|     def update_steam_special_offer(self, steam_special_offer: SteamSpecialOffer): |  | ||||||
|         self._logger.trace(__name__, f"Send SQL command: {steam_special_offer.udpate_string}") |  | ||||||
|         self._context.cursor.execute(steam_special_offer.udpate_string) |  | ||||||
|  |  | ||||||
|     def delete_steam_special_offer(self, steam_special_offer: SteamSpecialOffer): |  | ||||||
|         self._logger.trace(__name__, f"Send SQL command: {steam_special_offer.delete_string}") |  | ||||||
|         self._context.cursor.execute(steam_special_offer.delete_string) |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| from cpl_core.application import StartupExtensionABC |  | ||||||
| from cpl_core.configuration import ConfigurationABC |  | ||||||
| from cpl_core.dependency_injection import ServiceCollectionABC |  | ||||||
| from cpl_core.environment import ApplicationEnvironmentABC |  | ||||||
|  |  | ||||||
| from bot_data.service.migration_service import MigrationService |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class StartupMigrationExtension(StartupExtensionABC): |  | ||||||
|     def __init__(self): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC): |  | ||||||
|         services.add_transient(MigrationService) |  | ||||||
| @@ -1,71 +0,0 @@ | |||||||
| from cpl_core.dependency_injection import ServiceProviderABC |  | ||||||
| from cpl_discord.service import DiscordBotServiceABC |  | ||||||
| from cpl_query.extension import List |  | ||||||
|  |  | ||||||
| from bot_data.model.scheduled_event import ScheduledEvent |  | ||||||
| from bot_graphql.abc.filter_abc import FilterABC |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ScheduledEventFilter(FilterABC): |  | ||||||
|     def __init__(self, bot: DiscordBotServiceABC, services: ServiceProviderABC): |  | ||||||
|         FilterABC.__init__(self) |  | ||||||
|         self._bot = bot |  | ||||||
|         self._services = services |  | ||||||
|  |  | ||||||
|         self._id = None |  | ||||||
|         self._interval = None |  | ||||||
|         self._name = None |  | ||||||
|         self._description = None |  | ||||||
|         self._channel_id = None |  | ||||||
|         self._start_time = None |  | ||||||
|         self._end_time = None |  | ||||||
|         self._entity_type = None |  | ||||||
|         self._location = None |  | ||||||
|         self._server = None |  | ||||||
|  |  | ||||||
|     def from_dict(self, values: dict): |  | ||||||
|         self._get_attributes_from_dict( |  | ||||||
|             [ |  | ||||||
|                 ("id", int), |  | ||||||
|                 ("interval", str), |  | ||||||
|                 ("name", str), |  | ||||||
|                 ("description", str), |  | ||||||
|                 ("channel_id", str), |  | ||||||
|                 ("start_time", str), |  | ||||||
|                 ("end_time", str), |  | ||||||
|                 ("entity_type", str), |  | ||||||
|                 ("location", str), |  | ||||||
|             ], |  | ||||||
|             values, |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|         if "server" in values: |  | ||||||
|             from bot_graphql.filter.server_filter import ServerFilter |  | ||||||
|  |  | ||||||
|             self._server: ServerFilter = self._services.get_service(ServerFilter) |  | ||||||
|             self._server.from_dict(values["server"]) |  | ||||||
|  |  | ||||||
|     def filter(self, query: List[ScheduledEvent]) -> List[ScheduledEvent]: |  | ||||||
|         if self._id is not None: |  | ||||||
|             query = query.where(lambda x: x.id == self._id) |  | ||||||
|  |  | ||||||
|         query = self._filter_by_attributes( |  | ||||||
|             [ |  | ||||||
|                 {"attr": self._id, "func": lambda x: x.id == self._id}, |  | ||||||
|                 {"attr": self._interval, "func": lambda x: x.interval == self._interval}, |  | ||||||
|                 {"attr": self._name, "func": lambda x: x.name == self._name}, |  | ||||||
|                 {"attr": self._description, "func": lambda x: x.description == self._description}, |  | ||||||
|                 {"attr": self._channel_id, "func": lambda x: x.channel_id == self._channel_id}, |  | ||||||
|                 {"attr": self._start_time, "func": lambda x: x.start_time == self._start_time}, |  | ||||||
|                 {"attr": self._end_time, "func": lambda x: x.end_time == self._end_time}, |  | ||||||
|                 {"attr": self._entity_type, "func": lambda x: x.entity_type == self._entity_type}, |  | ||||||
|                 {"attr": self._location, "func": lambda x: x.location == self._location}, |  | ||||||
|             ], |  | ||||||
|             query, |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|         if self._server is not None: |  | ||||||
|             servers = self._server.filter(query.select(lambda x: x.server)).select(lambda x: x.id) |  | ||||||
|             query = query.where(lambda x: x.server.id in servers) |  | ||||||
|  |  | ||||||
|         return query |  | ||||||
| @@ -1,56 +0,0 @@ | |||||||
| from cpl_core.dependency_injection import ServiceProviderABC |  | ||||||
| from cpl_query.extension import List |  | ||||||
|  |  | ||||||
| from bot_data.model.user_warnings import UserWarnings |  | ||||||
| from bot_graphql.abc.filter_abc import FilterABC |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class UserWarningFilter(FilterABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         services: ServiceProviderABC, |  | ||||||
|     ): |  | ||||||
|         FilterABC.__init__(self) |  | ||||||
|  |  | ||||||
|         self._services = services |  | ||||||
|  |  | ||||||
|         self._id = None |  | ||||||
|         self._user = None |  | ||||||
|         self._description = None |  | ||||||
|         self._author = None |  | ||||||
|  |  | ||||||
|     def from_dict(self, values: dict): |  | ||||||
|         if "id" in values: |  | ||||||
|             self._id = int(values["id"]) |  | ||||||
|  |  | ||||||
|         if "user" in values: |  | ||||||
|             from bot_graphql.filter.user_filter import UserFilter |  | ||||||
|  |  | ||||||
|             self._user: UserFilter = self._services.get_service(UserFilter) |  | ||||||
|             self._user.from_dict(values["user"]) |  | ||||||
|  |  | ||||||
|         if "description" in values: |  | ||||||
|             self._description = values["description"] |  | ||||||
|  |  | ||||||
|         if "author" in values: |  | ||||||
|             from bot_graphql.filter.user_filter import UserFilter |  | ||||||
|  |  | ||||||
|             self._author: UserFilter = self._services.get_service(UserFilter) |  | ||||||
|             self._author.from_dict(values["author"]) |  | ||||||
|  |  | ||||||
|     def filter(self, query: List[UserWarnings]) -> List[UserWarnings]: |  | ||||||
|         if self._id is not None: |  | ||||||
|             query = query.where(lambda x: x.id == self._id) |  | ||||||
|  |  | ||||||
|         if self._user is not None: |  | ||||||
|             users = self._user.filter(query.select(lambda x: x.user)).select(lambda x: x.id) |  | ||||||
|             query = query.where(lambda x: x.id in users) |  | ||||||
|  |  | ||||||
|         if self._description is not None: |  | ||||||
|             query = query.where(lambda x: x.description == self._description or self._description in x.description) |  | ||||||
|  |  | ||||||
|         if self._author is not None: |  | ||||||
|             users = self._author.filter(query.select(lambda x: x.author)).select(lambda x: x.id) |  | ||||||
|             query = query.where(lambda x: x.id in users) |  | ||||||
|  |  | ||||||
|         return query |  | ||||||
| @@ -1,68 +0,0 @@ | |||||||
| type ScheduledEvent implements TableWithHistoryQuery { |  | ||||||
|     id: ID |  | ||||||
|     interval: String |  | ||||||
|     name: String |  | ||||||
|     description: String |  | ||||||
|     channelId: String |  | ||||||
|     startTime: String |  | ||||||
|     endTime: String |  | ||||||
|     entityType: Int |  | ||||||
|     location: String |  | ||||||
|  |  | ||||||
|     server: Server |  | ||||||
|  |  | ||||||
|     createdAt: String |  | ||||||
|     modifiedAt: String |  | ||||||
|  |  | ||||||
|     history: [ScheduledEventHistory] |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type ScheduledEventHistory implements HistoryTableQuery { |  | ||||||
|     id: ID |  | ||||||
|     interval: String |  | ||||||
|     name: String |  | ||||||
|     description: String |  | ||||||
|     channelId: String |  | ||||||
|     startTime: String |  | ||||||
|     endTime: String |  | ||||||
|     entityType: Int |  | ||||||
|     location: String |  | ||||||
|  |  | ||||||
|     server: ID |  | ||||||
|  |  | ||||||
|     deleted: Boolean |  | ||||||
|     dateFrom: String |  | ||||||
|     dateTo: String |  | ||||||
| } |  | ||||||
|  |  | ||||||
| input ScheduledEventFilter { |  | ||||||
|     id: ID |  | ||||||
|     interval: String |  | ||||||
|     name: String |  | ||||||
|     description: String |  | ||||||
|     channelId: String |  | ||||||
|     startTime: String |  | ||||||
|     endTime: String |  | ||||||
|     entityType: Int |  | ||||||
|     location: String |  | ||||||
|     server: ServerFilter |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type ScheduledEventMutation { |  | ||||||
|     createScheduledEvent(input: ScheduledEventInput!): ScheduledEvent |  | ||||||
|     updateScheduledEvent(input: ScheduledEventInput!): ScheduledEvent |  | ||||||
|     deleteScheduledEvent(id: ID): ScheduledEvent |  | ||||||
| } |  | ||||||
|  |  | ||||||
| input ScheduledEventInput { |  | ||||||
|     id: ID |  | ||||||
|     interval: String |  | ||||||
|     name: String |  | ||||||
|     description: String |  | ||||||
|     channelId: String |  | ||||||
|     startTime: String |  | ||||||
|     endTime: String |  | ||||||
|     entityType: Int |  | ||||||
|     location: String |  | ||||||
|     serverId: ID |  | ||||||
| } |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| type ServerStatistic { |  | ||||||
|     achievementsAchieved: Int |  | ||||||
|     messageCount: Int |  | ||||||
|  |  | ||||||
|     userCount: Int |  | ||||||
|     activeUserCount: Int |  | ||||||
|  |  | ||||||
|     userJoinedVoiceChannelCount: Int |  | ||||||
|     userJoinedVoiceChannelOntime: Float |  | ||||||
|  |  | ||||||
|     userJoinedGameServerCount: Int |  | ||||||
|     userJoinedGameServerOntime: Float |  | ||||||
|  |  | ||||||
|     userWarningCount: Int |  | ||||||
|  |  | ||||||
|     activityScore: Int |  | ||||||
| } |  | ||||||
| @@ -1,34 +0,0 @@ | |||||||
| type UserWarning implements TableWithHistoryQuery { |  | ||||||
|     id: ID |  | ||||||
|     user: User |  | ||||||
|     description: String |  | ||||||
|     author: User |  | ||||||
|  |  | ||||||
|     createdAt: String |  | ||||||
|     modifiedAt: String |  | ||||||
|  |  | ||||||
|     history: [UserWarningHistory] |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type UserWarningHistory implements HistoryTableQuery { |  | ||||||
|     id: ID |  | ||||||
|     user: ID |  | ||||||
|     description: String |  | ||||||
|     author: ID |  | ||||||
|  |  | ||||||
|     deleted: Boolean |  | ||||||
|     dateFrom: String |  | ||||||
|     dateTo: String |  | ||||||
| } |  | ||||||
|  |  | ||||||
| input UserWarningFilter { |  | ||||||
|     id: ID |  | ||||||
|     user: UserFilter |  | ||||||
| } |  | ||||||
|  |  | ||||||
| input UserWarningInput { |  | ||||||
|     id: ID |  | ||||||
|     user: ID |  | ||||||
|     description: String |  | ||||||
|     author: ID |  | ||||||
| } |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| from bot_data.model.server import Server |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ServerStatistics: |  | ||||||
|     def __init__(self, server: Server, kwargs: dict): |  | ||||||
|         self.server = server |  | ||||||
|         self.kwargs = kwargs |  | ||||||
| @@ -1,107 +0,0 @@ | |||||||
| from datetime import datetime |  | ||||||
|  |  | ||||||
| from cpl_core.database.context import DatabaseContextABC |  | ||||||
| from cpl_discord.service import DiscordBotServiceABC |  | ||||||
| from discord import EntityType |  | ||||||
|  |  | ||||||
| from bot_data.abc.server_repository_abc import ServerRepositoryABC |  | ||||||
| from bot_data.abc.scheduled_event_repository_abc import ScheduledEventRepositoryABC |  | ||||||
| from bot_data.model.scheduled_event import ScheduledEvent |  | ||||||
| from bot_data.model.scheduled_event_interval_enum import ScheduledEventIntervalEnum |  | ||||||
| from bot_data.model.user_role_enum import UserRoleEnum |  | ||||||
| from bot_graphql.abc.query_abc import QueryABC |  | ||||||
| from modules.permission.service.permission_service import PermissionService |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ScheduledEventMutation(QueryABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         servers: ServerRepositoryABC, |  | ||||||
|         scheduled_events: ScheduledEventRepositoryABC, |  | ||||||
|         bot: DiscordBotServiceABC, |  | ||||||
|         db: DatabaseContextABC, |  | ||||||
|         permissions: PermissionService, |  | ||||||
|     ): |  | ||||||
|         QueryABC.__init__(self, "ScheduledEventMutation") |  | ||||||
|  |  | ||||||
|         self._servers = servers |  | ||||||
|         self._scheduled_events = scheduled_events |  | ||||||
|         self._bot = bot |  | ||||||
|         self._db = db |  | ||||||
|         self._permissions = permissions |  | ||||||
|  |  | ||||||
|         self.set_field("createScheduledEvent", self.resolve_create_scheduled_event) |  | ||||||
|         self.set_field("updateScheduledEvent", self.resolve_update_scheduled_event) |  | ||||||
|         self.set_field("deleteScheduledEvent", self.resolve_delete_scheduled_event) |  | ||||||
|  |  | ||||||
|     def resolve_create_scheduled_event(self, *_, input: dict): |  | ||||||
|         server = self._servers.get_server_by_id(input["serverId"]) |  | ||||||
|         self._can_user_mutate_data(server, UserRoleEnum.moderator) |  | ||||||
|  |  | ||||||
|         scheduled_event = ScheduledEvent( |  | ||||||
|             ScheduledEventIntervalEnum(input["interval"]), |  | ||||||
|             input["name"], |  | ||||||
|             input["description"] if "description" in input else None, |  | ||||||
|             input["channelId"] if "channelId" in input else None, |  | ||||||
|             datetime.strptime(input["startTime"], "%Y-%m-%dT%H:%M:%S.%fZ"), |  | ||||||
|             datetime.strptime(input["endTime"], "%Y-%m-%dT%H:%M:%S.%fZ") if "endTime" in input else None, |  | ||||||
|             EntityType(int(input["entityType"])), |  | ||||||
|             input["location"] if "location" in input else None, |  | ||||||
|             server, |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|         self._scheduled_events.add_scheduled_event(scheduled_event) |  | ||||||
|         self._db.save_changes() |  | ||||||
|  |  | ||||||
|         def get_new_scheduled_event(srn: ScheduledEvent): |  | ||||||
|             return ( |  | ||||||
|                 srn.interval == scheduled_event.interval |  | ||||||
|                 and srn.name == scheduled_event.name |  | ||||||
|                 and srn.description == scheduled_event.description |  | ||||||
|             ) |  | ||||||
|  |  | ||||||
|         return ( |  | ||||||
|             self._scheduled_events.get_scheduled_events_by_server_id(scheduled_event.server.id) |  | ||||||
|             .where(get_new_scheduled_event) |  | ||||||
|             .last() |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     def resolve_update_scheduled_event(self, *_, input: dict): |  | ||||||
|         scheduled_event = self._scheduled_events.get_scheduled_event_by_id(input["id"]) |  | ||||||
|         self._can_user_mutate_data(scheduled_event.server, UserRoleEnum.moderator) |  | ||||||
|  |  | ||||||
|         scheduled_event.interval = ( |  | ||||||
|             ScheduledEventIntervalEnum(input["interval"]) if "interval" in input else scheduled_event.interval |  | ||||||
|         ) |  | ||||||
|         scheduled_event.name = input["name"] if "name" in input else scheduled_event.name |  | ||||||
|         scheduled_event.description = input["description"] if "description" in input else scheduled_event.description |  | ||||||
|         scheduled_event.channel_id = input["channelId"] if "channelId" in input else scheduled_event.channel_id |  | ||||||
|         scheduled_event.start_time = ( |  | ||||||
|             datetime.strptime(input["startTime"], "%Y-%m-%dT%H:%M:%S.%fZ") |  | ||||||
|             if "startTime" in input |  | ||||||
|             else scheduled_event.start_time |  | ||||||
|         ) |  | ||||||
|         scheduled_event.end_time = ( |  | ||||||
|             datetime.strptime(input["endTime"], "%Y-%m-%dT%H:%M:%S.%fZ") |  | ||||||
|             if "endTime" in input |  | ||||||
|             else scheduled_event.end_time |  | ||||||
|         ) |  | ||||||
|         scheduled_event.entity_type = ( |  | ||||||
|             EntityType(int(input["entityType"])) if "entityType" in input else scheduled_event.entity_type |  | ||||||
|         ) |  | ||||||
|         scheduled_event.location = input["location"] if "location" in input else scheduled_event.location |  | ||||||
|  |  | ||||||
|         self._scheduled_events.update_scheduled_event(scheduled_event) |  | ||||||
|         self._db.save_changes() |  | ||||||
|  |  | ||||||
|         scheduled_event = self._scheduled_events.get_scheduled_event_by_id(input["id"]) |  | ||||||
|         return scheduled_event |  | ||||||
|  |  | ||||||
|     def resolve_delete_scheduled_event(self, *_, id: int): |  | ||||||
|         scheduled_event = self._scheduled_events.get_scheduled_event_by_id(id) |  | ||||||
|         self._can_user_mutate_data(scheduled_event.server, UserRoleEnum.admin) |  | ||||||
|  |  | ||||||
|         self._scheduled_events.delete_scheduled_event(scheduled_event) |  | ||||||
|         self._db.save_changes() |  | ||||||
|  |  | ||||||
|         return scheduled_event |  | ||||||
| @@ -1,90 +0,0 @@ | |||||||
| from datetime import datetime |  | ||||||
|  |  | ||||||
| from cpl_core.database.context import DatabaseContextABC |  | ||||||
| from cpl_discord.service import DiscordBotServiceABC |  | ||||||
|  |  | ||||||
| from bot_api.route.route import Route |  | ||||||
| from bot_data.abc.level_repository_abc import LevelRepositoryABC |  | ||||||
| from bot_data.abc.server_repository_abc import ServerRepositoryABC |  | ||||||
| from bot_data.abc.user_repository_abc import UserRepositoryABC |  | ||||||
| from bot_data.abc.user_warnings_repository_abc import UserWarningsRepositoryABC |  | ||||||
| from bot_data.model.user import User |  | ||||||
| from bot_data.model.user_role_enum import UserRoleEnum |  | ||||||
| from bot_graphql.abc.query_abc import QueryABC |  | ||||||
| from modules.base.service.user_warnings_service import UserWarningsService |  | ||||||
| from modules.level.service.level_service import LevelService |  | ||||||
| from modules.permission.service.permission_service import PermissionService |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class UserMutation(QueryABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         servers: ServerRepositoryABC, |  | ||||||
|         users: UserRepositoryABC, |  | ||||||
|         bot: DiscordBotServiceABC, |  | ||||||
|         db: DatabaseContextABC, |  | ||||||
|         permissions: PermissionService, |  | ||||||
|         levels: LevelRepositoryABC, |  | ||||||
|         level_service: LevelService, |  | ||||||
|         user_warnings: UserWarningsRepositoryABC, |  | ||||||
|         user_warning_service: UserWarningsService, |  | ||||||
|     ): |  | ||||||
|         QueryABC.__init__(self, "UserMutation") |  | ||||||
|  |  | ||||||
|         self._servers = servers |  | ||||||
|         self._users = users |  | ||||||
|         self._bot = bot |  | ||||||
|         self._db = db |  | ||||||
|         self._permissions = permissions |  | ||||||
|         self._levels = levels |  | ||||||
|         self._level_service = level_service |  | ||||||
|         self._user_warnings = user_warnings |  | ||||||
|         self._user_warning_service = user_warning_service |  | ||||||
|  |  | ||||||
|         self.set_field("updateUser", self.resolve_update_user) |  | ||||||
|  |  | ||||||
|     def resolve_update_user(self, *_, input: dict): |  | ||||||
|         user = self._users.get_user_by_id(input["id"]) |  | ||||||
|  |  | ||||||
|         auth_user = Route.get_user() |  | ||||||
|         member = self._bot.get_guild(user.server.discord_id).get_member( |  | ||||||
|             auth_user.users.where(lambda x: x.server.id == user.server.id).single().discord_id |  | ||||||
|         ) |  | ||||||
|         if member.id != user.discord_id: |  | ||||||
|             self._can_user_mutate_data(user.server, UserRoleEnum.moderator) |  | ||||||
|  |  | ||||||
|             new_xp = None |  | ||||||
|             if "levelId" in input: |  | ||||||
|                 level = self._levels.get_level_by_id(input["levelId"]) |  | ||||||
|                 if user.level.id != level.id: |  | ||||||
|                     new_xp = level.min_xp |  | ||||||
|  |  | ||||||
|             if "userWarnings" in input: |  | ||||||
|                 self._update_user_warning(user, input["userWarnings"]) |  | ||||||
|  |  | ||||||
|             user.xp = new_xp if new_xp is not None else input["xp"] if "xp" in input else user.xp |  | ||||||
|  |  | ||||||
|         user.birthday = datetime.strptime(input["birthday"], "%d.%m.%Y") if "birthday" in input else user.birthday |  | ||||||
|  |  | ||||||
|         self._users.update_user(user) |  | ||||||
|         self._db.save_changes() |  | ||||||
|         self._bot.loop.create_task(self._level_service.set_level(user)) |  | ||||||
|  |  | ||||||
|         user = self._users.get_user_by_id(input["id"]) |  | ||||||
|         return user |  | ||||||
|  |  | ||||||
|     def _update_user_warning(self, user: User, new_warnings: dict): |  | ||||||
|         old_warnings = self._user_warnings.get_user_warnings_by_user_id(user.id) |  | ||||||
|         for warning in old_warnings: |  | ||||||
|             if warning.id in [int(x["id"]) if "id" in x else None for x in new_warnings]: |  | ||||||
|                 continue |  | ||||||
|  |  | ||||||
|             self._user_warning_service.remove_warnings(warning.id) |  | ||||||
|  |  | ||||||
|         for warning in new_warnings: |  | ||||||
|             if "id" in warning and int(warning["id"]) in old_warnings.select(lambda x: x.id): |  | ||||||
|                 continue |  | ||||||
|  |  | ||||||
|             member = self._bot.get_guild(user.server.discord_id).get_member(user.discord_id) |  | ||||||
|             author = self._users.get_user_by_id(int(warning["author"])) |  | ||||||
|             self._user_warning_service.add_warnings(member, warning["description"], author.discord_id) |  | ||||||
| @@ -1,24 +0,0 @@ | |||||||
| from cpl_core.database.context import DatabaseContextABC |  | ||||||
|  |  | ||||||
| from bot_data.model.scheduled_event_history import ScheduledEventHistory |  | ||||||
| from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ScheduledEventHistoryQuery(DataQueryWithHistoryABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         db: DatabaseContextABC, |  | ||||||
|     ): |  | ||||||
|         DataQueryWithHistoryABC.__init__(self, "ScheduledEvent", "ScheduledEventsHistory", ScheduledEventHistory, db) |  | ||||||
|  |  | ||||||
|         self.set_field("id", lambda x, *_: x.id) |  | ||||||
|         self.set_field("id", lambda x, *_: x.id) |  | ||||||
|         self.set_field("interval", lambda x, *_: x.interval.value) |  | ||||||
|         self.set_field("name", lambda x, *_: x.name) |  | ||||||
|         self.set_field("description", lambda x, *_: x.description) |  | ||||||
|         self.set_field("channel_id", lambda x, *_: x.channel_id) |  | ||||||
|         self.set_field("start_time", lambda x, *_: x.start_time) |  | ||||||
|         self.set_field("end_time", lambda x, *_: x.end_time) |  | ||||||
|         self.set_field("entity_type", lambda x, *_: x.entity_type) |  | ||||||
|         self.set_field("location", lambda x, *_: x.location) |  | ||||||
|         self.set_field("server", lambda x, *_: x.server) |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| from cpl_core.database.context import DatabaseContextABC |  | ||||||
|  |  | ||||||
| from bot_data.model.scheduled_event_history import ScheduledEventHistory |  | ||||||
| from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ScheduledEventQuery(DataQueryWithHistoryABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         db: DatabaseContextABC, |  | ||||||
|     ): |  | ||||||
|         DataQueryWithHistoryABC.__init__(self, "ScheduledEvent", "ScheduledEventsHistory", ScheduledEventHistory, db) |  | ||||||
|  |  | ||||||
|         self.set_field("id", lambda x, *_: x.id) |  | ||||||
|         self.set_field("interval", lambda x, *_: x.interval.value) |  | ||||||
|         self.set_field("name", lambda x, *_: x.name) |  | ||||||
|         self.set_field("description", lambda x, *_: x.description) |  | ||||||
|         self.set_field("channelId", lambda x, *_: x.channel_id) |  | ||||||
|         self.set_field("startTime", lambda x, *_: x.start_time) |  | ||||||
|         self.set_field("endTime", lambda x, *_: x.end_time) |  | ||||||
|         self.set_field("entityType", lambda x, *_: x.entity_type.value) |  | ||||||
|         self.set_field("location", lambda x, *_: x.location) |  | ||||||
|         self.set_field("server", lambda x, *_: x.server) |  | ||||||
| @@ -1,174 +0,0 @@ | |||||||
| import datetime |  | ||||||
| from typing import Optional |  | ||||||
|  |  | ||||||
| from cpl_core.configuration import ConfigurationABC |  | ||||||
| from cpl_core.database.context import DatabaseContextABC |  | ||||||
| from cpl_core.type import R, T |  | ||||||
|  |  | ||||||
| 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_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, |  | ||||||
|         db: DatabaseContextABC, |  | ||||||
|     ): |  | ||||||
|         QueryABC.__init__(self, "ServerStatistic") |  | ||||||
|  |  | ||||||
|         self._config = config |  | ||||||
|         self._db = db |  | ||||||
|  |  | ||||||
|         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_user_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_active_user_count(self, server, *_): |  | ||||||
|         return self._users.get_users_by_server_id(server.server.id).where(lambda x: not x.left_server).count() |  | ||||||
|  |  | ||||||
|     def _cast_query_result(self, query: str, r_type: T) -> Optional[R]: |  | ||||||
|         results = self._db.select(query) |  | ||||||
|         if len(results) == 0 or len(results[0]) == 0: |  | ||||||
|             return None |  | ||||||
|         result = results[0][0] |  | ||||||
|         default = None |  | ||||||
|         if r_type is int or r_type is float: |  | ||||||
|             default = 0 |  | ||||||
|         elif r_type is str: |  | ||||||
|             default = "" |  | ||||||
|  |  | ||||||
|         return r_type(result) if result is not None else default |  | ||||||
|  |  | ||||||
|     def _resolve_achievements(self, server, *_): |  | ||||||
|         query = f""" |  | ||||||
|             SELECT Count(UserGotAchievements.CreatedAt) FROM UserGotAchievements |  | ||||||
|             INNER JOIN Achievements ON UserGotAchievements.AchievementId = Achievements.Id |  | ||||||
|             INNER JOIN Users ON UserGotAchievements.UserId = Users.UserId |  | ||||||
|             WHERE Users.ServerId = {server.server.id} |  | ||||||
|                 AND UserGotAchievements.CreatedAt >= "{self._get_date(**server.kwargs)}"; |  | ||||||
|         """ |  | ||||||
|         return self._cast_query_result(query, int) |  | ||||||
|  |  | ||||||
|     def _resolve_message_count(self, server, *_): |  | ||||||
|         query = f""" |  | ||||||
|             SELECT SUM( |  | ||||||
|                 UserMessageCountPerHour.XPCount / ( |  | ||||||
|                     SELECT XpPerMessage |  | ||||||
|                     FROM CFG_Server |  | ||||||
|                     WHERE ServerId = {server.server.id} |  | ||||||
|                 ) |  | ||||||
|             ) |  | ||||||
|             FROM UserMessageCountPerHour |  | ||||||
|                      INNER JOIN Users ON UserMessageCountPerHour.UserId = Users.UserId |  | ||||||
|             WHERE Users.ServerId = {server.server.id} |  | ||||||
|               AND UserMessageCountPerHour.CreatedAt >= "{self._get_date(**server.kwargs)}"; |  | ||||||
|         """ |  | ||||||
|         return self._cast_query_result(query, int) |  | ||||||
|  |  | ||||||
|     def _resolve_voice_channel_count(self, server, *_): |  | ||||||
|         query = f""" |  | ||||||
|             SELECT Count(UserJoinedVoiceChannel.CreatedAt) FROM UserJoinedVoiceChannel |  | ||||||
|             INNER JOIN Users ON UserJoinedVoiceChannel.UserId = Users.UserId |  | ||||||
|             WHERE Users.ServerId = {server.server.id} |  | ||||||
|               AND UserJoinedVoiceChannel.CreatedAt >= "{self._get_date(**server.kwargs)}"; |  | ||||||
|         """ |  | ||||||
|         return self._cast_query_result(query, int) |  | ||||||
|  |  | ||||||
|     def _resolve_voice_channel_ontime(self, server, *_): |  | ||||||
|         query = f""" |  | ||||||
|             SELECT ROUND(SUM(TIME_TO_SEC(TIMEDIFF(UserJoinedVoiceChannel.LeavedOn, UserJoinedVoiceChannel.JoinedOn)) / 3600),{server.server.id}) FROM UserJoinedVoiceChannel |  | ||||||
|             INNER JOIN Users ON UserJoinedVoiceChannel.UserId = Users.UserId |  | ||||||
|             WHERE Users.ServerId = {server.server.id} |  | ||||||
|               AND UserJoinedVoiceChannel.CreatedAt >= "{self._get_date(**server.kwargs)}"; |  | ||||||
|         """ |  | ||||||
|         return self._cast_query_result(query, float) |  | ||||||
|  |  | ||||||
|     def _resolve_game_server_count(self, server, *_): |  | ||||||
|         query = f""" |  | ||||||
|             SELECT Count(UserJoinedGameServer.CreatedAt) FROM UserJoinedGameServer |  | ||||||
|             INNER JOIN Users ON UserJoinedGameServer.UserId = Users.UserId |  | ||||||
|             WHERE Users.ServerId = {server.server.id} |  | ||||||
|               AND UserJoinedGameServer.CreatedAt >= "{self._get_date(**server.kwargs)}"; |  | ||||||
|         """ |  | ||||||
|         return self._cast_query_result(query, int) |  | ||||||
|  |  | ||||||
|     def _resolve_game_server_ontime(self, server, *_): |  | ||||||
|         query = f""" |  | ||||||
|             SELECT ROUND(SUM(TIME_TO_SEC(TIMEDIFF(UserJoinedGameServer.LeavedOn, UserJoinedGameServer.JoinedOn)) / 3600),{server.server.id}) FROM UserJoinedGameServer |  | ||||||
|             INNER JOIN Users ON UserJoinedGameServer.UserId = Users.UserId |  | ||||||
|             WHERE Users.ServerId = {server.server.id} |  | ||||||
|               AND UserJoinedGameServer.CreatedAt >= "{self._get_date(**server.kwargs)}"; |  | ||||||
|         """ |  | ||||||
|         return self._cast_query_result(query, float) |  | ||||||
|  |  | ||||||
|     def _resolve_user_warning_count(self, server, *_): |  | ||||||
|         query = f""" |  | ||||||
|             SELECT COUNT(UserWarnings.CreatedAt) FROM UserWarnings |  | ||||||
|             INNER JOIN Users ON UserWarnings.UserId = Users.UserId |  | ||||||
|             WHERE Users.ServerId = {server.server.id} |  | ||||||
|               AND UserWarnings.CreatedAt >= "{self._get_date(**server.kwargs)}"; |  | ||||||
|         """ |  | ||||||
|         return self._cast_query_result(query, int) |  | ||||||
|  |  | ||||||
|     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_user_count(server, *_) |  | ||||||
|             ) |  | ||||||
|             / days |  | ||||||
|             * 1000 |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     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() |  | ||||||
| @@ -1,11 +0,0 @@ | |||||||
| from bot_graphql.abc.history_query_abc import HistoryQueryABC |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class UserWarningHistoryQuery(HistoryQueryABC): |  | ||||||
|     def __init__(self): |  | ||||||
|         HistoryQueryABC.__init__(self, "UserWarning") |  | ||||||
|  |  | ||||||
|         self.set_field("id", lambda x, *_: x.id) |  | ||||||
|         self.set_field("user", lambda x, *_: x.user) |  | ||||||
|         self.set_field("description", lambda x, *_: x.description) |  | ||||||
|         self.set_field("author", lambda x, *_: x.author) |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| from cpl_core.database.context import DatabaseContextABC |  | ||||||
|  |  | ||||||
| from bot_data.model.user_warnings_history import UserWarningsHistory |  | ||||||
| from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class UserWarningQuery(DataQueryWithHistoryABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         db: DatabaseContextABC, |  | ||||||
|     ): |  | ||||||
|         DataQueryWithHistoryABC.__init__(self, "UserWarning", "UserWarningsHistory", UserWarningsHistory, db) |  | ||||||
|  |  | ||||||
|         self.set_field("id", lambda x, *_: x.id) |  | ||||||
|         self.set_field("user", lambda x, *_: x.user) |  | ||||||
|         self.set_field("description", lambda x, *_: x.description) |  | ||||||
|         self.set_field("author", lambda x, *_: x.author) |  | ||||||
| @@ -1,37 +0,0 @@ | |||||||
| from cpl_discord.command import DiscordCommandABC |  | ||||||
| from discord.ext import commands |  | ||||||
| from discord.ext.commands import Context |  | ||||||
|  |  | ||||||
| from bot_core.helper.command_checks import CommandChecks |  | ||||||
| from bot_core.logging.command_logger import CommandLogger |  | ||||||
| from modules.base.service.event_service import EventService |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ScheduledEventsCommand(DiscordCommandABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         logger: CommandLogger, |  | ||||||
|         events: EventService, |  | ||||||
|     ): |  | ||||||
|         DiscordCommandABC.__init__(self) |  | ||||||
|  |  | ||||||
|         self._logger = logger |  | ||||||
|         self._events = events |  | ||||||
|  |  | ||||||
|         self._logger.trace(__name__, f"Loaded command service: {type(self).__name__}") |  | ||||||
|  |  | ||||||
|     @commands.hybrid_group(name="scheduled-events") |  | ||||||
|     @commands.guild_only() |  | ||||||
|     async def scheduled_events(self, ctx: Context): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     @scheduled_events.command() |  | ||||||
|     @commands.guild_only() |  | ||||||
|     @CommandChecks.check_is_ready() |  | ||||||
|     @CommandChecks.check_is_member_moderator() |  | ||||||
|     async def reload(self, ctx: Context): |  | ||||||
|         self._logger.debug(__name__, "Running scheduled-events reload") |  | ||||||
|         try: |  | ||||||
|             await self._events.check_and_create_scheduled_events(ctx.guild) |  | ||||||
|         except Exception as e: |  | ||||||
|             self._logger.error(__name__, f"Reloading scheduled events failed", e) |  | ||||||
| @@ -1,143 +0,0 @@ | |||||||
| import calendar |  | ||||||
| from datetime import datetime, timedelta |  | ||||||
| from typing import Optional |  | ||||||
| from zoneinfo import ZoneInfo |  | ||||||
|  |  | ||||||
| import discord |  | ||||||
| from cpl_core.configuration import ConfigurationABC |  | ||||||
| from cpl_core.database.context import DatabaseContextABC |  | ||||||
| from cpl_core.logging import LoggerABC |  | ||||||
| from cpl_discord.container import Guild |  | ||||||
| from cpl_query.extension import List |  | ||||||
| from discord import PrivacyLevel |  | ||||||
| from discord.scheduled_event import ScheduledEvent as DiscordEvent |  | ||||||
|  |  | ||||||
| from bot_data.abc.scheduled_event_repository_abc import ScheduledEventRepositoryABC |  | ||||||
| from bot_data.abc.server_repository_abc import ServerRepositoryABC |  | ||||||
| from bot_data.abc.user_repository_abc import UserRepositoryABC |  | ||||||
| from bot_data.model.scheduled_event import ScheduledEvent |  | ||||||
| from bot_data.model.scheduled_event_interval_enum import ScheduledEventIntervalEnum |  | ||||||
| from bot_data.model.server_config import ServerConfig |  | ||||||
| from modules.base.model.active_event import ActiveEvent |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class EventService: |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         config: ConfigurationABC, |  | ||||||
|         logger: LoggerABC, |  | ||||||
|         servers: ServerRepositoryABC, |  | ||||||
|         users: UserRepositoryABC, |  | ||||||
|         db: DatabaseContextABC, |  | ||||||
|         events: ScheduledEventRepositoryABC, |  | ||||||
|     ): |  | ||||||
|         self._config = config |  | ||||||
|         self._logger = logger |  | ||||||
|         self._servers = servers |  | ||||||
|         self._users = users |  | ||||||
|         self._db = db |  | ||||||
|         self._events = events |  | ||||||
|  |  | ||||||
|         self._active_events = List(ActiveEvent) |  | ||||||
|  |  | ||||||
|     def add_event(self, event: ActiveEvent): |  | ||||||
|         if self._active_events.contains(event): |  | ||||||
|             return |  | ||||||
|  |  | ||||||
|         self._active_events.add(event) |  | ||||||
|  |  | ||||||
|     def get_active_event(self, event: discord.ScheduledEvent) -> Optional[ActiveEvent]: |  | ||||||
|         return self._active_events.where(lambda x: x.event.id == event.id).single_or_default() |  | ||||||
|  |  | ||||||
|     def get_active_event_by_channel_id(self, channel_id: int) -> Optional[ActiveEvent]: |  | ||||||
|         return self._active_events.where( |  | ||||||
|             lambda x: x.event.channel is not None and x.event.channel.id == channel_id |  | ||||||
|         ).single_or_default() |  | ||||||
|  |  | ||||||
|     def remove_event(self, event: ActiveEvent): |  | ||||||
|         if not self._active_events.contains(event): |  | ||||||
|             return |  | ||||||
|  |  | ||||||
|         self._active_events.remove(event) |  | ||||||
|  |  | ||||||
|     def give_xp_for_event_participation(self, member: discord.Member, active_event: ActiveEvent): |  | ||||||
|         server = self._servers.get_server_by_discord_id(member.guild.id) |  | ||||||
|         user = self._users.get_user_by_discord_id_and_server_id(member.id, server.id) |  | ||||||
|         if active_event.participants.any(lambda x: x.id == user.id): |  | ||||||
|             self._logger.debug(__name__, f"Module {type(self)} stopped") |  | ||||||
|             return |  | ||||||
|  |  | ||||||
|         settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{server.discord_id}") |  | ||||||
|         user.xp += settings.xp_per_event_participation |  | ||||||
|         self._users.update_user(user) |  | ||||||
|         self._db.save_changes() |  | ||||||
|         active_event.participants.append(user) |  | ||||||
|  |  | ||||||
|     def _append_interval(self, interval: ScheduledEventIntervalEnum, ts: datetime) -> datetime: |  | ||||||
|         now = datetime.now().replace(tzinfo=ZoneInfo("Europe/Berlin")) |  | ||||||
|         if ts >= now: |  | ||||||
|             return ts |  | ||||||
|  |  | ||||||
|         if interval == ScheduledEventIntervalEnum.daily: |  | ||||||
|             ts = ts + timedelta(days=1) |  | ||||||
|  |  | ||||||
|         elif interval == ScheduledEventIntervalEnum.weekly: |  | ||||||
|             ts = ts + timedelta(weeks=1) |  | ||||||
|  |  | ||||||
|         elif interval == ScheduledEventIntervalEnum.monthly: |  | ||||||
|             days_in_month = calendar.monthrange(ts.year, ts.month + 1)[1] |  | ||||||
|             ts = ts + timedelta(days=days_in_month) |  | ||||||
|  |  | ||||||
|         elif interval == ScheduledEventIntervalEnum.yearly: |  | ||||||
|             ts = ts + timedelta(days=365) |  | ||||||
|  |  | ||||||
|         while ts < now: |  | ||||||
|             ts = self._append_interval(interval, ts) |  | ||||||
|  |  | ||||||
|         return ts |  | ||||||
|  |  | ||||||
|     async def check_and_create_scheduled_events(self, guild: Guild): |  | ||||||
|         server = self._servers.get_server_by_discord_id(guild.id) |  | ||||||
|         scheduled_events_from_db = self._events.get_scheduled_events_by_server_id(server.id) |  | ||||||
|         for scheduled_event in scheduled_events_from_db: |  | ||||||
|             scheduled_event: ScheduledEvent = scheduled_event |  | ||||||
|             from_guild = List(DiscordEvent, guild.scheduled_events).where( |  | ||||||
|                 lambda x: x.name == scheduled_event.name |  | ||||||
|                 and x.description == scheduled_event.description |  | ||||||
|                 and x.entity_type == scheduled_event.entity_type |  | ||||||
|             ) |  | ||||||
|             if from_guild.count() != 0: |  | ||||||
|                 continue |  | ||||||
|  |  | ||||||
|             kwargs = {"name": scheduled_event.name, "description": scheduled_event.description} |  | ||||||
|  |  | ||||||
|             if scheduled_event.channel_id is not None: |  | ||||||
|                 kwargs["channel"] = guild.get_channel(scheduled_event.channel_id) |  | ||||||
|  |  | ||||||
|             if scheduled_event.start_time is not None: |  | ||||||
|                 start_time = self._append_interval( |  | ||||||
|                     scheduled_event.interval, scheduled_event.start_time.replace(tzinfo=ZoneInfo("Europe/Berlin")) |  | ||||||
|                 ) |  | ||||||
|                 kwargs["start_time"] = start_time |  | ||||||
|                 scheduled_event.start_time = scheduled_event.start_time.replace(tzinfo=None) |  | ||||||
|  |  | ||||||
|             if scheduled_event.end_time is not None: |  | ||||||
|                 end_time = self._append_interval( |  | ||||||
|                     scheduled_event.interval, scheduled_event.end_time.replace(tzinfo=ZoneInfo("Europe/Berlin")) |  | ||||||
|                 ) |  | ||||||
|                 kwargs["end_time"] = end_time |  | ||||||
|                 scheduled_event.end_time = scheduled_event.end_time.replace(tzinfo=None) |  | ||||||
|  |  | ||||||
|             kwargs["entity_type"] = scheduled_event.entity_type |  | ||||||
|             if scheduled_event.location is not None: |  | ||||||
|                 kwargs["location"] = scheduled_event.location |  | ||||||
|  |  | ||||||
|             kwargs["privacy_level"] = PrivacyLevel.guild_only |  | ||||||
|  |  | ||||||
|             try: |  | ||||||
|                 self._logger.debug(__name__, f"Try to create scheduled event for guild {guild.name}") |  | ||||||
|                 await guild.create_scheduled_event(**kwargs) |  | ||||||
|                 self._events.update_scheduled_event(scheduled_event) |  | ||||||
|                 self._db.save_changes() |  | ||||||
|             except Exception as e: |  | ||||||
|                 self._logger.error(__name__, f"Watching scheduled events failed", e) |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
|  |  | ||||||
| """ |  | ||||||
| bot sh-edraft.de Discord bot |  | ||||||
| ~~~~~~~~~~~~~~~~~~~ |  | ||||||
|  |  | ||||||
| Discord bot for customers of sh-edraft.de |  | ||||||
|  |  | ||||||
| :copyright: (c) 2022 - 2023 sh-edraft.de |  | ||||||
| :license: MIT, see LICENSE for more details. |  | ||||||
|  |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| __title__ = "modules.base.tasks" |  | ||||||
| __author__ = "Sven Heidemann" |  | ||||||
| __license__ = "MIT" |  | ||||||
| __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" |  | ||||||
| __version__ = "1.2.2" |  | ||||||
|  |  | ||||||
| from collections import namedtuple |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # imports: |  | ||||||
|  |  | ||||||
| VersionInfo = namedtuple("VersionInfo", "major minor micro") |  | ||||||
| version_info = VersionInfo(major="1", minor="2", micro="2") |  | ||||||
| @@ -1,68 +0,0 @@ | |||||||
| import datetime |  | ||||||
|  |  | ||||||
| from cpl_core.configuration import ConfigurationABC |  | ||||||
| from cpl_core.database.context import DatabaseContextABC |  | ||||||
| from cpl_discord.service import DiscordBotServiceABC |  | ||||||
| from cpl_translation import TranslatePipe |  | ||||||
| from discord.ext import tasks |  | ||||||
|  |  | ||||||
| from bot_core.abc.task_abc import TaskABC |  | ||||||
| from bot_core.logging.task_logger import TaskLogger |  | ||||||
| from bot_core.service.message_service import MessageService |  | ||||||
| from bot_data.abc.user_repository_abc import UserRepositoryABC |  | ||||||
| from bot_data.model.server_config import ServerConfig |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class BirthdayWatcher(TaskABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         config: ConfigurationABC, |  | ||||||
|         logger: TaskLogger, |  | ||||||
|         bot: DiscordBotServiceABC, |  | ||||||
|         db: DatabaseContextABC, |  | ||||||
|         users: UserRepositoryABC, |  | ||||||
|         message_service: MessageService, |  | ||||||
|         t: TranslatePipe, |  | ||||||
|     ): |  | ||||||
|         TaskABC.__init__(self) |  | ||||||
|  |  | ||||||
|         self._config = config |  | ||||||
|         self._logger = logger |  | ||||||
|         self._bot = bot |  | ||||||
|         self._db = db |  | ||||||
|         self._users = users |  | ||||||
|         self._message_service = message_service |  | ||||||
|         self._t = t |  | ||||||
|  |  | ||||||
|         if not self._is_maintenance(): |  | ||||||
|             self.watch.start() |  | ||||||
|  |  | ||||||
|     @tasks.loop(time=datetime.time(hour=8, minute=0)) |  | ||||||
|     async def watch(self): |  | ||||||
|         self._logger.info(__name__, "Watching birthdays") |  | ||||||
|         try: |  | ||||||
|             today = datetime.date.today() |  | ||||||
|             users = self._users.get_users().where(lambda x: x.birthday is not None) |  | ||||||
|             for user in users: |  | ||||||
|                 if user.birthday.day != today.day or user.birthday.month != today.month: |  | ||||||
|                     continue |  | ||||||
|  |  | ||||||
|                 settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{user.server.discord_id}") |  | ||||||
|  |  | ||||||
|                 user.xp += settings.xp_for_birthday |  | ||||||
|                 self._users.update_user(user) |  | ||||||
|                 self._db.save_changes() |  | ||||||
|  |  | ||||||
|                 guild = self._bot.get_guild(user.server.discord_id) |  | ||||||
|                 member = guild.get_member(user.discord_id) |  | ||||||
|                 await self._message_service.send_channel_message( |  | ||||||
|                     self._bot.get_channel(settings.notification_chat_id), |  | ||||||
|                     self._t.transform("modules.base.user.birthday.has_birthday").format(member.mention), |  | ||||||
|                     is_persistent=True, |  | ||||||
|                 ) |  | ||||||
|         except Exception as e: |  | ||||||
|             self._logger.error(__name__, f"Watching birthdays failed", e) |  | ||||||
|  |  | ||||||
|     @watch.before_loop |  | ||||||
|     async def wait(self): |  | ||||||
|         await self._wait_until_ready() |  | ||||||
| @@ -1,51 +0,0 @@ | |||||||
| from cpl_core.configuration import ConfigurationABC |  | ||||||
| from cpl_core.database.context import DatabaseContextABC |  | ||||||
| from cpl_discord.service import DiscordBotServiceABC |  | ||||||
| from cpl_translation import TranslatePipe |  | ||||||
| from discord.ext import tasks |  | ||||||
|  |  | ||||||
| from bot_core.abc.task_abc import TaskABC |  | ||||||
| from bot_core.logging.task_logger import TaskLogger |  | ||||||
| from bot_core.service.message_service import MessageService |  | ||||||
| from bot_data.abc.server_repository_abc import ServerRepositoryABC |  | ||||||
| from modules.base.service.event_service import EventService |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ScheduledEventsWatcher(TaskABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         config: ConfigurationABC, |  | ||||||
|         logger: TaskLogger, |  | ||||||
|         bot: DiscordBotServiceABC, |  | ||||||
|         db: DatabaseContextABC, |  | ||||||
|         servers: ServerRepositoryABC, |  | ||||||
|         events: EventService, |  | ||||||
|         message_service: MessageService, |  | ||||||
|         t: TranslatePipe, |  | ||||||
|     ): |  | ||||||
|         TaskABC.__init__(self) |  | ||||||
|  |  | ||||||
|         self._config = config |  | ||||||
|         self._logger = logger |  | ||||||
|         self._bot = bot |  | ||||||
|         self._db = db |  | ||||||
|         self._servers = servers |  | ||||||
|         self._events = events |  | ||||||
|         self._message_service = message_service |  | ||||||
|         self._t = t |  | ||||||
|  |  | ||||||
|         if not self._is_maintenance(): |  | ||||||
|             self.watch.start() |  | ||||||
|  |  | ||||||
|     @tasks.loop(hours=12) |  | ||||||
|     async def watch(self): |  | ||||||
|         self._logger.info(__name__, "Watching scheduled events") |  | ||||||
|         try: |  | ||||||
|             for guild in self._bot.guilds: |  | ||||||
|                 await self._events.check_and_create_scheduled_events(guild) |  | ||||||
|         except Exception as e: |  | ||||||
|             self._logger.error(__name__, f"Watching scheduled events failed", e) |  | ||||||
|  |  | ||||||
|     @watch.before_loop |  | ||||||
|     async def wait(self): |  | ||||||
|         await self._wait_until_ready() |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| { |  | ||||||
|   "DefaultLevel": { |  | ||||||
|     "LevelHeader": "~~~ dev-Level ~~~", |  | ||||||
|     "Levels": [ |  | ||||||
|       { |  | ||||||
|         "Name": "dev-Newbie", |  | ||||||
|         "Color": "0x1abc9c", |  | ||||||
|         "MinXp": 0, |  | ||||||
|         "Permissions": 968552209984 |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         "Name": "dev-Keks", |  | ||||||
|         "Color": "0x2ecc71", |  | ||||||
|         "MinXp": 100, |  | ||||||
|         "Permissions": 1002928856640 |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         "Name": "dev-Doppelkeks", |  | ||||||
|         "Color": "0x3498db", |  | ||||||
|         "MinXp": 200, |  | ||||||
|         "Permissions": 1071849660224 |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         "Name": "dev-Auror", |  | ||||||
|         "Color": "0xf1c40f", |  | ||||||
|         "MinXp": 300, |  | ||||||
|         "Permissions": 1089042120513 |  | ||||||
|       } |  | ||||||
|     ] |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| { |  | ||||||
|   "DefaultLevel": { |  | ||||||
|     "LevelHeader": "~~~ ed-Level ~~~", |  | ||||||
|     "Levels": [ |  | ||||||
|       { |  | ||||||
|         "Name": "ed-Newbie", |  | ||||||
|         "Color": "0x1abc9c", |  | ||||||
|         "MinXp": 0, |  | ||||||
|         "Permissions": 968552209984 |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         "Name": "ed-Keks", |  | ||||||
|         "Color": "0x2ecc71", |  | ||||||
|         "MinXp": 100, |  | ||||||
|         "Permissions": 1002928856640 |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         "Name": "ed-Doppelkeks", |  | ||||||
|         "Color": "0x3498db", |  | ||||||
|         "MinXp": 200, |  | ||||||
|         "Permissions": 1071849660224 |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         "Name": "ed-Auror", |  | ||||||
|         "Color": "0xf1c40f", |  | ||||||
|         "MinXp": 300, |  | ||||||
|         "Permissions": 1089042120513 |  | ||||||
|       } |  | ||||||
|     ] |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| { |  | ||||||
|   "DefaultLevel": { |  | ||||||
|     "LevelHeader": "~~~ ed-Level ~~~", |  | ||||||
|     "Levels": [ |  | ||||||
|       { |  | ||||||
|         "Name": "ed-Newbie", |  | ||||||
|         "Color": "0x1abc9c", |  | ||||||
|         "MinXp": 0, |  | ||||||
|         "Permissions": 968552209984 |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         "Name": "ed-Keks", |  | ||||||
|         "Color": "0x2ecc71", |  | ||||||
|         "MinXp": 100, |  | ||||||
|         "Permissions": 1002928856640 |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         "Name": "ed-Doppelkeks", |  | ||||||
|         "Color": "0x3498db", |  | ||||||
|         "MinXp": 200, |  | ||||||
|         "Permissions": 1071849660224 |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         "Name": "ed-Auror", |  | ||||||
|         "Color": "0xf1c40f", |  | ||||||
|         "MinXp": 300, |  | ||||||
|         "Permissions": 1089042120513 |  | ||||||
|       } |  | ||||||
|     ] |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| { |  | ||||||
|   "DefaultLevel": { |  | ||||||
|     "LevelHeader": "~~~ test-Level ~~~", |  | ||||||
|     "Levels": [ |  | ||||||
|       { |  | ||||||
|         "Name": "test-Newbie", |  | ||||||
|         "Color": "0x1abc9c", |  | ||||||
|         "MinXp": 0, |  | ||||||
|         "Permissions": 968552209984 |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         "Name": "test-Keks", |  | ||||||
|         "Color": "0x2ecc71", |  | ||||||
|         "MinXp": 100, |  | ||||||
|         "Permissions": 1002928856640 |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         "Name": "test-Doppelkeks", |  | ||||||
|         "Color": "0x3498db", |  | ||||||
|         "MinXp": 200, |  | ||||||
|         "Permissions": 1071849660224 |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         "Name": "test-Auror", |  | ||||||
|         "Color": "0xf1c40f", |  | ||||||
|         "MinXp": 300, |  | ||||||
|         "Permissions": 1089042120513 |  | ||||||
|       } |  | ||||||
|     ] |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,74 +0,0 @@ | |||||||
| import discord |  | ||||||
| from cpl_core.configuration import ConfigurationABC |  | ||||||
| from cpl_core.logging import LoggerABC |  | ||||||
| from cpl_discord.service import DiscordBotServiceABC |  | ||||||
|  |  | ||||||
| from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC |  | ||||||
| from bot_data.abc.server_repository_abc import ServerRepositoryABC |  | ||||||
| from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC |  | ||||||
| from bot_data.model.team_member_type_enum import TeamMemberTypeEnum |  | ||||||
| from modules.permission.abc.permission_service_abc import PermissionServiceABC |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class PermissionService(PermissionServiceABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         logger: LoggerABC, |  | ||||||
|         bot: DiscordBotServiceABC, |  | ||||||
|         config: ConfigurationABC, |  | ||||||
|         servers: ServerRepositoryABC, |  | ||||||
|         server_configs: ServerConfigRepositoryABC, |  | ||||||
|         technician_configs: TechnicianConfigRepositoryABC, |  | ||||||
|     ): |  | ||||||
|         PermissionServiceABC.__init__(self) |  | ||||||
|         self._logger = logger |  | ||||||
|         self._bot = bot |  | ||||||
|         self._config = config |  | ||||||
|         self._servers = servers |  | ||||||
|         self._server_configs = server_configs |  | ||||||
|         self._technician_configs = technician_configs |  | ||||||
|  |  | ||||||
|     def _has_member_role(self, member: discord.Member, team_member_type: TeamMemberTypeEnum) -> bool: |  | ||||||
|         if member is None or member.guild is None: |  | ||||||
|             return False |  | ||||||
|  |  | ||||||
|         self._logger.debug(__name__, f"Checking is member {member.name} {team_member_type.value}") |  | ||||||
|  |  | ||||||
|         try: |  | ||||||
|             server = self._servers.get_server_by_discord_id(member.guild.id) |  | ||||||
|             config = self._server_configs.get_server_config_by_server(server.id) |  | ||||||
|             roles = config.team_role_ids.where(lambda x: x.team_member_type == team_member_type).select( |  | ||||||
|                 lambda x: member.guild.get_role(x.role_id) |  | ||||||
|             ) |  | ||||||
|             for role in roles: |  | ||||||
|                 if role not in member.roles: |  | ||||||
|                     continue |  | ||||||
|  |  | ||||||
|                 return True |  | ||||||
|         except Exception as e: |  | ||||||
|             self._logger.error(__name__, "Permission check failed", e) |  | ||||||
|  |  | ||||||
|         return False |  | ||||||
|  |  | ||||||
|     def is_member_admin(self, member: discord.Member) -> bool: |  | ||||||
|         return self._has_member_role(member, TeamMemberTypeEnum.admin) |  | ||||||
|  |  | ||||||
|     def is_member_moderator(self, member: discord.Member) -> bool: |  | ||||||
|         return self._has_member_role(member, TeamMemberTypeEnum.moderator) or self._has_member_role( |  | ||||||
|             member, TeamMemberTypeEnum.admin |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     def is_member_technician(self, member: discord.Member) -> bool: |  | ||||||
|         if member is None or member.guild is None: |  | ||||||
|             return False |  | ||||||
|  |  | ||||||
|         self._logger.debug(__name__, f"Checking is member {member.name} technician") |  | ||||||
|  |  | ||||||
|         try: |  | ||||||
|             tech_config = self._technician_configs.get_technician_config() |  | ||||||
|             if member.id in tech_config.technician_ids: |  | ||||||
|                 return True |  | ||||||
|         except Exception as e: |  | ||||||
|             self._logger.error(__name__, "Permission check failed", e) |  | ||||||
|  |  | ||||||
|         return False |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
|  |  | ||||||
| """ |  | ||||||
| bot sh-edraft.de Discord bot |  | ||||||
| ~~~~~~~~~~~~~~~~~~~ |  | ||||||
|  |  | ||||||
| Discord bot for customers of sh-edraft.de |  | ||||||
|  |  | ||||||
| :copyright: (c) 2022 - 2023 sh-edraft.de |  | ||||||
| :license: MIT, see LICENSE for more details. |  | ||||||
|  |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| __title__ = "modules.special_offers" |  | ||||||
| __author__ = "Sven Heidemann" |  | ||||||
| __license__ = "MIT" |  | ||||||
| __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" |  | ||||||
| __version__ = "1.2.2" |  | ||||||
|  |  | ||||||
| from collections import namedtuple |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # imports |  | ||||||
|  |  | ||||||
| VersionInfo = namedtuple("VersionInfo", "major minor micro") |  | ||||||
| version_info = VersionInfo(major="1", minor="2", micro="2") |  | ||||||
| @@ -1,46 +0,0 @@ | |||||||
| { |  | ||||||
|   "ProjectSettings": { |  | ||||||
|     "Name": "steam-special-offers", |  | ||||||
|     "Version": { |  | ||||||
|       "Major": "1", |  | ||||||
|       "Minor": "2", |  | ||||||
|       "Micro": "2" |  | ||||||
|     }, |  | ||||||
|     "Author": "", |  | ||||||
|     "AuthorEmail": "", |  | ||||||
|     "Description": "", |  | ||||||
|     "LongDescription": "", |  | ||||||
|     "URL": "", |  | ||||||
|     "CopyrightDate": "", |  | ||||||
|     "CopyrightName": "", |  | ||||||
|     "LicenseName": "", |  | ||||||
|     "LicenseDescription": "", |  | ||||||
|     "Dependencies": [ |  | ||||||
|       "cpl-core>=1.2.dev410" |  | ||||||
|     ], |  | ||||||
|     "DevDependencies": [ |  | ||||||
|       "cpl-cli>=1.2.dev410" |  | ||||||
|     ], |  | ||||||
|     "PythonVersion": ">=3.10.4", |  | ||||||
|     "PythonPath": { |  | ||||||
|       "linux": "" |  | ||||||
|     }, |  | ||||||
|     "Classifiers": [] |  | ||||||
|   }, |  | ||||||
|   "BuildSettings": { |  | ||||||
|     "ProjectType": "library", |  | ||||||
|     "SourcePath": "", |  | ||||||
|     "OutputPath": "../../dist", |  | ||||||
|     "Main": "steam_special_offers.main", |  | ||||||
|     "EntryPoint": "steam-special-offers", |  | ||||||
|     "IncludePackageData": false, |  | ||||||
|     "Included": [], |  | ||||||
|     "Excluded": [ |  | ||||||
|       "*/__pycache__", |  | ||||||
|       "*/logs", |  | ||||||
|       "*/tests" |  | ||||||
|     ], |  | ||||||
|     "PackageData": {}, |  | ||||||
|     "ProjectReferences": [] |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,22 +0,0 @@ | |||||||
| from cpl_core.configuration import ConfigurationABC |  | ||||||
| from cpl_core.dependency_injection import ServiceCollectionABC |  | ||||||
| from cpl_core.environment import ApplicationEnvironmentABC |  | ||||||
| from cpl_discord.service.discord_collection_abc import DiscordCollectionABC |  | ||||||
|  |  | ||||||
| from bot_core.abc.module_abc import ModuleABC |  | ||||||
| from bot_core.abc.task_abc import TaskABC |  | ||||||
| from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum |  | ||||||
| from modules.special_offers.steam_offer_watcher import SteamOfferWatcher |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class SteamSpecialOffersModule(ModuleABC): |  | ||||||
|     def __init__(self, dc: DiscordCollectionABC): |  | ||||||
|         ModuleABC.__init__(self, dc, FeatureFlagsEnum.steam_special_offers_module) |  | ||||||
|  |  | ||||||
|     def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC): |  | ||||||
|         services.add_singleton(TaskABC, SteamOfferWatcher) |  | ||||||
|         # commands |  | ||||||
|         # events |  | ||||||
| @@ -1,220 +0,0 @@ | |||||||
| import asyncio |  | ||||||
| import datetime |  | ||||||
|  |  | ||||||
| import bs4 |  | ||||||
| import discord |  | ||||||
| import requests |  | ||||||
| from cpl_core.configuration import ConfigurationABC |  | ||||||
| from cpl_core.database.context import DatabaseContextABC |  | ||||||
| from cpl_discord.service import DiscordBotServiceABC |  | ||||||
| from cpl_query.extension import List |  | ||||||
| from cpl_translation import TranslatePipe |  | ||||||
| from discord.ext import tasks |  | ||||||
|  |  | ||||||
| from bot_core.abc.task_abc import TaskABC |  | ||||||
| from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum |  | ||||||
| from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings |  | ||||||
| from bot_core.logging.task_logger import TaskLogger |  | ||||||
| from bot_core.service.message_service import MessageService |  | ||||||
| from bot_data.abc.steam_special_offer_repository_abc import ( |  | ||||||
|     SteamSpecialOfferRepositoryABC, |  | ||||||
| ) |  | ||||||
| from bot_data.model.server_config import ServerConfig |  | ||||||
| from bot_data.model.steam_special_offer import SteamSpecialOffer |  | ||||||
| from bot_data.model.technician_config import TechnicianConfig |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class SteamOfferWatcher(TaskABC): |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         config: ConfigurationABC, |  | ||||||
|         bot: DiscordBotServiceABC, |  | ||||||
|         logger: TaskLogger, |  | ||||||
|         db: DatabaseContextABC, |  | ||||||
|         offers: SteamSpecialOfferRepositoryABC, |  | ||||||
|         message_service: MessageService, |  | ||||||
|         t: TranslatePipe, |  | ||||||
|         tech_config: TechnicianConfig, |  | ||||||
|     ): |  | ||||||
|         TaskABC.__init__(self) |  | ||||||
|  |  | ||||||
|         self._config = config |  | ||||||
|         self._logger = logger |  | ||||||
|         self._db = db |  | ||||||
|         self._offers = offers |  | ||||||
|         self._bot = bot |  | ||||||
|         self._message_service = message_service |  | ||||||
|         self._t = t |  | ||||||
|         self._tech_config = tech_config |  | ||||||
|  |  | ||||||
|         self._is_new = False |  | ||||||
|         self._urls = {} |  | ||||||
|         self._image_urls = {} |  | ||||||
|  |  | ||||||
|         if not self._is_maintenance(): |  | ||||||
|             self.watch.start() |  | ||||||
|  |  | ||||||
|     @staticmethod |  | ||||||
|     def _get_max_count() -> int: |  | ||||||
|         count = 0 |  | ||||||
|         result = requests.get(f"https://store.steampowered.com/search/results?specials=1") |  | ||||||
|         soup = bs4.BeautifulSoup(result.text, "lxml") |  | ||||||
|         element = soup.find_all("div", {"class": "search_results_count"}) |  | ||||||
|         if len(element) < 1: |  | ||||||
|             return count |  | ||||||
|  |  | ||||||
|         count = int(element[0].contents[0].split(" ")[0].replace(",", "")) |  | ||||||
|  |  | ||||||
|         return count |  | ||||||
|  |  | ||||||
|     def _get_games_from_page(self, start: int, count: int) -> List[SteamSpecialOffer]: |  | ||||||
|         games = List(SteamSpecialOffer) |  | ||||||
|         result = requests.get( |  | ||||||
|             f"https://store.steampowered.com/search/results?query&start={start}&count={count}&force_infinite=1&specials=1&filter=topsellers" |  | ||||||
|         ) |  | ||||||
|         soup = bs4.BeautifulSoup(result.text, "lxml") |  | ||||||
|         elements = soup.find_all("a", {"class": "search_result_row"}) |  | ||||||
|         if len(elements) < 1: |  | ||||||
|             return games |  | ||||||
|  |  | ||||||
|         for element in elements: |  | ||||||
|             name_element = element.find("span", {"class": "title"}) |  | ||||||
|             original_price_element = element.find("div", {"class": "discount_original_price"}) |  | ||||||
|             discount_element = element.find("div", {"class": "discount_pct"}) |  | ||||||
|             discount_price_element = element.find("div", {"class": "discount_final_price"}) |  | ||||||
|  |  | ||||||
|             if ( |  | ||||||
|                 name_element is None |  | ||||||
|                 or len(name_element.contents) < 1 |  | ||||||
|                 or original_price_element is None |  | ||||||
|                 or len(original_price_element.contents) < 1 |  | ||||||
|                 or discount_element is None |  | ||||||
|                 or len(discount_element.contents) < 1 |  | ||||||
|                 or discount_price_element is None |  | ||||||
|                 or len(discount_price_element.contents) < 1 |  | ||||||
|             ): |  | ||||||
|                 continue |  | ||||||
|  |  | ||||||
|             name = name_element.contents[0].replace("'", "`").replace('"', "`") |  | ||||||
|             original_price = float( |  | ||||||
|                 original_price_element.contents[0].replace(" ", "").replace("€", "").replace(",", ".") |  | ||||||
|             ) |  | ||||||
|             discount = int(discount_element.contents[0].replace("%", "")) |  | ||||||
|             discount_price = float( |  | ||||||
|                 discount_price_element.contents[0].replace(" ", "").replace("€", "").replace(",", ".") |  | ||||||
|             ) |  | ||||||
|             games.add(SteamSpecialOffer(name, original_price, discount_price, discount)) |  | ||||||
|             self._urls[name] = element.attrs["href"] |  | ||||||
|             self._image_urls[name] = element.find("div", {"class": "search_capsule"}).find("img").attrs["src"] |  | ||||||
|  |  | ||||||
|         return games |  | ||||||
|  |  | ||||||
|     def _get_new_game_offers(self) -> List[SteamSpecialOffer]: |  | ||||||
|         new_offers = List(SteamSpecialOffer) |  | ||||||
|  |  | ||||||
|         sale_count = self._tech_config.max_steam_offer_count |  | ||||||
|         # todo: let admins change the value |  | ||||||
|         self._logger.debug(__name__, f"Get special offers from 0 to {sale_count}") |  | ||||||
|         for i in range(0, sale_count, 100): |  | ||||||
|             if i > sale_count: |  | ||||||
|                 break |  | ||||||
|             new_offers.extend(self._get_games_from_page(i, 100)) |  | ||||||
|  |  | ||||||
|         self._logger.debug(__name__, f"Got {new_offers.count()} offers") |  | ||||||
|  |  | ||||||
|         return new_offers |  | ||||||
|  |  | ||||||
|     async def _send_embed_for_offer(self, offer: SteamSpecialOffer, channel_id: int) -> discord.Embed: |  | ||||||
|         embed = discord.Embed( |  | ||||||
|             title=offer.name, |  | ||||||
|             url=self._urls[offer.name], |  | ||||||
|             color=int("ef9d0d", 16), |  | ||||||
|             timestamp=datetime.datetime.now(), |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|         embed.add_field( |  | ||||||
|             name=self._t.transform("modules.special_offers.price"), |  | ||||||
|             value=f"~~{offer.original_price}€~~", |  | ||||||
|             inline=True, |  | ||||||
|         ) |  | ||||||
|         embed.add_field( |  | ||||||
|             name=self._t.transform("modules.special_offers.discount"), |  | ||||||
|             value=f"{offer.discount_pct}%", |  | ||||||
|             inline=True, |  | ||||||
|         ) |  | ||||||
|         embed.add_field( |  | ||||||
|             name=self._t.transform("modules.special_offers.discount_price"), |  | ||||||
|             value=f"{offer.discount_price}€", |  | ||||||
|             inline=True, |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|         embed.set_image(url=self._image_urls[offer.name]) |  | ||||||
|  |  | ||||||
|         await self._message_service.send_channel_message( |  | ||||||
|             self._bot.get_channel(channel_id), |  | ||||||
|             embed, |  | ||||||
|             is_persistent=True, |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     def _watch(self) -> List[SteamSpecialOffer]: |  | ||||||
|         self._is_new = self._offers.get_steam_special_offers().count() == 0 |  | ||||||
|         new_offers = self._get_new_game_offers() |  | ||||||
|         new_offers_names = new_offers.select(lambda x: x.name).to_list() |  | ||||||
|  |  | ||||||
|         old_offers = self._offers.get_steam_special_offers() |  | ||||||
|         old_offers_names = old_offers.select(lambda x: x.name).to_list() |  | ||||||
|  |  | ||||||
|         offers_for_notifications = List(SteamSpecialOffer) |  | ||||||
|  |  | ||||||
|         for offer in old_offers: |  | ||||||
|             offer: SteamSpecialOffer = offer |  | ||||||
|             if offer.name in new_offers_names: |  | ||||||
|                 continue |  | ||||||
|  |  | ||||||
|             self._offers.delete_steam_special_offer(offer) |  | ||||||
|             self._db.save_changes() |  | ||||||
|  |  | ||||||
|         for offer in new_offers: |  | ||||||
|             if offer.name in old_offers_names: |  | ||||||
|                 self._offers.update_steam_special_offer(offer) |  | ||||||
|                 self._db.save_changes() |  | ||||||
|                 continue |  | ||||||
|  |  | ||||||
|             self._offers.add_steam_special_offer(offer) |  | ||||||
|             self._db.save_changes() |  | ||||||
|             offers_for_notifications.add(offer) |  | ||||||
|  |  | ||||||
|         self._logger.trace(__name__, "Finished watching") |  | ||||||
|         return offers_for_notifications |  | ||||||
|  |  | ||||||
|     @tasks.loop(hours=4) |  | ||||||
|     async def watch(self): |  | ||||||
|         self._logger.info(__name__, "Watching steam special offers") |  | ||||||
|         try: |  | ||||||
|             offers_for_notifications = self._watch() |  | ||||||
|             self._logger.debug( |  | ||||||
|                 __name__, |  | ||||||
|                 f"Sending offer notifications for {offers_for_notifications.count()} offers", |  | ||||||
|             ) |  | ||||||
|             if self._is_new: |  | ||||||
|                 return |  | ||||||
|             for guild in self._bot.guilds: |  | ||||||
|                 settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{guild.id}") |  | ||||||
|                 if ( |  | ||||||
|                     not FeatureFlagsSettings.get_flag_from_dict( |  | ||||||
|                         settings.feature_flags, FeatureFlagsEnum.steam_special_offers |  | ||||||
|                     ) |  | ||||||
|                     or settings.game_offer_notification_chat_id is None |  | ||||||
|                 ): |  | ||||||
|                     continue |  | ||||||
|  |  | ||||||
|                 for offer in offers_for_notifications: |  | ||||||
|                     self._bot.loop.create_task( |  | ||||||
|                         self._send_embed_for_offer(offer, settings.game_offer_notification_chat_id) |  | ||||||
|                     ) |  | ||||||
|         except Exception as e: |  | ||||||
|             self._logger.error(__name__, f"Steam offer watcher failed", e) |  | ||||||
|  |  | ||||||
|     @watch.before_loop |  | ||||||
|     async def wait(self): |  | ||||||
|         await self._wait_until_ready() |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| # imports |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| from cpl_core.application import ApplicationABC |  | ||||||
| from cpl_core.configuration import ConfigurationABC |  | ||||||
| from cpl_core.console import Console |  | ||||||
| from cpl_core.dependency_injection import ServiceProviderABC |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class Application(ApplicationABC): |  | ||||||
|     def __init__(self, config: ConfigurationABC, services: ServiceProviderABC): |  | ||||||
|         ApplicationABC.__init__(self, config, services) |  | ||||||
|  |  | ||||||
|     async def configure(self): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     async def main(self): |  | ||||||
|         Console.write_line("Finished") |  | ||||||
| @@ -1,22 +0,0 @@ | |||||||
| { |  | ||||||
|   "TimeFormatSettings": { |  | ||||||
|     "DateFormat": "%Y-%m-%d", |  | ||||||
|     "TimeFormat": "%H:%M:%S", |  | ||||||
|     "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f", |  | ||||||
|     "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S" |  | ||||||
|   }, |  | ||||||
|   "LoggingSettings": { |  | ||||||
|     "Path": "logs/", |  | ||||||
|     "Filename": "log_$start_time.log", |  | ||||||
|     "ConsoleLogLevel": "ERROR", |  | ||||||
|     "FileLogLevel": "WARN" |  | ||||||
|   }, |  | ||||||
|   "BotLoggingSettings": { |  | ||||||
|     "Database": { |  | ||||||
|       "Path": "logs/$date_now/", |  | ||||||
|       "Filename": "database.log", |  | ||||||
|       "ConsoleLogLevel": "ERROR", |  | ||||||
|       "FileLogLevel": "INFO" |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user