Compare commits

..

No commits in common. "master" and "1.2.0" have entirely different histories.

431 changed files with 5084 additions and 9500 deletions

View File

@ -6,17 +6,9 @@ on:
- dev - dev
jobs: jobs:
pre-build: on-push-deploy_sh-edraft:
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ] runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest container: sh-edraft.de/act-runner:latest
steps:
- name: Shutdown stack
run: docker stack rm sdb_dev
build-bot:
needs: pre-build
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
steps: steps:
- name: Setup docker - name: Setup docker
uses: https://github.com/papodaca/install-docker-action@main uses: https://github.com/papodaca/install-docker-action@main
@ -30,44 +22,10 @@ jobs:
- name: Prepare bot build - name: Prepare bot build
run: | run: |
cd bot
python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
cd bot
cpl i cpl i
- name: Build docker bot
run: |
cd bot
docker image prune -f
cpl build
docker build -t git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cpl gv)-dev .
- name: Login to registry git.sh-edraft.de
uses: https://github.com/docker/login-action@v1
with:
registry: git.sh-edraft.de
username: ${{ secrets.CI_USERNAME }}
password: ${{ secrets.CI_ACCESS_TOKEN }}
- name: Push image
run: |
cd bot
docker push git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cpl gv)-dev
build-web:
needs: pre-build
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: git.sh-edraft.de/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: Setup node - name: Setup node
uses: https://github.com/actions/setup-node@v3 uses: https://github.com/actions/setup-node@v3
@ -77,45 +35,29 @@ jobs:
npm install -g ts-node npm install -g ts-node
npm ci npm ci
- name: Shutdown stack
run: docker stack rm sdb_dev
- name: Build docker bot
run: |
cd bot
docker image prune -f
cpl build
docker build -t sh-edraft.de/sdb-bot:$(cpl gv)-dev .
- name: Build docker web - name: Build docker web
run: | run: |
cd web cd web
docker image prune -f docker image prune -f
cp src/favicon.dev.ico src/favicon.ico cp src/favicon.dev.ico src/favicon.ico
npm run build npm run build
docker build -t git.sh-edraft.de/sh-edraft.de/sdb-web:$(npm run -s gv)-dev . docker build -t sh-edraft.de/sdb-web:$(npm run -s gv)-dev .
- name: Login to registry git.sh-edraft.de
uses: https://github.com/docker/login-action@v1
with:
registry: git.sh-edraft.de
username: ${{ secrets.CI_USERNAME }}
password: ${{ secrets.CI_ACCESS_TOKEN }}
- name: Push image
run: |
cd web
docker push git.sh-edraft.de/sh-edraft.de/sdb-web:$(npm run -s gv)-dev
deploy:
needs: [ build-bot, build-web ]
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
steps:
- name: Clone Repository
uses: https://github.com/actions/checkout@v3
with:
token: ${{ secrets.CI_ACCESS_TOKEN }}
submodules: true
- name: Install cpl
run: python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
- name: Set version - name: Set version
run: | run: |
cd bot/docker cd bot/docker
chmod +x ./set-docker-compose-image-version.sh chmod +x ./set-docker-compose-image-version.sh
./set-docker-compose-image-version.sh git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cd ../; cpl gv)-dev git.sh-edraft.de/sh-edraft.de/sdb-web:$(cd ../../web; npm run -s gv;)-dev ./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

View File

@ -6,17 +6,9 @@ on:
- master - master
jobs: jobs:
pre-build: on-push-deploy_sh-edraft:
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ] runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest container: sh-edraft.de/act-runner:latest
steps:
- name: Shutdown stack
run: docker stack rm sdb_prod
build-bot:
needs: pre-build
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
steps: steps:
- name: Setup docker - name: Setup docker
uses: https://github.com/papodaca/install-docker-action@main uses: https://github.com/papodaca/install-docker-action@main
@ -30,44 +22,10 @@ jobs:
- name: Prepare bot build - name: Prepare bot build
run: | run: |
cd bot
python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
cd bot
cpl i cpl i
- name: Build docker bot
run: |
cd bot
docker image prune -f
cpl build
docker build -t git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cpl gv) .
- name: Login to registry git.sh-edraft.de
uses: https://github.com/docker/login-action@v1
with:
registry: git.sh-edraft.de
username: ${{ secrets.CI_USERNAME }}
password: ${{ secrets.CI_ACCESS_TOKEN }}
- name: Push image
run: |
cd bot
docker push git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cpl gv)
build-web:
needs: pre-build
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: git.sh-edraft.de/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: Setup node - name: Setup node
uses: https://github.com/actions/setup-node@v3 uses: https://github.com/actions/setup-node@v3
@ -77,44 +35,28 @@ jobs:
npm install -g ts-node npm install -g ts-node
npm ci npm ci
- name: Shutdown stack
run: docker stack rm sdb_prod
- name: Build docker bot
run: |
cd bot
docker image prune -f
cpl build
docker build -t sh-edraft.de/sdb-bot:$(cpl gv) .
- name: Build docker web - name: Build docker web
run: | run: |
cd web cd web
docker image prune -f docker image prune -f
npm run build npm run build
docker build -t git.sh-edraft.de/sh-edraft.de/sdb-web:$(npm run -s gv) . docker build -t sh-edraft.de/sdb-web:$(npm run -s gv) .
- name: Login to registry git.sh-edraft.de
uses: https://github.com/docker/login-action@v1
with:
registry: git.sh-edraft.de
username: ${{ secrets.CI_USERNAME }}
password: ${{ secrets.CI_ACCESS_TOKEN }}
- name: Push image
run: |
cd web
docker push git.sh-edraft.de/sh-edraft.de/sdb-web:$(npm run -s gv)
deploy:
needs: [ build-bot, build-web ]
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
steps:
- name: Clone Repository
uses: https://github.com/actions/checkout@v3
with:
token: ${{ secrets.CI_ACCESS_TOKEN }}
submodules: true
- name: Install cpl
run: python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
- name: Set version - name: Set version
run: | run: |
cd bot/docker cd bot/docker
chmod +x ./set-docker-compose-image-version.sh chmod +x ./set-docker-compose-image-version.sh
./set-docker-compose-image-version.sh git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cd ../; cpl gv) git.sh-edraft.de/sh-edraft.de/sdb-web:$(cd ../../web; npm run -s gv;) ./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

View File

@ -6,17 +6,9 @@ on:
- staging - staging
jobs: jobs:
pre-build: on-push-deploy_sh-edraft:
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ] runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest container: sh-edraft.de/act-runner:latest
steps:
- name: Shutdown stack
run: docker stack rm sdb_staging
build-bot:
needs: pre-build
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
steps: steps:
- name: Setup docker - name: Setup docker
uses: https://github.com/papodaca/install-docker-action@main uses: https://github.com/papodaca/install-docker-action@main
@ -30,44 +22,10 @@ jobs:
- name: Prepare bot build - name: Prepare bot build
run: | run: |
cd bot
python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
cd bot
cpl i cpl i
- name: Build docker bot
run: |
cd bot
docker image prune -f
cpl build
docker build -t git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cpl gv)-staging .
- name: Login to registry git.sh-edraft.de
uses: https://github.com/docker/login-action@v1
with:
registry: git.sh-edraft.de
username: ${{ secrets.CI_USERNAME }}
password: ${{ secrets.CI_ACCESS_TOKEN }}
- name: Push image
run: |
cd bot
docker push git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cpl gv)-staging
build-web:
needs: pre-build
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: git.sh-edraft.de/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: Setup node - name: Setup node
uses: https://github.com/actions/setup-node@v3 uses: https://github.com/actions/setup-node@v3
@ -77,45 +35,29 @@ jobs:
npm install -g ts-node npm install -g ts-node
npm ci 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 - name: Build docker web
run: | run: |
cd web cd web
docker image prune -f docker image prune -f
cp src/favicon.staging.ico src/favicon.ico cp src/favicon.staging.ico src/favicon.ico
npm run build npm run build
docker build -t git.sh-edraft.de/sh-edraft.de/sdb-web:$(npm run -s gv)-staging . docker build -t sh-edraft.de/sdb-web:$(npm run -s gv)-staging .
- name: Login to registry git.sh-edraft.de
uses: https://github.com/docker/login-action@v1
with:
registry: git.sh-edraft.de
username: ${{ secrets.CI_USERNAME }}
password: ${{ secrets.CI_ACCESS_TOKEN }}
- name: Push image
run: |
cd web
docker push git.sh-edraft.de/sh-edraft.de/sdb-web:$(npm run -s gv)-staging
deploy:
needs: [ build-bot, build-web ]
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
steps:
- name: Clone Repository
uses: https://github.com/actions/checkout@v3
with:
token: ${{ secrets.CI_ACCESS_TOKEN }}
submodules: true
- name: Install cpl
run: python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
- name: Set version - name: Set version
run: | run: |
cd bot/docker cd bot/docker
chmod +x ./set-docker-compose-image-version.sh chmod +x ./set-docker-compose-image-version.sh
./set-docker-compose-image-version.sh git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cd ../; cpl gv)-staging git.sh-edraft.de/sh-edraft.de/sdb-web:$(cd ../../web; npm run -s gv;)-staging ./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 - 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

View File

@ -14,14 +14,14 @@
"config": "src/modules/config/config.json", "config": "src/modules/config/config.json",
"database": "src/modules/database/database.json", "database": "src/modules/database/database.json",
"level": "src/modules/level/level.json", "level": "src/modules/level/level.json",
"permission": "src/modules/permission/permission.json",
"technician": "src/modules/technician/technician.json", "technician": "src/modules/technician/technician.json",
"short-role-name": "src/modules/short_role_name/short-role-name.json", "short-role-name": "src/modules/short_role_name/short-role-name.json",
"special-offers": "src/modules/special_offers/special-offers.json", "special-offers": "src/modules/special_offers/special-offers.json",
"checks": "tools/checks/checks.json", "checks": "tools/checks/checks.json",
"get-version": "tools/get_version/get-version.json", "get-version": "tools/get_version/get-version.json",
"post-build": "tools/post_build/post-build.json", "post-build": "tools/post_build/post-build.json",
"set-version": "tools/set_version/set-version.json", "set-version": "tools/set_version/set-version.json"
"migration-to-sql": "tools/migration_to_sql/migration-to-sql.json"
}, },
"Scripts": { "Scripts": {
"format": "black ./", "format": "black ./",

@ -1 +1 @@
Subproject commit fbcd9226c4d199529fdbce5169b38b1b23074adb Subproject commit 9c0dc595348f9ccd58409cc21171456d9ba85758

View File

@ -15,7 +15,7 @@ __title__ = "bot"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

0
bot/src/bot/bot Executable file → Normal file
View File

View File

@ -4,7 +4,7 @@
"Version": { "Version": {
"Major": "1", "Major": "1",
"Minor": "2", "Minor": "2",
"Micro": "8" "Micro": "0"
}, },
"Author": "Sven Heidemann", "Author": "Sven Heidemann",
"AuthorEmail": "sven.heidemann@sh-edraft.de", "AuthorEmail": "sven.heidemann@sh-edraft.de",
@ -16,6 +16,7 @@
"LicenseName": "MIT", "LicenseName": "MIT",
"LicenseDescription": "MIT, see LICENSE for more details.", "LicenseDescription": "MIT, see LICENSE for more details.",
"Dependencies": [ "Dependencies": [
"cpl-core==2023.10.0",
"cpl-translation==2023.4.0.post1", "cpl-translation==2023.4.0.post1",
"cpl-query==2023.10.0", "cpl-query==2023.10.0",
"cpl-discord==2023.10.0.post1", "cpl-discord==2023.10.0.post1",
@ -32,14 +33,11 @@
"cryptography==41.0.4", "cryptography==41.0.4",
"discord==2.3.2", "discord==2.3.2",
"bs4==0.0.1", "bs4==0.0.1",
"lxml==4.9.3", "lxml==4.9.3"
"python-valve==0.2.1",
"cpl-core==2023.10.2"
], ],
"DevDependencies": [ "DevDependencies": [
"cpl-cli==2023.4.0.post3", "cpl-cli==2023.4.0.post3",
"pygount==1.6.1", "pygount==1.6.1"
"black==23.10.1"
], ],
"PythonVersion": ">=3.10.4", "PythonVersion": ">=3.10.4",
"PythonPath": {}, "PythonPath": {},
@ -71,6 +69,7 @@
"../modules/config/config.json", "../modules/config/config.json",
"../modules/database/database.json", "../modules/database/database.json",
"../modules/level/level.json", "../modules/level/level.json",
"../modules/permission/permission.json",
"../modules/short_role_name/short-role-name.json", "../modules/short_role_name/short-role-name.json",
"../modules/special_offers/special-offers.json", "../modules/special_offers/special-offers.json",
"../modules/technician/technician.json" "../modules/technician/technician.json"

@ -1 +1 @@
Subproject commit eeebd13f80c6ceecc922ede5771e55212a884019 Subproject commit c11ca6f2e8e54bacdf16da677fbcf03705ff9780

View File

@ -15,7 +15,7 @@ __title__ = "bot.extension"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -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}"))
)

View File

@ -6,7 +6,6 @@ from cpl_core.application import ApplicationBuilder
from cpl_core.console import Console from cpl_core.console import Console
from bot.application import Application from bot.application import Application
from bot.extension.clean_logs_extension import CleanLogsExtension
from bot.extension.init_bot_extension import InitBotExtension from bot.extension.init_bot_extension import InitBotExtension
from bot.startup import Startup from bot.startup import Startup
from bot.startup_discord_extension import StartupDiscordExtension from bot.startup_discord_extension import StartupDiscordExtension
@ -32,7 +31,6 @@ class Program:
.use_extension(StartupDiscordExtension) .use_extension(StartupDiscordExtension)
.use_extension(StartupModuleExtension) .use_extension(StartupModuleExtension)
.use_extension(StartupMigrationExtension) .use_extension(StartupMigrationExtension)
.use_extension(CleanLogsExtension)
.use_extension(DatabaseExtension) .use_extension(DatabaseExtension)
.use_extension(ConfigExtension) .use_extension(ConfigExtension)
.use_extension(InitBotExtension) .use_extension(InitBotExtension)

View File

@ -12,6 +12,7 @@ from modules.boot_log.boot_log_module import BootLogModule
from modules.config.config_module import ConfigModule from modules.config.config_module import ConfigModule
from modules.database.database_module import DatabaseModule from modules.database.database_module import DatabaseModule
from modules.level.level_module import LevelModule from modules.level.level_module import LevelModule
from modules.permission.permission_module import PermissionModule
from modules.short_role_name.short_role_name_module import ShortRoleNameModule from modules.short_role_name.short_role_name_module import ShortRoleNameModule
from modules.special_offers.special_offers_module import SteamSpecialOffersModule from modules.special_offers.special_offers_module import SteamSpecialOffersModule
from modules.technician.technician_module import TechnicianModule from modules.technician.technician_module import TechnicianModule
@ -29,6 +30,7 @@ class ModuleList:
ConfigModule, # has to be before db check ConfigModule, # has to be before db check
DatabaseModule, DatabaseModule,
GraphQLModule, GraphQLModule,
PermissionModule,
AutoRoleModule, AutoRoleModule,
BaseModule, BaseModule,
LevelModule, LevelModule,

View File

@ -15,7 +15,6 @@ from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_core.logging.command_logger import CommandLogger from bot_core.logging.command_logger import CommandLogger
from bot_core.logging.database_logger import DatabaseLogger from bot_core.logging.database_logger import DatabaseLogger
from bot_core.logging.event_logger import EventLogger
from bot_core.logging.message_logger import MessageLogger from bot_core.logging.message_logger import MessageLogger
from bot_core.logging.task_logger import TaskLogger from bot_core.logging.task_logger import TaskLogger
from bot_data.db_context import DBContext from bot_data.db_context import DBContext
@ -46,7 +45,6 @@ class Startup(StartupABC):
services.add_singleton(CustomFileLoggerABC, DatabaseLogger) services.add_singleton(CustomFileLoggerABC, DatabaseLogger)
services.add_singleton(CustomFileLoggerABC, MessageLogger) services.add_singleton(CustomFileLoggerABC, MessageLogger)
services.add_singleton(CustomFileLoggerABC, TaskLogger) services.add_singleton(CustomFileLoggerABC, TaskLogger)
services.add_singleton(CustomFileLoggerABC, EventLogger)
if self._feature_flags.get_flag(FeatureFlagsEnum.api_module): if self._feature_flags.get_flag(FeatureFlagsEnum.api_module):
services.add_singleton(CustomFileLoggerABC, ApiLogger) services.add_singleton(CustomFileLoggerABC, ApiLogger)

View File

@ -2,22 +2,22 @@
"api": { "api": {
"api": { "api": {
"test_mail": { "test_mail": {
"message": "Dies ist eine Test-Mail vom Krümelmonster Web Interface\r\nGesendet von {}-{}", "message": "Dies ist eine Test-Mail vom Krümelmonster Web Interface\nGesendet von {}-{}",
"subject": "Krümelmonster Web Interface Test-Mail" "subject": "Krümelmonster Web Interface Test-Mail"
} }
}, },
"auth": { "auth": {
"confirmation": { "confirmation": {
"message": "Öffne den Link, um die E-Mail zu bestätigen:\r\n{}auth/register/{}", "message": "Öffne den Link, um die E-Mail zu bestätigen:\n{}auth/register/{}",
"subject": "E-Mail für {} {} bestätigen" "subject": "E-Mail für {} {} bestätigen"
}, },
"forgot_password": { "forgot_password": {
"message": "Öffne den Link, um das Passwort zu ändern:\r\n{}auth/forgot-password/{}", "message": "Öffne den Link, um das Passwort zu ändern:\n{}auth/forgot-password/{}",
"subject": "Passwort für {} {} zurücksetzen" "subject": "Passwort für {} {} zurücksetzen"
} }
}, },
"mail": { "mail": {
"automatic_mail": "\r\n\r\nDies ist eine automatische E-Mail.\r\nGesendet von {}-{}@{}" "automatic_mail": "\n\nDies ist eine automatische E-Mail.\nGesendet von {}-{}@{}"
} }
}, },
"common": { "common": {

View File

@ -15,7 +15,7 @@ __title__ = "bot_api"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -15,7 +15,7 @@ __title__ = "bot_api.abc"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -114,7 +114,3 @@ class AuthServiceABC(ABC):
@abstractmethod @abstractmethod
async def reset_password_async(self, rp_dto: ResetPasswordDTO): async def reset_password_async(self, rp_dto: ResetPasswordDTO):
pass pass
@abstractmethod
async def resend_confirmation_email_by_mail(self, mail: str):
pass

View File

@ -16,8 +16,8 @@ from werkzeug.exceptions import NotFound
from bot_api.configuration.api_settings import ApiSettings from bot_api.configuration.api_settings import ApiSettings
from bot_api.configuration.authentication_settings import AuthenticationSettings from bot_api.configuration.authentication_settings import AuthenticationSettings
from bot_core.exception.service_error_code_enum import ServiceErrorCode from bot_api.exception.service_error_code_enum import ServiceErrorCode
from bot_core.exception.service_exception import ServiceException from bot_api.exception.service_exception import ServiceException
from bot_api.logging.api_logger import ApiLogger from bot_api.logging.api_logger import ApiLogger
from bot_api.model.error_dto import ErrorDTO from bot_api.model.error_dto import ErrorDTO
from bot_api.route.route import Route from bot_api.route.route import Route

View File

@ -4,7 +4,7 @@
"Version": { "Version": {
"Major": "1", "Major": "1",
"Minor": "2", "Minor": "2",
"Micro": "8" "Micro": "0"
}, },
"Author": "", "Author": "",
"AuthorEmail": "", "AuthorEmail": "",

@ -1 +1 @@
Subproject commit 12ffcbcd9b88612251a1e23cb6724e21562f74b8 Subproject commit 521951b8abb0f784b59b6d3e0210606fa193e60a

View File

@ -15,7 +15,7 @@ __title__ = "bot_api.configuration"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports # imports
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -15,7 +15,7 @@ __title__ = "bot_api.controller"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -14,10 +14,7 @@ from bot_api.model.reset_password_dto import ResetPasswordDTO
from bot_api.model.token_dto import TokenDTO from bot_api.model.token_dto import TokenDTO
from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO
from bot_api.route.route import Route from bot_api.route.route import Route
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_data.model.auth_role_enum import AuthRoleEnum from bot_data.model.auth_role_enum import AuthRoleEnum
from bot_data.model.technician_config import TechnicianConfig
class AuthController: class AuthController:
@ -33,7 +30,6 @@ class AuthController:
mail_settings: EMailClientSettings, mail_settings: EMailClientSettings,
mailer: EMailClientABC, mailer: EMailClientABC,
auth_service: AuthServiceABC, auth_service: AuthServiceABC,
technician_config: TechnicianConfig,
): ):
self._config = config self._config = config
self._env = env self._env = env
@ -43,7 +39,6 @@ class AuthController:
self._mail_settings = mail_settings self._mail_settings = mail_settings
self._mailer = mailer self._mailer = mailer
self._auth_service = auth_service self._auth_service = auth_service
self._technician_config = technician_config
@Route.get(f"{BasePath}/users") @Route.get(f"{BasePath}/users")
@Route.authorize(role=AuthRoleEnum.admin) @Route.authorize(role=AuthRoleEnum.admin)
@ -75,20 +70,10 @@ class AuthController:
@Route.post(f"{BasePath}/register") @Route.post(f"{BasePath}/register")
async def register(self): async def register(self):
if not FeatureFlagsSettings.get_flag_from_dict(
self._technician_config.feature_flags, FeatureFlagsEnum.basic_registration
):
return
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True)) dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
self._auth_service.add_auth_user(dto) self._auth_service.add_auth_user(dto)
return "", 200 return "", 200
@Route.post(f"{BasePath}/resend-confirmation-email-by-mail/<mail>")
async def resend_confirmation_email_by_user_id(self, mail: str):
await self._auth_service.resend_confirmation_email_by_mail(mail)
return "", 200
@Route.post(f"{BasePath}/register-by-id/<id>") @Route.post(f"{BasePath}/register-by-id/<id>")
async def register_id(self, id: str): async def register_id(self, id: str):
result = await self._auth_service.confirm_email_async(id) result = await self._auth_service.confirm_email_async(id)
@ -96,11 +81,6 @@ class AuthController:
@Route.post(f"{BasePath}/login") @Route.post(f"{BasePath}/login")
async def login(self) -> Response: async def login(self) -> Response:
if not FeatureFlagsSettings.get_flag_from_dict(
self._technician_config.feature_flags, FeatureFlagsEnum.basic_login
):
return jsonify({})
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True)) dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
result = await self._auth_service.login_async(dto) result = await self._auth_service.login_async(dto)
return jsonify(result.to_dict()) return jsonify(result.to_dict())
@ -120,11 +100,6 @@ class AuthController:
@Route.post(f"{BasePath}/forgot-password/<email>") @Route.post(f"{BasePath}/forgot-password/<email>")
async def forgot_password(self, email: str): async def forgot_password(self, email: str):
if not FeatureFlagsSettings.get_flag_from_dict(
self._technician_config.feature_flags, FeatureFlagsEnum.basic_login
):
return "", 409
await self._auth_service.forgot_password_async(email) await self._auth_service.forgot_password_async(email)
return "", 200 return "", 200
@ -135,11 +110,6 @@ class AuthController:
@Route.post(f"{BasePath}/reset-password") @Route.post(f"{BasePath}/reset-password")
async def reset_password(self): async def reset_password(self):
if not FeatureFlagsSettings.get_flag_from_dict(
self._technician_config.feature_flags, FeatureFlagsEnum.basic_login
):
return "", 409
dto: ResetPasswordDTO = JSONProcessor.process(ResetPasswordDTO, request.get_json(force=True, silent=True)) dto: ResetPasswordDTO = JSONProcessor.process(ResetPasswordDTO, request.get_json(force=True, silent=True))
await self._auth_service.reset_password_async(dto) await self._auth_service.reset_password_async(dto)
return "", 200 return "", 200

View File

@ -16,7 +16,6 @@ from bot_api.api import Api
from bot_api.configuration.discord_authentication_settings import ( from bot_api.configuration.discord_authentication_settings import (
DiscordAuthenticationSettings, DiscordAuthenticationSettings,
) )
from bot_core.exception.service_exception import ServiceException
from bot_api.logging.api_logger import ApiLogger from bot_api.logging.api_logger import ApiLogger
from bot_api.model.auth_user_dto import AuthUserDTO from bot_api.model.auth_user_dto import AuthUserDTO
from bot_api.route.route import Route from bot_api.route.route import Route
@ -91,10 +90,5 @@ class AuthDiscordController:
AuthRoleEnum.normal, AuthRoleEnum.normal,
) )
try:
result = await self._auth_service.login_discord_async(dto, response["id"]) result = await self._auth_service.login_discord_async(dto, response["id"])
return jsonify(result.to_dict()) return jsonify(result.to_dict())
except ServiceException as e:
r = jsonify({"email": dto.email})
r.status_code = 403
return r

View File

@ -12,9 +12,6 @@ from bot_api.logging.api_logger import ApiLogger
from bot_api.model.settings_dto import SettingsDTO from bot_api.model.settings_dto import SettingsDTO
from bot_api.model.version_dto import VersionDTO from bot_api.model.version_dto import VersionDTO
from bot_api.route.route import Route from bot_api.route.route import Route
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_data.model.technician_config import TechnicianConfig
class GuiController: class GuiController:
@ -85,11 +82,3 @@ class GuiController:
) )
self._mailer.send_mail(mail) self._mailer.send_mail(mail)
return "", 200 return "", 200
@Route.get(f"{BasePath}/has-feature-flag/<flag>")
async def has_feature_flag(self, flag: str):
settings: TechnicianConfig = self._config.get_configuration(TechnicianConfig)
return {
"key": flag,
"value": FeatureFlagsSettings.get_flag_from_dict(settings.feature_flags, FeatureFlagsEnum(flag)),
}

View File

@ -15,7 +15,7 @@ __title__ = "bot_api.event"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -11,11 +11,11 @@ Discord bot for customers of sh-edraft.de
""" """
__title__ = "modules.base.tasks" __title__ = "bot_api.exception"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -1,4 +1,4 @@
from bot_core.exception.service_error_code_enum import ServiceErrorCode from bot_api.exception.service_error_code_enum import ServiceErrorCode
class ServiceException(Exception): class ServiceException(Exception):

View File

@ -15,7 +15,7 @@ __title__ = "bot_api.filter"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -15,7 +15,7 @@ __title__ = "bot_api.filter.discord"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -15,7 +15,7 @@ __title__ = "bot_api.logging"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -15,7 +15,7 @@ __title__ = "bot_api.model"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -15,7 +15,7 @@ __title__ = "bot_api.model.discord"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -1,7 +1,10 @@
import traceback
from typing import Optional from typing import Optional
from cpl_core.console import Console
from bot_api.abc.dto_abc import DtoABC from bot_api.abc.dto_abc import DtoABC
from bot_core.exception.service_error_code_enum import ServiceErrorCode from bot_api.exception.service_error_code_enum import ServiceErrorCode
class ErrorDTO(DtoABC): class ErrorDTO(DtoABC):

View File

@ -15,7 +15,7 @@ __title__ = "bot_api.route"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -8,8 +8,8 @@ from flask import request, jsonify
from flask_cors import cross_origin from flask_cors import cross_origin
from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_core.exception.service_error_code_enum import ServiceErrorCode from bot_api.exception.service_error_code_enum import ServiceErrorCode
from bot_core.exception.service_exception import ServiceException from bot_api.exception.service_exception import ServiceException
from bot_api.model.error_dto import ErrorDTO from bot_api.model.error_dto import ErrorDTO
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
from bot_data.model.auth_role_enum import AuthRoleEnum from bot_data.model.auth_role_enum import AuthRoleEnum

View File

@ -15,7 +15,7 @@ __title__ = "bot_api.service"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports # imports
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -1,5 +1,6 @@
import hashlib import hashlib
import re import re
import textwrap
import uuid import uuid
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from threading import Thread from threading import Thread
@ -18,8 +19,8 @@ from flask import request
from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_api.configuration.authentication_settings import AuthenticationSettings from bot_api.configuration.authentication_settings import AuthenticationSettings
from bot_api.configuration.frontend_settings import FrontendSettings from bot_api.configuration.frontend_settings import FrontendSettings
from bot_core.exception.service_error_code_enum import ServiceErrorCode from bot_api.exception.service_error_code_enum import ServiceErrorCode
from bot_core.exception.service_exception import ServiceException from bot_api.exception.service_exception import ServiceException
from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria
from bot_api.logging.api_logger import ApiLogger from bot_api.logging.api_logger import ApiLogger
from bot_api.model.auth_user_dto import AuthUserDTO from bot_api.model.auth_user_dto import AuthUserDTO
@ -171,7 +172,11 @@ class AuthService(AuthServiceABC):
mail.add_header("Content-Transfer-Encoding: quoted-printable") mail.add_header("Content-Transfer-Encoding: quoted-printable")
mail.add_receiver(str(email)) mail.add_receiver(str(email))
mail.subject = subject mail.subject = subject
mail.body = f"{message}\r\n{self._t.transform('api.mail.automatic_mail').format(self._environment.application_name, self._environment.environment_name, self._environment.host_name)}" mail.body = textwrap.dedent(
f"""{message}
{self._t.transform('api.mail.automatic_mail').format(self._environment.application_name, self._environment.environment_name, self._environment.host_name)}
"""
)
thr = Thread(target=self._mailer.send_mail, args=[mail]) thr = Thread(target=self._mailer.send_mail, args=[mail])
thr.start() thr.start()
@ -594,12 +599,3 @@ class AuthService(AuthServiceABC):
user.forgot_password_id = None user.forgot_password_id = None
self._auth_users.update_auth_user(user) self._auth_users.update_auth_user(user)
self._db.save_changes() self._db.save_changes()
async def resend_confirmation_email_by_mail(self, mail: str):
user = self._auth_users.find_auth_user_by_email(mail)
if user is None:
raise ServiceException(ServiceErrorCode.InvalidUser, f"User not found")
if user.confirmation_id is None:
raise ServiceException(ServiceErrorCode.DataAlreadyExists, f"User already confirmed")
self._send_confirmation_id_to_user(user)

View File

@ -4,8 +4,8 @@ from cpl_discord.service import DiscordBotServiceABC
from cpl_query.extension import List from cpl_query.extension import List
from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_core.exception.service_error_code_enum import ServiceErrorCode from bot_api.exception.service_error_code_enum import ServiceErrorCode
from bot_core.exception.service_exception import ServiceException from bot_api.exception.service_exception import ServiceException
from bot_api.filter.discord.server_select_criteria import ServerSelectCriteria from bot_api.filter.discord.server_select_criteria import ServerSelectCriteria
from bot_api.model.discord.server_dto import ServerDTO from bot_api.model.discord.server_dto import ServerDTO
from bot_api.model.discord.server_filtered_result_dto import ServerFilteredResultDTO from bot_api.model.discord.server_filtered_result_dto import ServerFilteredResultDTO

View File

@ -15,7 +15,7 @@ __title__ = "bot_api.transformer"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -10,7 +10,7 @@ from bot_api.model.user_dto import UserDTO
from bot_data.model.auth_role_enum import AuthRoleEnum from bot_data.model.auth_role_enum import AuthRoleEnum
from bot_data.model.auth_user import AuthUser from bot_data.model.auth_user import AuthUser
from bot_data.model.user import User from bot_data.model.user import User
from bot_core.abc.permission_service_abc import PermissionServiceABC from modules.permission.abc.permission_service_abc import PermissionServiceABC
class AuthUserTransformer(TransformerABC): class AuthUserTransformer(TransformerABC):
@ -35,37 +35,21 @@ class AuthUserTransformer(TransformerABC):
@ServiceProviderABC.inject @ServiceProviderABC.inject
def _is_technician(user: User, bot: DiscordBotServiceABC, permissions: PermissionServiceABC): def _is_technician(user: User, bot: DiscordBotServiceABC, permissions: PermissionServiceABC):
guild = bot.get_guild(user.server.discord_id) guild = bot.get_guild(user.server.discord_id)
if guild is None:
return permissions.is_member_technician_by_id(user.discord_id)
member = guild.get_member(user.discord_id) member = guild.get_member(user.discord_id)
if member is None:
return permissions.is_member_technician_by_id(user.discord_id)
return permissions.is_member_technician(member) return permissions.is_member_technician(member)
@staticmethod @staticmethod
@ServiceProviderABC.inject @ServiceProviderABC.inject
def _is_admin(user: User, bot: DiscordBotServiceABC, permissions: PermissionServiceABC): def _is_admin(user: User, bot: DiscordBotServiceABC, permissions: PermissionServiceABC):
guild = bot.get_guild(user.server.discord_id) guild = bot.get_guild(user.server.discord_id)
if guild is None:
return False
member = guild.get_member(user.discord_id) member = guild.get_member(user.discord_id)
if member is None:
return False
return permissions.is_member_admin(member) return permissions.is_member_admin(member)
@staticmethod @staticmethod
@ServiceProviderABC.inject @ServiceProviderABC.inject
def _is_moderator(user: User, bot: DiscordBotServiceABC, permissions: PermissionServiceABC): def _is_moderator(user: User, bot: DiscordBotServiceABC, permissions: PermissionServiceABC):
guild = bot.get_guild(user.server.discord_id) guild = bot.get_guild(user.server.discord_id)
if guild is None:
return False
member = guild.get_member(user.discord_id) member = guild.get_member(user.discord_id)
if member is None:
return False
return permissions.is_member_moderator(member) return permissions.is_member_moderator(member)
@classmethod @classmethod

View File

@ -15,7 +15,7 @@ __title__ = "bot_core"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports # imports
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -15,7 +15,7 @@ __title__ = "bot_core.abc"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -48,16 +48,6 @@ class ClientUtilsABC(ABC):
def get_auto_complete_list(self, _l: List, current: str, select: Callable = None) -> List: def get_auto_complete_list(self, _l: List, current: str, select: Callable = None) -> List:
pass pass
@abstractmethod
def update_user_message_xp_count_by_hour(
self,
created_at: datetime,
user: User,
settings: ServerConfig,
is_reaction: bool = False,
):
pass
@abstractmethod @abstractmethod
def is_message_xp_count_by_hour_higher_that_max_message_count_per_hour( def is_message_xp_count_by_hour_higher_that_max_message_count_per_hour(
self, self,

View File

@ -21,7 +21,7 @@ class TaskABC(commands.Cog):
@ServiceProviderABC.inject @ServiceProviderABC.inject
async def _wait_until_ready(self, config: ConfigurationABC, logger: TaskLogger, bot: DiscordBotServiceABC): async def _wait_until_ready(self, config: ConfigurationABC, logger: TaskLogger, bot: DiscordBotServiceABC):
logger.debug(__name__, f"Waiting before ready {type(self).__name__}") logger.debug(__name__, f"Waiting before {type(self).__name__}")
await bot.wait_until_ready() await bot.wait_until_ready()
async def wait(): async def wait():

View File

@ -4,7 +4,7 @@
"Version": { "Version": {
"Major": "1", "Major": "1",
"Minor": "2", "Minor": "2",
"Micro": "8" "Micro": "0"
}, },
"Author": "Sven Heidemann", "Author": "Sven Heidemann",
"AuthorEmail": "sven.heidemann@sh-edraft.de", "AuthorEmail": "sven.heidemann@sh-edraft.de",

View File

@ -15,7 +15,7 @@ __title__ = "bot_core.configuration"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -15,6 +15,7 @@ class FeatureFlagsEnum(Enum):
database_module = "DatabaseModule" database_module = "DatabaseModule"
level_module = "LevelModule" level_module = "LevelModule"
moderator_module = "ModeratorModule" moderator_module = "ModeratorModule"
permission_module = "PermissionModule"
short_role_name_module = "ShortRoleNameModule" short_role_name_module = "ShortRoleNameModule"
steam_special_offers_module = "SteamSpecialOffersModule" steam_special_offers_module = "SteamSpecialOffersModule"
# features # features
@ -26,6 +27,3 @@ class FeatureFlagsEnum(Enum):
short_role_name = "ShortRoleName" short_role_name = "ShortRoleName"
technician_full_access = "TechnicianFullAccess" technician_full_access = "TechnicianFullAccess"
steam_special_offers = "SteamSpecialOffers" steam_special_offers = "SteamSpecialOffers"
scheduled_events = "ScheduledEvents"
basic_registration = "BasicRegistration"
basic_login = "BasicLogin"

View File

@ -16,6 +16,7 @@ class FeatureFlagsSettings(ConfigurationModelABC):
FeatureFlagsEnum.data_module.value: True, # 03.10.2022 #56 FeatureFlagsEnum.data_module.value: True, # 03.10.2022 #56
FeatureFlagsEnum.database_module.value: True, # 02.10.2022 #48 FeatureFlagsEnum.database_module.value: True, # 02.10.2022 #48
FeatureFlagsEnum.moderator_module.value: False, # 02.10.2022 #48 FeatureFlagsEnum.moderator_module.value: False, # 02.10.2022 #48
FeatureFlagsEnum.permission_module.value: True, # 02.10.2022 #48
FeatureFlagsEnum.config_module.value: True, # 19.07.2023 #127 FeatureFlagsEnum.config_module.value: True, # 19.07.2023 #127
FeatureFlagsEnum.short_role_name_module.value: True, # 28.09.2023 #378 FeatureFlagsEnum.short_role_name_module.value: True, # 28.09.2023 #378
FeatureFlagsEnum.steam_special_offers_module.value: True, # 11.10.2023 #188 FeatureFlagsEnum.steam_special_offers_module.value: True, # 11.10.2023 #188
@ -28,9 +29,6 @@ class FeatureFlagsSettings(ConfigurationModelABC):
FeatureFlagsEnum.short_role_name.value: False, # 28.09.2023 #378 FeatureFlagsEnum.short_role_name.value: False, # 28.09.2023 #378
FeatureFlagsEnum.technician_full_access.value: False, # 03.10.2023 #393 FeatureFlagsEnum.technician_full_access.value: False, # 03.10.2023 #393
FeatureFlagsEnum.steam_special_offers.value: False, # 11.10.2023 #188 FeatureFlagsEnum.steam_special_offers.value: False, # 11.10.2023 #188
FeatureFlagsEnum.scheduled_events.value: False, # 14.11.2023 #410
FeatureFlagsEnum.basic_registration.value: False, # 19.11.2023 #440
FeatureFlagsEnum.basic_login.value: False, # 19.11.2023 #440
} }
def __init__(self, **kwargs: dict): def __init__(self, **kwargs: dict):

View File

@ -15,7 +15,7 @@ __title__ = "bot_core.core_extension"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -9,7 +9,7 @@ from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_core.helper.command_checks import CommandChecks from bot_core.helper.command_checks import CommandChecks
from bot_core.helper.event_checks import EventChecks from bot_core.helper.event_checks import EventChecks
from bot_core.abc.permission_service_abc import PermissionServiceABC from modules.permission.abc.permission_service_abc import PermissionServiceABC
class CoreExtension(ApplicationExtensionABC): class CoreExtension(ApplicationExtensionABC):

View File

@ -1,18 +1,20 @@
import asyncio
from cpl_core.configuration import ConfigurationABC from cpl_core.configuration import ConfigurationABC
from cpl_core.logging import LoggerABC
from cpl_discord.events import OnReadyABC from cpl_discord.events import OnReadyABC
from cpl_discord.service import DiscordBotServiceABC from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe from cpl_translation import TranslatePipe
from bot_core.abc.client_utils_abc import ClientUtilsABC from bot_core.abc.client_utils_abc import ClientUtilsABC
from bot_core.environment_variables import MAINTENANCE from bot_core.environment_variables import MAINTENANCE
from bot_core.logging.event_logger import EventLogger
class CoreExtensionOnReadyEvent(OnReadyABC): class CoreExtensionOnReadyEvent(OnReadyABC):
def __init__( def __init__(
self, self,
config: ConfigurationABC, config: ConfigurationABC,
logger: EventLogger, logger: LoggerABC,
bot: DiscordBotServiceABC, bot: DiscordBotServiceABC,
client_utils: ClientUtilsABC, client_utils: ClientUtilsABC,
t: TranslatePipe, t: TranslatePipe,

View File

@ -7,7 +7,6 @@ from cpl_discord.service.discord_collection_abc import DiscordCollectionABC
from bot_core.abc.client_utils_abc import ClientUtilsABC from bot_core.abc.client_utils_abc import ClientUtilsABC
from bot_core.abc.message_service_abc import MessageServiceABC from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.abc.module_abc import ModuleABC from bot_core.abc.module_abc import ModuleABC
from bot_core.abc.permission_service_abc import PermissionServiceABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.events.core_on_ready_event import CoreOnReadyEvent from bot_core.events.core_on_ready_event import CoreOnReadyEvent
from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
@ -15,7 +14,6 @@ from bot_core.service.client_utils_service import ClientUtilsService
from bot_core.service.config_service import ConfigService from bot_core.service.config_service import ConfigService
from bot_core.service.data_integrity_service import DataIntegrityService from bot_core.service.data_integrity_service import DataIntegrityService
from bot_core.service.message_service import MessageService from bot_core.service.message_service import MessageService
from bot_core.service.permission_service import PermissionService
class CoreModule(ModuleABC): class CoreModule(ModuleABC):
@ -30,7 +28,6 @@ class CoreModule(ModuleABC):
services.add_transient(MessageServiceABC, MessageService) services.add_transient(MessageServiceABC, MessageService)
services.add_transient(ClientUtilsABC, ClientUtilsService) services.add_transient(ClientUtilsABC, ClientUtilsService)
services.add_transient(DataIntegrityService) services.add_transient(DataIntegrityService)
services.add_singleton(PermissionServiceABC, PermissionService)
# pipes # pipes
services.add_transient(DateTimeOffsetPipe) services.add_transient(DateTimeOffsetPipe)

View File

@ -15,7 +15,7 @@ __title__ = "bot_core.events"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -1,15 +1,15 @@
from cpl_core.logging import LoggerABC
from cpl_discord.events import OnReadyABC from cpl_discord.events import OnReadyABC
from cpl_discord.service import DiscordBotServiceABC from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe from cpl_translation import TranslatePipe
from bot_core.abc.client_utils_abc import ClientUtilsABC from bot_core.abc.client_utils_abc import ClientUtilsABC
from bot_core.logging.event_logger import EventLogger
class CoreOnReadyEvent(OnReadyABC): class CoreOnReadyEvent(OnReadyABC):
def __init__( def __init__(
self, self,
logger: EventLogger, logger: LoggerABC,
bot: DiscordBotServiceABC, bot: DiscordBotServiceABC,
client_utils: ClientUtilsABC, client_utils: ClientUtilsABC,
t: TranslatePipe, t: TranslatePipe,

View File

@ -15,7 +15,7 @@ __title__ = "bot_core.exception"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -15,7 +15,7 @@ __title__ = "bot_core.helper"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -7,7 +7,7 @@ from discord.ext.commands import Context
from bot_core.abc.client_utils_abc import ClientUtilsABC from bot_core.abc.client_utils_abc import ClientUtilsABC
from bot_core.abc.message_service_abc import MessageServiceABC from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.exception.check_error import CheckError from bot_core.exception.check_error import CheckError
from bot_core.abc.permission_service_abc import PermissionServiceABC from modules.permission.abc.permission_service_abc import PermissionServiceABC
class CommandChecks: class CommandChecks:

View File

@ -15,7 +15,7 @@ __title__ = "bot_core.logging"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports # imports
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -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 EventLogger(CustomFileLoggerABC):
def __init__(
self,
config: ConfigurationABC,
time_format: TimeFormatSettings,
env: ApplicationEnvironmentABC,
):
CustomFileLoggerABC.__init__(self, "Event", config, time_format, env)

View File

@ -15,7 +15,7 @@ __title__ = "bot_core.pipes"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports # imports
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -15,7 +15,7 @@ __title__ = "bot_core.service"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -143,13 +143,14 @@ class ClientUtilsService(ClientUtilsABC):
return _l.take(25) return _l.take(25)
def update_user_message_xp_count_by_hour( def is_message_xp_count_by_hour_higher_that_max_message_count_per_hour(
self, self,
created_at: datetime, created_at: datetime,
user: User, user: User,
settings: ServerConfig, settings: ServerConfig,
is_reaction: bool = False, is_reaction: bool = False,
): ) -> bool:
umcph = None
try: try:
umcph = self._umcphs.find_user_message_count_per_hour_by_user_id_and_date(user.id, created_at) umcph = self._umcphs.find_user_message_count_per_hour_by_user_id_and_date(user.id, created_at)
if umcph is None: if umcph is None:
@ -161,50 +162,44 @@ class ClientUtilsService(ClientUtilsABC):
user, user,
) )
) )
self._db.save_changes()
umcph = self._umcphs.get_user_message_count_per_hour_by_user_id_and_date(user.id, created_at)
umcph.xp_count += settings.xp_per_reaction if is_reaction else settings.xp_per_message self._db.save_changes()
umcph = self._umcphs.get_user_message_count_per_hour_by_user_id_and_date(user.id, created_at)
except Exception as e:
self._logger.error(
__name__,
f"Cannot add user message count per hour with id {umcph.id}",
e,
)
return False
try:
if is_reaction:
umcph.xp_count += settings.xp_per_reaction
else:
umcph.xp_count += settings.xp_per_message
self._umcphs.update_user_message_count_per_hour(umcph) self._umcphs.update_user_message_count_per_hour(umcph)
self._db.save_changes() self._db.save_changes()
except Exception as e: except Exception as e:
self._logger.error( self._logger.error(
__name__, __name__,
f"Cannot update user message count per hour {created_at}", f"Cannot update user message count per hour with id {umcph.id}",
e, e,
) )
return False return False
def is_message_xp_count_by_hour_higher_that_max_message_count_per_hour( if umcph.xp_count is None:
self,
created_at: datetime,
user: User,
settings: ServerConfig,
is_reaction: bool = False,
) -> bool:
try:
umcph = self._umcphs.find_user_message_count_per_hour_by_user_id_and_date(user.id, created_at)
if umcph is None or umcph.xp_count is None:
return False return False
return umcph.xp_count > settings.max_message_xp_per_hour return umcph.xp_count > settings.max_message_xp_per_hour
except Exception as e:
self._logger.error(
__name__,
f"Cannot add user message count per hour with",
e,
)
return False
def get_ontime_for_user(self, user: User) -> float: def get_ontime_for_user(self, user: User) -> float:
return round( return round(
sum( self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.id)
[ .where(lambda x: x.leaved_on is not None and x.joined_on is not None)
(join.leaved_on - join.joined_on).total_seconds() / 3600 .sum(lambda join: (join.leaved_on - join.joined_on).total_seconds() / 3600),
for join in self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.id)
if join.leaved_on is not None and join.joined_on is not None
]
),
2, 2,
) )
@ -219,7 +214,7 @@ class ClientUtilsService(ClientUtilsABC):
guild: Guild = self._bot.guilds.where(lambda g: g == guild).single() guild: Guild = self._bot.guilds.where(lambda g: g == guild).single()
channel = guild.get_channel(discord_channel_id) channel = guild.get_channel(discord_channel_id)
message = await channel.fetch_message(discord_message_id) message = await channel.fetch_message(discord_message_id)
emoji = List(discord.Emoji, [x for x in guild.emojis if x.name == rule.emoji_name]).single() emoji = List(discord.Emoji, guild.emojis).where(lambda x: x.name == rule.emoji_name).single()
if emoji is None: if emoji is None:
self._logger.debug(__name__, f"Emoji {rule.emoji_name} not found") self._logger.debug(__name__, f"Emoji {rule.emoji_name} not found")

View File

@ -1,8 +1,9 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Union
import discord
from cpl_core.configuration import ConfigurationABC from cpl_core.configuration import ConfigurationABC
from cpl_core.database.context import DatabaseContextABC from cpl_core.database.context import DatabaseContextABC
from cpl_discord.container import Member, Guild
from cpl_discord.service import DiscordBotServiceABC from cpl_discord.service import DiscordBotServiceABC
from bot_core.abc.client_utils_abc import ClientUtilsABC from bot_core.abc.client_utils_abc import ClientUtilsABC
@ -65,76 +66,74 @@ class DataIntegrityService:
self._is_for_shutdown = False self._is_for_shutdown = False
async def check_data_integrity(self, is_for_shutdown=False): def _check_known_users(self):
self._logger.info(__name__, f"Data integrity service started") self._logger.debug(__name__, f"Start checking KnownUsers table, {len(self._bot.users)}")
if is_for_shutdown != self._is_for_shutdown: for u in self._bot.users:
self._is_for_shutdown = is_for_shutdown u: discord.User = u
try: try:
for g in self._bot.guilds: if u.bot:
self._logger.debug(__name__, f"Start check for server: {g.id}") self._logger.trace(__name__, f"User {u.id} is ignored, because its a bot")
s = self._get_or_create_server(g)
self._logger.debug(__name__, f"Start check for clients")
self._check_clients(g.id, s)
for m in [m for m in g.members if not m.bot]:
await self._check_default_role(m)
self._check_known_user(m.id)
self._logger.debug(__name__, f"Start check for member: {g.id}@{m.id}")
u = self._get_or_create_user(s, m.id)
self._logger.debug(__name__, f"Start check for user joined server: {g.id}@{m.id}")
self._check_user_join(g, m, u)
self._logger.debug(__name__, f"Start check for user joined voice channels: {g.id}@{m.id}")
self._check_user_joined_vc(g.id, m, u)
self._logger.debug(__name__, f"Start check for user joined game servers: {g.id}@{m.id}")
self._check_user_joined_gs(g.id, m.id, u)
self._logger.debug(__name__, f"Start check for user got achievements: {g.id}@{m.id}")
await self._check_for_user_achievements(u)
for m in [m for m in g.members if m.bot]:
u = self._users.find_user_by_discord_id_and_server_id(m.id, s.id)
if u is None:
continue continue
self._remove_bot(u) user = self._known_users.find_user_by_discord_id(u.id)
self._logger.info(__name__, f"Data integrity service finished") if user is not None:
except Exception as e: continue
self._logger.fatal(__name__, f"Checking data integrity failed", e)
def _get_or_create_server(self, guild: Guild) -> Server: self._logger.warn(__name__, f"Unknown user: {u.id}")
try: self._logger.debug(__name__, f"Add user: {u.id}")
server = self._servers.find_server_by_discord_id(guild.id) self._known_users.add_user(KnownUser(u.id))
if server is not None:
return server
self._logger.warn(__name__, f"Server not found in database: {guild.id}")
self._logger.debug(__name__, f"Add server: {guild.id}")
self._servers.add_server(Server(guild.id))
self._db_context.save_changes() self._db_context.save_changes()
server = self._servers.find_server_by_discord_id(guild.id) user = self._known_users.find_user_by_discord_id(u.id)
if server is None: if user is None:
self._logger.fatal(__name__, f"Cannot add server: {guild.id}") self._logger.fatal(__name__, f"Cannot add user: {u.id}")
self._logger.trace(__name__, f"Added server: {guild.id}") self._logger.debug(__name__, f"Added user: {u.id}")
return server except Exception as e:
self._logger.error(__name__, f"Cannot get user", e)
def _check_servers(self):
self._logger.debug(__name__, f"Start checking Servers table")
for g in self._bot.guilds:
g: discord.Guild = g
try:
server = self._servers.find_server_by_discord_id(g.id)
if server is not None:
continue
self._logger.warn(__name__, f"Server not found in database: {g.id}")
self._logger.debug(__name__, f"Add server: {g.id}")
self._servers.add_server(Server(g.id))
self._db_context.save_changes()
server = self._servers.find_server_by_discord_id(g.id)
if server is None:
self._logger.fatal(__name__, f"Cannot add server: {g.id}")
self._logger.debug(__name__, f"Added server: {g.id}")
except Exception as e: except Exception as e:
self._logger.error(__name__, f"Cannot get server", e) self._logger.error(__name__, f"Cannot get server", e)
def _check_clients(self, guild_id: int, server: Server): results = self._servers.get_servers()
if results is None or len(results) == 0:
self._logger.error(__name__, f"Table Servers is empty!")
def _check_clients(self):
self._logger.debug(__name__, f"Start checking Clients table")
for g in self._bot.guilds:
g: discord.Guild = g
try: try:
server: Server = self._servers.find_server_by_discord_id(g.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {g.id}")
client = self._clients.find_client_by_server_id(server.id) client = self._clients.find_client_by_server_id(server.id)
if client is not None: if client is not None:
return continue
self._logger.warn( self._logger.warn(
__name__, __name__,
f"Client for server {guild_id} not found in database: {self._bot.user.id}", f"Client for server {g.id} not found in database: {self._bot.user.id}",
) )
self._logger.debug(__name__, f"Add client: {self._bot.user.id}") self._logger.debug(__name__, f"Add client: {self._bot.user.id}")
self._clients.add_client(Client(self._bot.user.id, 0, 0, 0, 0, 0, server)) self._clients.add_client(Client(self._bot.user.id, 0, 0, 0, 0, 0, server))
@ -144,10 +143,10 @@ class DataIntegrityService:
if client is None: if client is None:
self._logger.fatal( self._logger.fatal(
__name__, __name__,
f"Cannot add client {self._bot.user.id} for server {guild_id}", f"Cannot add client {self._bot.user.id} for server {g.id}",
) )
self._logger.trace(__name__, f"Added client: {guild_id}") self._logger.debug(__name__, f"Added client: {g.id}")
except Exception as e: except Exception as e:
self._logger.error(__name__, f"Cannot get client", e) self._logger.error(__name__, f"Cannot get client", e)
@ -155,37 +154,32 @@ class DataIntegrityService:
if results is None or len(results) == 0: if results is None or len(results) == 0:
self._logger.error(__name__, f"Table Servers is empty!") self._logger.error(__name__, f"Table Servers is empty!")
def _check_known_user(self, member_id: int): def _check_users(self):
self._logger.debug(__name__, f"Start checking Users table")
for g in self._bot.guilds:
g: discord.Guild = g
try: try:
if self._known_users.find_user_by_discord_id(member_id) is not None: server = self._servers.find_server_by_discord_id(g.id)
return if server is None:
self._logger.fatal(__name__, f"Server not found in database: {g.id}")
self._logger.warn(__name__, f"Unknown user: {member_id}") for u in g.members:
self._logger.trace(__name__, f"Add known user: {member_id}") u: Union[discord.Member, discord.User] = u
self._known_users.add_user(KnownUser(member_id)) if u.bot:
self._db_context.save_changes() self._logger.trace(__name__, f"User {u.id} is ignored, because its a bot")
continue
user = self._known_users.find_user_by_discord_id(member_id) user = self._users.find_user_by_discord_id_and_server_id(u.id, server.id)
if user is None:
self._logger.fatal(__name__, f"Cannot add user: {member_id}")
self._logger.trace(__name__, f"Added known user: {member_id}")
except Exception as e:
self._logger.error(__name__, f"Cannot get user", e)
def _get_or_create_user(self, server: Server, member_id: int) -> User:
try:
user = self._users.find_user_by_discord_id_and_server_id(member_id, server.id)
if user is not None: if user is not None:
return user continue
self._logger.warn(__name__, f"User not found in database: {member_id}") self._logger.warn(__name__, f"User not found in database: {u.id}")
self._logger.debug(__name__, f"Add user: {member_id}") self._logger.debug(__name__, f"Add user: {u.id}")
self._users.add_user(User(member_id, 0, 0, 0, None, server)) self._users.add_user(User(u.id, 0, 0, 0, None, server))
self._db_context.save_changes() self._db_context.save_changes()
self._logger.trace(__name__, f"Added User: {member_id}") self._logger.debug(__name__, f"Added User: {u.id}")
return self._users.get_user_by_discord_id_and_server_id(member_id, server.id)
except Exception as e: except Exception as e:
self._logger.error(__name__, f"Cannot get User", e) self._logger.error(__name__, f"Cannot get User", e)
@ -193,34 +187,63 @@ class DataIntegrityService:
if results is None or len(results) == 0: if results is None or len(results) == 0:
self._logger.error(__name__, f"Table Users is empty!") self._logger.error(__name__, f"Table Users is empty!")
def _check_user_join(self, guild: Guild, member: Member, user: User): def _check_user_joins(self):
self._logger.debug(__name__, f"Start checking UserJoinedServers table")
for guild in self._bot.guilds:
guild: discord.Guild = guild
server = self._servers.find_server_by_discord_id(guild.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
try: try:
for u in guild.members:
u: discord.User = u
if u.bot:
self._logger.trace(__name__, f"User {u.id} is ignored, because its a bot")
continue
user = self._users.find_user_by_discord_id_and_server_id(u.id, server.id)
if user is None:
self._logger.fatal(__name__, f"User not found in database: {u.id}")
join = self._user_joins.find_active_user_joined_server_by_user_id(user.id) join = self._user_joins.find_active_user_joined_server_by_user_id(user.id)
if join is not None: if join is not None:
return continue
m: discord.Member = u
self._logger.warn( self._logger.warn(
__name__, __name__,
f"Active UserJoinedServer not found in database: {guild.id}:{member.id}@{member.joined_at}", f"Active UserJoinedServer not found in database: {guild.id}:{u.id}@{m.joined_at}",
) )
self._logger.debug( self._logger.debug(
__name__, __name__,
f"Add UserJoinedServer: {guild.id}:{member.id}@{member.joined_at}", f"Add UserJoinedServer: {guild.id}:{u.id}@{m.joined_at}",
)
self._user_joins.add_user_joined_server(
UserJoinedServer(user, self._dtp.transform(m.joined_at), None)
) )
self._user_joins.add_user_joined_server(UserJoinedServer(user, self._dtp.transform(member.joined_at), None))
self._db_context.save_changes() self._db_context.save_changes()
self._logger.trace(__name__, f"Added UserJoinedServer: {member.id}") self._logger.debug(__name__, f"Added UserJoinedServer: {u.id}")
except Exception as e: except Exception as e:
self._logger.error(__name__, f"Cannot get UserJoinedServer", e) self._logger.error(__name__, f"Cannot get UserJoinedServer", e)
try: results = self._users.get_users()
if results is None or len(results) == 0:
self._logger.error(__name__, f"Table Users is empty!")
joins = self._user_joins.get_user_joined_servers() joins = self._user_joins.get_user_joined_servers()
for join in [x for x in joins if x.user.server.discord_id == guild.id and x.leaved_on is None]: for join in joins:
dc_user = guild.get_member(join.user.discord_id) join: UserJoinedServer = join
if dc_user is not None: if join.user.server.discord_id != guild.id:
continue continue
if join.leaved_on is not None:
continue
dc_user = guild.get_member(join.user.discord_id)
if dc_user is None:
self._logger.warn( self._logger.warn(
__name__, __name__,
f"User {join.user.discord_id} already left the server.", f"User {join.user.discord_id} already left the server.",
@ -229,26 +252,42 @@ class DataIntegrityService:
self._user_joins.update_user_joined_server(join) self._user_joins.update_user_joined_server(join)
self._db_context.save_changes() self._db_context.save_changes()
except Exception as e:
self._logger.error(__name__, f"Cannot update UserJoinedServer", e)
def _check_user_joined_vc(self, guild_id: int, member: Member, user: User): def _check_user_joins_vc(self):
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{guild_id}") self._logger.debug(__name__, f"Start checking UserJoinedVoiceChannel table")
for guild in self._bot.guilds:
guild: discord.Guild = guild
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{guild.id}")
server = self._servers.find_server_by_discord_id(guild.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
try: try:
# close open voice states # close open voice states
for member in guild.members:
if member.bot:
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
continue
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
if user is None:
self._logger.fatal(__name__, f"User not found in database: {member.id}")
joins = self._user_joins_vc.find_active_user_joined_voice_channels_by_user_id(user.id) joins = self._user_joins_vc.find_active_user_joined_voice_channels_by_user_id(user.id)
if joins is None or len(joins) == 0: if joins is None or len(joins) == 0:
return continue
for join in joins: for join in joins:
self._logger.warn( self._logger.warn(
__name__, __name__,
f"Active UserJoinedVoiceChannel found in database: {guild_id}:{member.id}@{join.joined_on}", f"Active UserJoinedVoiceChannel found in database: {guild.id}:{member.id}@{join.joined_on}",
) )
join.leaved_on = datetime.now() join.leaved_on = datetime.now()
if ((join.leaved_on - join.joined_on).total_seconds() / 60 / 60) > settings.max_voice_state_hours: if (
(join.leaved_on - join.joined_on).total_seconds() / 60 / 60
) > settings.max_voice_state_hours:
join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours) join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours)
self._user_joins_vc.update_user_joined_voice_channel(join) self._user_joins_vc.update_user_joined_voice_channel(join)
@ -262,30 +301,59 @@ class DataIntegrityService:
return return
# add open voice states # add open voice states
for member in guild.members:
if member.bot:
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
continue
if member.voice is None or member.voice.channel.id in settings.afk_channel_ids: if member.voice is None or member.voice.channel.id in settings.afk_channel_ids:
return continue
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
if user is None:
self._logger.fatal(__name__, f"User not found in database: {member.id}")
join = UserJoinedVoiceChannel(user, member.voice.channel.id, datetime.now()) join = UserJoinedVoiceChannel(user, member.voice.channel.id, datetime.now())
self._user_joins_vc.add_user_joined_voice_channel(join) self._user_joins_vc.add_user_joined_voice_channel(join)
self._db_context.save_changes() self._db_context.save_changes()
except Exception as e: except Exception as e:
self._logger.error(__name__, f"Cannot get UserJoinedVoiceChannel", e) self._logger.error(__name__, f"Cannot get UserJoinedVoiceChannel", e)
def _check_user_joined_gs(self, guild_id: int, member_id: int, user: User): def _check_user_joined_gs(self):
self._logger.debug(__name__, f"Start checking UserJoinedGameServer table")
for guild in self._bot.guilds:
guild: discord.Guild = guild
server = self._servers.find_server_by_discord_id(guild.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
try: try:
for member in guild.members:
if member.bot:
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
continue
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
if user is None:
self._logger.fatal(__name__, f"User not found in database: {member.id}")
joins = self._user_joined_gs.find_active_user_joined_game_servers_by_user_id(user.id) joins = self._user_joined_gs.find_active_user_joined_game_servers_by_user_id(user.id)
if joins is None or len(joins) == 0: if joins is None or len(joins) == 0:
return continue
for join in joins: for join in joins:
self._logger.warn( self._logger.warn(
__name__, __name__,
f"Active UserJoinedGameServer found in database: {guild_id}:{member_id}@{join.joined_on}", f"Active UserJoinedGameServer found in database: {guild.id}:{member.id}@{join.joined_on}",
) )
join.leaved_on = datetime.now() join.leaved_on = datetime.now()
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{guild_id}") settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{guild.id}")
if join.time > settings.max_voice_state_hours: if (
(join.leaved_on - join.joined_on).total_seconds() / 60 / 60
) > settings.max_voice_state_hours:
join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours) join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours)
self._user_joined_gs.update_user_joined_game_server(join) self._user_joined_gs.update_user_joined_game_server(join)
@ -297,19 +365,38 @@ class DataIntegrityService:
except Exception as e: except Exception as e:
self._logger.error(__name__, f"Cannot get UserJoinedGameServer", e) self._logger.error(__name__, f"Cannot get UserJoinedGameServer", e)
async def _check_for_user_achievements(self, user: User): async def _check_for_user_achievements(self):
try: self._logger.debug(__name__, f"Start checking UserGotAchievement table")
await self._achievements.validate_achievements_for_user(user)
except Exception as e:
self._logger.error(__name__, f"Cannot check UserGotAchievement for {user.id}", e)
async def _check_default_role(self, member: Member): for guild in self._bot.guilds:
server = self._servers.find_server_by_discord_id(guild.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
for member in guild.members:
if member.bot:
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
continue
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
if user is None:
self._logger.fatal(__name__, f"User not found in database: {member.id}")
await self._achievements.validate_achievements_for_user(user)
async def _check_default_role(self):
for guild in self._bot.guilds:
for member in guild.members:
await self._client_utils.check_default_role(member) await self._client_utils.check_default_role(member)
def _remove_bot(self, user: User): def _check_for_bots(self):
known_user = self._known_users.find_user_by_discord_id(user.discord_id) for guild in self._bot.guilds:
if known_user is not None: server = self._servers.get_server_by_discord_id(guild.id)
self._known_users.delete_user(known_user)
for member in guild.members.where(lambda x: x.bot):
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
if user is None:
continue
for join in self._user_joins.get_user_joined_servers_by_user_id(user.id): for join in self._user_joins.get_user_joined_servers_by_user_id(user.id):
self._user_joins.delete_user_joined_server(join) self._user_joins.delete_user_joined_server(join)
@ -317,3 +404,18 @@ class DataIntegrityService:
self._user_joins_vc.delete_user_joined_voice_channel_by_user_id(user.id) self._user_joins_vc.delete_user_joined_voice_channel_by_user_id(user.id)
self._users.delete_user(user) self._users.delete_user(user)
self._db_context.save_changes() self._db_context.save_changes()
async def check_data_integrity(self, is_for_shutdown=False):
if is_for_shutdown != self._is_for_shutdown:
self._is_for_shutdown = is_for_shutdown
await self._check_default_role()
self._check_known_users()
self._check_servers()
self._check_clients()
self._check_users()
self._check_user_joins()
self._check_user_joins_vc()
self._check_user_joined_gs()
await self._check_for_user_achievements()
self._check_for_bots()

View File

@ -1,129 +0,0 @@
from typing import Optional
import discord
from cpl_core.configuration import ConfigurationABC
from cpl_core.logging import LoggerABC
from cpl_discord.service import DiscordBotServiceABC
from bot_core.abc.permission_service_abc import PermissionServiceABC
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
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
# member_id: {team_member_type: {guild_id: bool}}
self._cache: dict[int, dict[TeamMemberTypeEnum, dict[int, bool]]] = {}
def reset_cache(self):
self._cache = {}
def get_cached_permission(
self, member_id: int, team_member_type: TeamMemberTypeEnum, guild_id: int = None
) -> Optional[bool]:
if member_id not in self._cache:
self._cache[member_id] = {}
if team_member_type not in self._cache[member_id]:
self._cache[member_id][team_member_type] = {}
return None
if guild_id not in self._cache[member_id][team_member_type]:
return None
return self._cache[member_id][team_member_type][guild_id]
def set_cached_permission(
self, value: bool, member_id: int, team_member_type: TeamMemberTypeEnum, guild_id: int = None
):
if member_id not in self._cache:
self._cache[member_id] = {}
if team_member_type not in self._cache[member_id]:
self._cache[member_id][team_member_type] = {}
self._cache[member_id][team_member_type][guild_id] = value
def _has_member_role(self, member: discord.Member, team_member_type: TeamMemberTypeEnum) -> bool:
if member is None or member.guild is None:
return False
try:
has_permission_cached = self.get_cached_permission(member.id, team_member_type, member.guild.id)
if has_permission_cached is not None:
return has_permission_cached
self._logger.debug(__name__, f"Checking is member {member.name} {team_member_type.value}")
has_permission = True in [
member.guild.get_role(x.role_id) in member.roles
for x in self._server_configs.get_server_config_by_server(
self._servers.get_server_by_discord_id(member.guild.id).id
).team_role_ids
if x.team_member_type == team_member_type
]
self.set_cached_permission(has_permission, member.id, team_member_type, member.guild.id)
return has_permission
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
has_permission_cached = self.get_cached_permission(member.id, TeamMemberTypeEnum.technician)
if has_permission_cached is not None:
return has_permission_cached
self._logger.debug(__name__, f"Checking is member {member.name} technician")
try:
has_permission = member.id in self._technician_configs.get_technician_config().technician_ids
self.set_cached_permission(has_permission, member.id, TeamMemberTypeEnum.technician)
return has_permission
except Exception as e:
self._logger.error(__name__, "Permission check failed", e)
return False
def is_member_technician_by_id(self, member_id: int):
has_permission_cached = self.get_cached_permission(member_id, TeamMemberTypeEnum.technician)
if has_permission_cached is not None:
return has_permission_cached
self._logger.debug(__name__, f"Checking is member {member_id} technician")
try:
has_permission = member_id in self._technician_configs.get_technician_config().technician_ids
self.set_cached_permission(has_permission, member_id, TeamMemberTypeEnum.technician)
return has_permission
except Exception as e:
self._logger.error(__name__, "Permission check failed", e)
return False

View File

@ -15,7 +15,7 @@ __title__ = "bot_data"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports # imports
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -15,7 +15,7 @@ __title__ = "bot_data.abc"
__author__ = "Sven Heidemann" __author__ = "Sven Heidemann"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.8" __version__ = "1.2.0"
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports # imports
VersionInfo = namedtuple("VersionInfo", "major minor micro") VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="8") version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -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

View File

@ -19,6 +19,10 @@ class UserJoinedServerRepositoryABC(ABC):
def get_user_joined_server_by_id(self, id: int) -> UserJoinedServer: def get_user_joined_server_by_id(self, id: int) -> UserJoinedServer:
pass pass
@abstractmethod
def get_user_joined_server_by_server_id(self, server_id: int) -> UserJoinedServer:
pass
@abstractmethod @abstractmethod
def get_user_joined_servers_by_user_id(self, user_id: int) -> list[UserJoinedServer]: def get_user_joined_servers_by_user_id(self, user_id: int) -> list[UserJoinedServer]:
pass pass

View File

@ -31,10 +31,6 @@ class UserRepositoryABC(ABC):
def get_users_by_server_id(self, server_id: int) -> List[User]: def get_users_by_server_id(self, server_id: int) -> List[User]:
pass pass
@abstractmethod
def get_users_with_activity_by_server_id(self, server_id: int) -> List[User]:
pass
@abstractmethod @abstractmethod
def get_user_by_discord_id_and_server_id(self, discord_id: int, server_id: int) -> User: def get_user_by_discord_id_and_server_id(self, discord_id: int, server_id: int) -> User:
pass pass

View File

@ -18,10 +18,6 @@ class UserWarningsRepositoryABC(ABC):
def get_user_warnings_by_id(self, id: int) -> UserWarnings: def get_user_warnings_by_id(self, id: int) -> UserWarnings:
pass pass
@abstractmethod
def get_user_warnings_by_server_id(self, server_id: int) -> List[UserWarnings]:
pass
@abstractmethod @abstractmethod
def get_user_warnings_by_user_id(self, user_id: int) -> List[UserWarnings]: def get_user_warnings_by_user_id(self, user_id: int) -> List[UserWarnings]:
pass pass

View File

@ -4,7 +4,7 @@
"Version": { "Version": {
"Major": "1", "Major": "1",
"Minor": "2", "Minor": "2",
"Micro": "8" "Micro": "0"
}, },
"Author": "Sven Heidemann", "Author": "Sven Heidemann",
"AuthorEmail": "sven.heidemann@sh-edraft.de", "AuthorEmail": "sven.heidemann@sh-edraft.de",

View File

@ -14,7 +14,6 @@ from bot_data.abc.data_seeder_abc import DataSeederABC
from bot_data.abc.game_server_repository_abc import GameServerRepositoryABC from bot_data.abc.game_server_repository_abc import GameServerRepositoryABC
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
from bot_data.abc.level_repository_abc import LevelRepositoryABC from bot_data.abc.level_repository_abc import LevelRepositoryABC
from bot_data.abc.scheduled_event_repository_abc import ScheduledEventRepositoryABC
from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.short_role_name_repository_abc import ShortRoleNameRepositoryABC from bot_data.abc.short_role_name_repository_abc import ShortRoleNameRepositoryABC
@ -46,7 +45,6 @@ from bot_data.service.client_repository_service import ClientRepositoryService
from bot_data.service.game_server_repository_service import GameServerRepositoryService from bot_data.service.game_server_repository_service import GameServerRepositoryService
from bot_data.service.known_user_repository_service import KnownUserRepositoryService from bot_data.service.known_user_repository_service import KnownUserRepositoryService
from bot_data.service.level_repository_service import LevelRepositoryService from bot_data.service.level_repository_service import LevelRepositoryService
from bot_data.service.scheduled_event_repository_service import ScheduledEventRepositoryService
from bot_data.service.seeder_service import SeederService from bot_data.service.seeder_service import SeederService
from bot_data.service.server_config_repository_service import ( from bot_data.service.server_config_repository_service import (
ServerConfigRepositoryService, ServerConfigRepositoryService,
@ -117,7 +115,6 @@ class DataModule(ModuleABC):
services.add_transient(ServerConfigRepositoryABC, ServerConfigRepositoryService) services.add_transient(ServerConfigRepositoryABC, ServerConfigRepositoryService)
services.add_transient(ShortRoleNameRepositoryABC, ShortRoleNameRepositoryService) services.add_transient(ShortRoleNameRepositoryABC, ShortRoleNameRepositoryService)
services.add_transient(SteamSpecialOfferRepositoryABC, SteamSpecialOfferRepositoryService) services.add_transient(SteamSpecialOfferRepositoryABC, SteamSpecialOfferRepositoryService)
services.add_transient(ScheduledEventRepositoryABC, ScheduledEventRepositoryService)
services.add_transient(SeederService) services.add_transient(SeederService)
services.add_transient(DataSeederABC, TechnicianConfigSeeder) services.add_transient(DataSeederABC, TechnicianConfigSeeder)

View File

@ -1,50 +0,0 @@
from typing import Optional
from cpl_core.database import DatabaseSettings
from cpl_core.database.connection import DatabaseConnectionABC
from mysql.connector.abstracts import MySQLConnectionAbstract
from mysql.connector.cursor import MySQLCursorBuffered
class DBConnection(DatabaseConnectionABC):
def __init__(self):
DatabaseConnectionABC.__init__(self)
self._database: Optional[MySQLConnectionAbstract] = None
self._cursor: Optional[MySQLCursorBuffered] = None
@property
def server(self) -> MySQLConnectionAbstract:
return self._database
@property
def cursor(self) -> MySQLCursorBuffered:
return self._cursor
def connect(self, settings: DatabaseSettings):
# connection = sql.connect(
# host=settings.host,
# port=settings.port,
# user=settings.user,
# passwd=CredentialManager.decrypt(settings.password),
# charset=settings.charset,
# use_unicode=settings.use_unicode,
# buffered=settings.buffered,
# auth_plugin=settings.auth_plugin,
# ssl_disabled=settings.ssl_disabled,
# )
# connection.cursor().execute(f"CREATE DATABASE IF NOT EXISTS `{settings.database}`;")
# self._database = sql.connect(
# host=settings.host,
# port=settings.port,
# user=settings.user,
# passwd=CredentialManager.decrypt(settings.password),
# db=settings.database,
# charset=settings.charset,
# use_unicode=settings.use_unicode,
# buffered=settings.buffered,
# auth_plugin=settings.auth_plugin,
# ssl_disabled=settings.ssl_disabled,
# )
self._
self._cursor = self._database.cursor()

View File

@ -1,12 +1,9 @@
import uuid import time
from cpl_core.database import DatabaseSettings from cpl_core.database import DatabaseSettings
from cpl_core.database.context import DatabaseContext from cpl_core.database.context import DatabaseContext
from bot_core.exception.service_error_code_enum import ServiceErrorCode
from bot_core.exception.service_exception import ServiceException
from bot_core.logging.database_logger import DatabaseLogger from bot_core.logging.database_logger import DatabaseLogger
from bot_data.mysql_pool import MySQLPool
class DBContext(DatabaseContext): class DBContext(DatabaseContext):
@ -14,45 +11,36 @@ class DBContext(DatabaseContext):
self._logger = logger self._logger = logger
DatabaseContext.__init__(self) DatabaseContext.__init__(self)
self._pool: MySQLPool = None
self._fails = 0 self._fails = 0
def connect(self, database_settings: DatabaseSettings): def connect(self, database_settings: DatabaseSettings):
try: try:
self._logger.debug(__name__, "Connecting to database") self._logger.debug(__name__, "Connecting to database")
self._pool = MySQLPool(database_settings) self._db.connect(database_settings)
self._pool.execute(f"CREATE DATABASE IF NOT EXISTS `{database_settings.database}`;", commit=True)
self._logger.info(__name__, "Connected to database") self._logger.info(__name__, "Connected to database")
except Exception as e: except Exception as e:
self._logger.fatal(__name__, "Connecting to database failed", e) self._logger.fatal(__name__, "Connecting to database failed", e)
@property
def cursor(self):
return self
def save_changes(self): def save_changes(self):
pass try:
self._logger.trace(__name__, "Save changes")
super(DBContext, self).save_changes()
self._logger.debug(__name__, "Saved changes")
except Exception as e:
self._logger.error(__name__, "Saving changes failed", e)
def select(self, statement: str) -> list[tuple]: def select(self, statement: str) -> list[tuple]:
try: try:
return self._pool.execute(statement) return super(DBContext, self).select(statement)
except Exception as e: except Exception as e:
if self._fails >= 3: if self._fails >= 3:
self._logger.error(__name__, f"Database error caused by {statement}", e) self._logger.fatal(__name__, f"Database error caused by {statement}", e)
uid = uuid.uuid4()
raise ServiceException(
ServiceErrorCode.Unknown,
f"Query failed three times with {type(e).__name__}. Contact an admin and give them the UID: {uid}",
)
self._logger.error(__name__, f"Database error caused by {statement}", e) self._logger.error(__name__, f"Database error caused by {statement}", e)
self._fails += 1 self._fails += 1
try: try:
self._logger.debug(__name__, "Retry select") time.sleep(0.5)
return self.select(statement) return self.select(statement)
except Exception as e: except Exception as e:
pass pass
return [] return []
def execute(self, statement: str):
return self._pool.execute(statement, commit=True)

View File

@ -0,0 +1,26 @@
# -*- 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__ = "bot_data.migration"
__author__ = "Sven Heidemann"
__license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "1.2.0"
from collections import namedtuple
# imports
VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="1", minor="2", micro="0")

View File

@ -0,0 +1,127 @@
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.abc.migration_abc import MigrationABC
from bot_data.db_context import DBContext
class AchievementsMigration(MigrationABC):
name = "1.1.0_AchievementsMigration"
def __init__(self, logger: DatabaseLogger, db: DBContext):
MigrationABC.__init__(self)
self._logger = logger
self._db = db
self._cursor = db.cursor
def upgrade(self):
self._logger.debug(__name__, "Running upgrade")
self._cursor.execute(
str(
f"""
CREATE TABLE IF NOT EXISTS `Achievements` (
`Id` BIGINT NOT NULL AUTO_INCREMENT,
`Name` VARCHAR(255) NOT NULL,
`Description` VARCHAR(255) NOT NULL,
`Attribute` VARCHAR(255) NOT NULL,
`Operator` VARCHAR(255) NOT NULL,
`Value` VARCHAR(255) NOT NULL,
`ServerId` BIGINT,
`CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6),
`LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
PRIMARY KEY(`Id`),
FOREIGN KEY (`ServerId`) REFERENCES `Servers`(`ServerId`)
);
"""
)
)
self._cursor.execute(
str(
f"""
CREATE TABLE IF NOT EXISTS `AchievementsHistory`
(
`Id` BIGINT(20) NOT NULL,
`Name` VARCHAR(255) NOT NULL,
`Description` VARCHAR(255) NOT NULL,
`Attribute` VARCHAR(255) NOT NULL,
`Operator` VARCHAR(255) NOT NULL,
`Value` VARCHAR(255) NOT NULL,
`ServerId` BIGINT,
`Deleted` BOOL DEFAULT FALSE,
`DateFrom` DATETIME(6) NOT NULL,
`DateTo` DATETIME(6) NOT NULL
);
"""
)
)
self._cursor.execute(
str(
f"""
CREATE TABLE IF NOT EXISTS `UserGotAchievements` (
`Id` BIGINT NOT NULL AUTO_INCREMENT,
`UserId` BIGINT,
`AchievementId` BIGINT,
`CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6),
`LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
PRIMARY KEY(`Id`),
FOREIGN KEY (`UserId`) REFERENCES `Users`(`UserId`),
FOREIGN KEY (`AchievementId`) REFERENCES `Achievements`(`Id`)
);
"""
)
)
# A join table history between users and achievements is not necessary.
self._cursor.execute(str(f"""ALTER TABLE Users ADD MessageCount BIGINT NOT NULL DEFAULT 0 AFTER XP;"""))
self._cursor.execute(str(f"""ALTER TABLE Users ADD ReactionCount BIGINT NOT NULL DEFAULT 0 AFTER XP;"""))
self._cursor.execute(str(f"""ALTER TABLE UsersHistory ADD MessageCount BIGINT NOT NULL DEFAULT 0 AFTER XP;"""))
self._cursor.execute(str(f"""ALTER TABLE UsersHistory ADD ReactionCount BIGINT NOT NULL DEFAULT 0 AFTER XP;"""))
self._cursor.execute(str(f"""DROP TRIGGER IF EXISTS `TR_AchievementsUpdate`;"""))
self._cursor.execute(
str(
f"""
CREATE TRIGGER `TR_AchievementsUpdate`
AFTER UPDATE
ON `Achievements`
FOR EACH ROW
BEGIN
INSERT INTO `AchievementsHistory` (
`Id`, `Name`, `Description`, `Attribute`, `Operator`, `Value`, `ServerId`, `DateFrom`, `DateTo`
)
VALUES (
OLD.Id, OLD.Name, OLD.Description, OLD.Attribute, OLD.Operator, OLD.Value, OLD.ServerId, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)
);
END;
"""
)
)
self._cursor.execute(str(f"""DROP TRIGGER IF EXISTS `TR_AchievementsDelete`;"""))
self._cursor.execute(
str(
f"""
CREATE TRIGGER `TR_AchievementsDelete`
AFTER DELETE
ON `Achievements`
FOR EACH ROW
BEGIN
INSERT INTO `AchievementsHistory` (
`Id`, `Name`, `Description`, `Attribute`, `Operator`, `Value`, `ServerId`, `Deleted`, `DateFrom`, `DateTo`
)
VALUES (
OLD.Id, OLD.Name, OLD.Description, OLD.Attribute, OLD.Operator, OLD.Value, OLD.ServerId, TRUE, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)
);
END;
"""
)
)
def downgrade(self):
self._cursor.execute("DROP TABLE `Achievements`;")
self._cursor.execute(str(f"""ALTER TABLE Users DROP COLUMN MessageCount;"""))
self._cursor.execute(str(f"""ALTER TABLE Users DROP COLUMN ReactionCount;"""))

View File

@ -0,0 +1,38 @@
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.abc.migration_abc import MigrationABC
from bot_data.db_context import DBContext
class ApiKeyMigration(MigrationABC):
name = "1.0.0_ApiKeyMigration"
def __init__(self, logger: DatabaseLogger, db: DBContext):
MigrationABC.__init__(self)
self._logger = logger
self._db = db
self._cursor = db.cursor
def upgrade(self):
self._logger.debug(__name__, "Running upgrade")
self._cursor.execute(
str(
f"""
CREATE TABLE IF NOT EXISTS `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`)
);
"""
)
)
def downgrade(self):
self._cursor.execute("DROP TABLE `ApiKeys`;")

View File

@ -0,0 +1,61 @@
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.abc.migration_abc import MigrationABC
from bot_data.db_context import DBContext
class ApiMigration(MigrationABC):
name = "0.3_ApiMigration"
def __init__(self, logger: DatabaseLogger, db: DBContext):
MigrationABC.__init__(self)
self._logger = logger
self._db = db
self._cursor = db.cursor
def upgrade(self):
self._logger.debug(__name__, "Running upgrade")
self._cursor.execute(
str(
f"""
CREATE TABLE IF NOT EXISTS `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`)
);
"""
)
)
self._cursor.execute(
str(
f"""
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`)
);
"""
)
)
def downgrade(self):
self._cursor.execute("DROP TABLE `AuthUsers`;")
self._cursor.execute("DROP TABLE `AuthUserUsersRelations`;")

View File

@ -0,0 +1,33 @@
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.abc.migration_abc import MigrationABC
from bot_data.db_context import DBContext
class AutoRoleFix1Migration(MigrationABC):
name = "0.3.0_AutoRoleFixMigration"
def __init__(self, logger: DatabaseLogger, db: DBContext):
MigrationABC.__init__(self)
self._logger = logger
self._db = db
self._cursor = db.cursor
def upgrade(self):
self._logger.debug(__name__, "Running upgrade")
self._cursor.execute(
str(
f"""
ALTER TABLE AutoRoles ADD DiscordChannelId BIGINT NOT NULL AFTER ServerId;
"""
)
)
def downgrade(self):
self._cursor.execute(
str(
f"""
ALTER TABLE AutoRoles DROP COLUMN DiscordChannelId;
"""
)
)

View File

@ -0,0 +1,53 @@
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.abc.migration_abc import MigrationABC
from bot_data.db_context import DBContext
class AutoRoleMigration(MigrationABC):
name = "0.2.1_AutoRoleMigration"
def __init__(self, logger: DatabaseLogger, db: DBContext):
MigrationABC.__init__(self)
self._logger = logger
self._db = db
self._cursor = db.cursor
def upgrade(self):
self._logger.debug(__name__, "Running upgrade")
self._cursor.execute(
str(
f"""
CREATE TABLE IF NOT EXISTS `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`)
);
"""
)
)
self._cursor.execute(
str(
f"""
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`)
);
"""
)
)
def downgrade(self):
self._cursor.execute("DROP TABLE `AutoRole`;")
self._cursor.execute("DROP TABLE `AutoRoleRules`;")

View File

@ -0,0 +1,84 @@
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.abc.migration_abc import MigrationABC
from bot_data.db_context import DBContext
class BirthdayMigration(MigrationABC):
name = "1.2.0_BirthdayMigration"
def __init__(self, logger: DatabaseLogger, db: DBContext):
MigrationABC.__init__(self)
self._logger = logger
self._db = db
self._cursor = db.cursor
def upgrade(self):
self._logger.debug(__name__, "Running upgrade")
self._cursor.execute(
str(
f"""
ALTER TABLE Users
ADD Birthday DATE NULL AFTER MessageCount;
"""
)
)
self._cursor.execute(
str(
f"""
ALTER TABLE UsersHistory
ADD Birthday DATE NULL AFTER MessageCount;
"""
)
)
self._exec(__file__, "users.sql")
self._cursor.execute(
str(
f"""
ALTER TABLE CFG_Server
ADD XpForBirthday BIGINT(20) NOT NULL DEFAULT 0 AFTER XpPerAchievement;
"""
)
)
self._cursor.execute(
str(
f"""
ALTER TABLE CFG_ServerHistory
ADD XpForBirthday BIGINT(20) NOT NULL DEFAULT 0 AFTER XpPerAchievement;
"""
)
)
self._exec(__file__, "config/server.sql")
def downgrade(self):
self._cursor.execute(
str(
f"""
ALTER TABLE Users DROP COLUMN Birthday;
"""
)
)
self._cursor.execute(
str(
f"""
ALTER TABLE UsersHistory DROP COLUMN Birthday;
"""
)
)
self._cursor.execute(
str(
f"""
ALTER TABLE CFG_Server DROP COLUMN XpForBirthday;
"""
)
)
self._cursor.execute(
str(
f"""
ALTER TABLE CFG_ServerHistory DROP COLUMN XpForBirthday;
"""
)
)

View File

@ -0,0 +1,29 @@
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.abc.migration_abc import MigrationABC
from bot_data.db_context import DBContext
class ConfigFeatureFlagsMigration(MigrationABC):
name = "1.1.0_ConfigFeatureFlagsMigration"
def __init__(self, logger: DatabaseLogger, db: DBContext):
MigrationABC.__init__(self)
self._logger = logger
self._db = db
self._cursor = db.cursor
def upgrade(self):
self._logger.debug(__name__, "Running upgrade")
self._cursor.execute(
str("""ALTER TABLE CFG_Technician ADD FeatureFlags JSON NULL DEFAULT ('{}') AFTER CacheMaxMessages;""")
)
self._cursor.execute(
str("""ALTER TABLE CFG_Server ADD FeatureFlags JSON NULL DEFAULT ('{}') AFTER LoginMessageChannelId;""")
)
def downgrade(self):
self._logger.debug(__name__, "Running downgrade")
self._cursor.execute("ALTER TABLE CFG_Technician DROP COLUMN FeatureFlags;")
self._cursor.execute("ALTER TABLE CFG_Server DROP COLUMN FeatureFlags;")

View File

@ -0,0 +1,145 @@
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.abc.migration_abc import MigrationABC
from bot_data.db_context import DBContext
class ConfigMigration(MigrationABC):
name = "1.1.0_ConfigMigration"
def __init__(self, logger: DatabaseLogger, db: DBContext):
MigrationABC.__init__(self)
self._logger = logger
self._db = db
def upgrade(self):
self._logger.debug(__name__, "Running upgrade")
self._server_upgrade()
self._technician_upgrade()
self._exec(__file__, "config/server.sql")
self._exec(__file__, "config/server_afk_channels.sql")
self._exec(__file__, "config/server_team_roles.sql")
self._exec(__file__, "config/technician.sql")
self._exec(__file__, "config/technician_ids.sql")
self._exec(__file__, "config/technician_ping_urls.sql")
def _server_upgrade(self):
self._cursor.execute(
str(
f"""
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`)
);
"""
)
)
self._cursor.execute(
str(
f"""
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`)
);
"""
)
)
self._cursor.execute(
str(
f"""
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`)
);
"""
)
)
def _technician_upgrade(self):
self._cursor.execute(
str(
f"""
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`)
);
"""
)
)
self._cursor.execute(
str(
f"""
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`)
);
"""
)
)
self._cursor.execute(
str(
f"""
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`)
);
"""
)
)
def downgrade(self):
self._logger.debug(__name__, "Running downgrade")
self._server_downgrade()
self._technician_downgrade()
def _server_downgrade(self):
self._cursor.execute("DROP TABLE `CFG_Server`;")
def _technician_downgrade(self):
self._cursor.execute("DROP TABLE `CFG_Technician`;")
self._cursor.execute("DROP TABLE `CFG_TechnicianPingUrls`;")
self._cursor.execute("DROP TABLE `CFG_TechnicianIds`;")

View File

@ -0,0 +1,56 @@
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.abc.migration_abc import MigrationABC
from bot_data.db_context import DBContext
class DBHistoryMigration(MigrationABC):
name = "1.0.0_DBHistoryMigration"
prio = 1
def __init__(self, logger: DatabaseLogger, db: DBContext):
MigrationABC.__init__(self)
self._logger = logger
self._db = db
self._cursor = db.cursor
def upgrade(self):
self._logger.debug(__name__, "Running upgrade")
self._exec(__file__, "api_keys.sql")
self._exec(__file__, "auth_users.sql")
self._exec(__file__, "auth_user_users_relation.sql")
self._exec(__file__, "auto_role_rules.sql")
self._exec(__file__, "auto_roles.sql")
self._exec(__file__, "clients.sql")
self._exec(__file__, "game_servers.sql")
self._exec(__file__, "known_users.sql")
self._exec(__file__, "levels.sql")
self._exec(__file__, "servers.sql")
self._exec(__file__, "user_game_idents.sql")
self._exec(__file__, "user_joined_game_servers.sql")
self._exec(__file__, "user_joined_servers.sql")
self._exec(__file__, "user_joined_voice_channel.sql")
self._exec(__file__, "user_message_count_per_hour.sql")
self._exec(__file__, "users.sql")
self._exec(__file__, "user_warnings.sql")
self._logger.debug(__name__, "Finished history upgrade")
def downgrade(self):
self._cursor.execute("DROP TABLE `ApiKeysHistory`;")
self._cursor.execute("DROP TABLE `AuthUsersHistory`;")
self._cursor.execute("DROP TABLE `AuthUserUsersRelationsHistory`;")
self._cursor.execute("DROP TABLE `AutoRoleRulesHistory`;")
self._cursor.execute("DROP TABLE `AutoRolesHistory`;")
self._cursor.execute("DROP TABLE `ClientsHistory`;")
self._cursor.execute("DROP TABLE `GameServersHistory`;")
self._cursor.execute("DROP TABLE `KnownUsersHistory`;")
self._cursor.execute("DROP TABLE `LevelsHistory`;")
self._cursor.execute("DROP TABLE `ServersHistory`;")
self._cursor.execute("DROP TABLE `UserGameIdentsHistory`;")
self._cursor.execute("DROP TABLE `UserJoinedGameServerHistory`;")
self._cursor.execute("DROP TABLE `UserJoinedServersHistory`;")
self._cursor.execute("DROP TABLE `UserJoinedVoiceChannelHistory`;")
self._cursor.execute("DROP TABLE `UserMessageCountPerHourHistory`;")
self._cursor.execute("DROP TABLE `UsersHistory`;")
self._cursor.execute("DROP TABLE `UserWarningsHistory`;")

View File

@ -0,0 +1,46 @@
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;

View File

@ -0,0 +1,46 @@
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;

View File

@ -0,0 +1,62 @@
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;

View File

@ -0,0 +1,46 @@
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;

View File

@ -0,0 +1,48 @@
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;

View File

@ -0,0 +1,54 @@
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;

View File

@ -1,12 +1,29 @@
ALTER TABLE CFG_Server CREATE TABLE IF NOT EXISTS `CFG_ServerHistory`
ADD ResetMemberAfterRejoin BOOLEAN NOT NULL DEFAULT FALSE AFTER GameOfferNotificationChatId; (
`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,
`DefaultRoleId` BIGINT NULL,
`ShortRoleNameSetOnlyHighest` BOOLEAN NOT NULL DEFAULT FALSE,
`FeatureFlags` JSON NULL DEFAULT ('{}'),
`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`;
ALTER TABLE CFG_ServerHistory
ADD ResetMemberAfterRejoin BOOLEAN NOT NULL DEFAULT FALSE AFTER GameOfferNotificationChatId;
DROP TRIGGER IF EXISTS `TR_CFG_ServerUpdate`;;
CREATE TRIGGER `TR_CFG_ServerUpdate` CREATE TRIGGER `TR_CFG_ServerUpdate`
AFTER UPDATE AFTER UPDATE
@ -29,8 +46,6 @@ BEGIN
`LoginMessageChannelId`, `LoginMessageChannelId`,
`DefaultRoleId`, `DefaultRoleId`,
`ShortRoleNameSetOnlyHighest`, `ShortRoleNameSetOnlyHighest`,
`GameOfferNotificationChatId`,
`ResetMemberAfterRejoin`,
`FeatureFlags`, `FeatureFlags`,
`ServerId`, `ServerId`,
`DateFrom`, `DateFrom`,
@ -51,15 +66,13 @@ BEGIN
OLD.LoginMessageChannelId, OLD.LoginMessageChannelId,
OLD.DefaultRoleId, OLD.DefaultRoleId,
OLD.ShortRoleNameSetOnlyHighest, OLD.ShortRoleNameSetOnlyHighest,
OLD.GameOfferNotificationChatId,
OLD.ResetMemberAfterRejoin,
OLD.FeatureFlags, OLD.FeatureFlags,
OLD.ServerId, OLD.ServerId,
OLD.LastModifiedAt, OLD.LastModifiedAt,
CURRENT_TIMESTAMP(6)); CURRENT_TIMESTAMP(6));
END;; END;
DROP TRIGGER IF EXISTS `TR_CFG_ServerDelete`;; DROP TRIGGER IF EXISTS `TR_CFG_ServerDelete`;
CREATE TRIGGER `TR_CFG_ServerDelete` CREATE TRIGGER `TR_CFG_ServerDelete`
AFTER DELETE AFTER DELETE
@ -82,8 +95,6 @@ BEGIN
`LoginMessageChannelId`, `LoginMessageChannelId`,
`DefaultRoleId`, `DefaultRoleId`,
`ShortRoleNameSetOnlyHighest`, `ShortRoleNameSetOnlyHighest`,
`GameOfferNotificationChatId`,
`ResetMemberAfterRejoin`,
`ServerId`, `ServerId`,
`FeatureFlags`, `FeatureFlags`,
`Deleted`, `Deleted`,
@ -105,12 +116,9 @@ BEGIN
OLD.LoginMessageChannelId, OLD.LoginMessageChannelId,
OLD.DefaultRoleId, OLD.DefaultRoleId,
OLD.ShortRoleNameSetOnlyHighest, OLD.ShortRoleNameSetOnlyHighest,
OLD.GameOfferNotificationChatId,
OLD.ResetMemberAfterRejoin,
OLD.FeatureFlags, OLD.FeatureFlags,
OLD.ServerId, OLD.ServerId,
TRUE, TRUE,
OLD.LastModifiedAt, OLD.LastModifiedAt,
CURRENT_TIMESTAMP(6)); CURRENT_TIMESTAMP(6));
END;; END;

View File

@ -0,0 +1,57 @@
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;

View File

@ -0,0 +1,62 @@
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;

View File

@ -1,10 +1,19 @@
ALTER TABLE CFG_Technician CREATE TABLE IF NOT EXISTS `CFG_TechnicianHistory`
ADD Maintenance BOOLEAN DEFAULT FALSE AFTER MaxSteamOfferCount; (
`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,
`MaxSteamOfferCount` BIGINT NOT NULL DEFAULT 250,
`Maintenance` BOOLEAN DEFAULT FALSE,
`FeatureFlags` JSON NULL DEFAULT ('{}'),
`Deleted` BOOL DEFAULT FALSE,
`DateFrom` DATETIME(6) NOT NULL,
`DateTo` DATETIME(6) NOT NULL
);
ALTER TABLE CFG_TechnicianHistory DROP TRIGGER IF EXISTS `TR_CFG_TechnicianUpdate`;
ADD Maintenance BOOLEAN DEFAULT FALSE AFTER MaxSteamOfferCount;
DROP TRIGGER IF EXISTS `TR_CFG_TechnicianUpdate`;;
CREATE TRIGGER `TR_CFG_TechnicianUpdate` CREATE TRIGGER `TR_CFG_TechnicianUpdate`
AFTER UPDATE AFTER UPDATE
@ -31,9 +40,9 @@ BEGIN
OLD.FeatureFlags, OLD.FeatureFlags,
OLD.LastModifiedAt, OLD.LastModifiedAt,
CURRENT_TIMESTAMP(6)); CURRENT_TIMESTAMP(6));
END;; END;
DROP TRIGGER IF EXISTS `TR_CFG_TechnicianDelete`;; DROP TRIGGER IF EXISTS `TR_CFG_TechnicianDelete`;
CREATE TRIGGER `TR_CFG_TechnicianDelete` CREATE TRIGGER `TR_CFG_TechnicianDelete`
AFTER DELETE AFTER DELETE
@ -62,5 +71,4 @@ BEGIN
TRUE, TRUE,
OLD.LastModifiedAt, OLD.LastModifiedAt,
CURRENT_TIMESTAMP(6)); CURRENT_TIMESTAMP(6));
END;; END;

View File

@ -0,0 +1,52 @@
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;

View File

@ -0,0 +1,52 @@
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;

View File

@ -0,0 +1,46 @@
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;

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