diff --git a/.gitea/workflows/deploy_prod.yaml b/.gitea/workflows/deploy_prod.yaml index 09566db7..ea0aa6c1 100644 --- a/.gitea/workflows/deploy_prod.yaml +++ b/.gitea/workflows/deploy_prod.yaml @@ -81,7 +81,6 @@ jobs: run: | cd web docker image prune -f - cp src/favicon.ico src/favicon.ico npm run build docker build -t git.sh-edraft.de/sh-edraft.de/sdb-web:$(npm run -s gv) . diff --git a/bot/docker b/bot/docker index 36ed4305..fbcd9226 160000 --- a/bot/docker +++ b/bot/docker @@ -1 +1 @@ -Subproject commit 36ed43055df2979b5c4c486a161b1754803915cc +Subproject commit fbcd9226c4d199529fdbce5169b38b1b23074adb diff --git a/bot/src/bot/__init__.py b/bot/src/bot/__init__.py index ede30721..614dd9f0 100644 --- a/bot/src/bot/__init__.py +++ b/bot/src/bot/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot/bot.json b/bot/src/bot/bot.json index 7e04313a..477a78f1 100644 --- a/bot/src/bot/bot.json +++ b/bot/src/bot/bot.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "Sven Heidemann", "AuthorEmail": "sven.heidemann@sh-edraft.de", @@ -16,7 +16,6 @@ "LicenseName": "MIT", "LicenseDescription": "MIT, see LICENSE for more details.", "Dependencies": [ - "cpl-core==2023.10.1", "cpl-translation==2023.4.0.post1", "cpl-query==2023.10.0", "cpl-discord==2023.10.0.post1", @@ -34,7 +33,8 @@ "discord==2.3.2", "bs4==0.0.1", "lxml==4.9.3", - "python-valve==0.2.1" + "python-valve==0.2.1", + "cpl-core==2023.10.2" ], "DevDependencies": [ "cpl-cli==2023.4.0.post3", diff --git a/bot/src/bot/config b/bot/src/bot/config index be5b15f2..eeebd13f 160000 --- a/bot/src/bot/config +++ b/bot/src/bot/config @@ -1 +1 @@ -Subproject commit be5b15f227e7b2b12cc73c0edd7f6fa95dbdd52f +Subproject commit eeebd13f80c6ceecc922ede5771e55212a884019 diff --git a/bot/src/bot/extension/__init__.py b/bot/src/bot/extension/__init__.py index e2eb725e..3bc4b792 100644 --- a/bot/src/bot/extension/__init__.py +++ b/bot/src/bot/extension/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot.extension" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot/translation/de.json b/bot/src/bot/translation/de.json index 45f64e14..d6631bd1 100644 --- a/bot/src/bot/translation/de.json +++ b/bot/src/bot/translation/de.json @@ -2,22 +2,22 @@ "api": { "api": { "test_mail": { - "message": "Dies ist eine Test-Mail vom Krümelmonster Web Interface\nGesendet von {}-{}", + "message": "Dies ist eine Test-Mail vom Krümelmonster Web Interface\r\nGesendet von {}-{}", "subject": "Krümelmonster Web Interface Test-Mail" } }, "auth": { "confirmation": { - "message": "Öffne den Link, um die E-Mail zu bestätigen:\n{}auth/register/{}", + "message": "Öffne den Link, um die E-Mail zu bestätigen:\r\n{}auth/register/{}", "subject": "E-Mail für {} {} bestätigen" }, "forgot_password": { - "message": "Öffne den Link, um das Passwort zu ändern:\n{}auth/forgot-password/{}", + "message": "Öffne den Link, um das Passwort zu ändern:\r\n{}auth/forgot-password/{}", "subject": "Passwort für {} {} zurücksetzen" } }, "mail": { - "automatic_mail": "\n\nDies ist eine automatische E-Mail.\nGesendet von {}-{}@{}" + "automatic_mail": "\r\n\r\nDies ist eine automatische E-Mail.\r\nGesendet von {}-{}@{}" } }, "common": { diff --git a/bot/src/bot_api/__init__.py b/bot/src/bot_api/__init__.py index ad8a9c26..b92fc1c9 100644 --- a/bot/src/bot_api/__init__.py +++ b/bot/src/bot_api/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_api" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/abc/__init__.py b/bot/src/bot_api/abc/__init__.py index 8df940d6..0029690d 100644 --- a/bot/src/bot_api/abc/__init__.py +++ b/bot/src/bot_api/abc/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_api.abc" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/abc/auth_service_abc.py b/bot/src/bot_api/abc/auth_service_abc.py index 1ba5fbbb..c72d0d14 100644 --- a/bot/src/bot_api/abc/auth_service_abc.py +++ b/bot/src/bot_api/abc/auth_service_abc.py @@ -114,3 +114,7 @@ class AuthServiceABC(ABC): @abstractmethod async def reset_password_async(self, rp_dto: ResetPasswordDTO): pass + + @abstractmethod + async def resend_confirmation_email_by_mail(self, mail: str): + pass diff --git a/bot/src/bot_api/api.py b/bot/src/bot_api/api.py index 84184695..c27ad0bf 100644 --- a/bot/src/bot_api/api.py +++ b/bot/src/bot_api/api.py @@ -16,8 +16,8 @@ from werkzeug.exceptions import NotFound from bot_api.configuration.api_settings import ApiSettings from bot_api.configuration.authentication_settings import AuthenticationSettings -from bot_api.exception.service_error_code_enum import ServiceErrorCode -from bot_api.exception.service_exception import ServiceException +from bot_core.exception.service_error_code_enum import ServiceErrorCode +from bot_core.exception.service_exception import ServiceException from bot_api.logging.api_logger import ApiLogger from bot_api.model.error_dto import ErrorDTO from bot_api.route.route import Route diff --git a/bot/src/bot_api/bot-api.json b/bot/src/bot_api/bot-api.json index 2a3b6254..8567eca4 100644 --- a/bot/src/bot_api/bot-api.json +++ b/bot/src/bot_api/bot-api.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "", "AuthorEmail": "", diff --git a/bot/src/bot_api/config b/bot/src/bot_api/config index 521951b8..12ffcbcd 160000 --- a/bot/src/bot_api/config +++ b/bot/src/bot_api/config @@ -1 +1 @@ -Subproject commit 521951b8abb0f784b59b6d3e0210606fa193e60a +Subproject commit 12ffcbcd9b88612251a1e23cb6724e21562f74b8 diff --git a/bot/src/bot_api/configuration/__init__.py b/bot/src/bot_api/configuration/__init__.py index d6362551..9b6512a0 100644 --- a/bot/src/bot_api/configuration/__init__.py +++ b/bot/src/bot_api/configuration/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_api.configuration" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/controller/__init__.py b/bot/src/bot_api/controller/__init__.py index ad8aff7d..0f3da57f 100644 --- a/bot/src/bot_api/controller/__init__.py +++ b/bot/src/bot_api/controller/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_api.controller" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/controller/auth_controller.py b/bot/src/bot_api/controller/auth_controller.py index 12ec2b9b..6f13abdc 100644 --- a/bot/src/bot_api/controller/auth_controller.py +++ b/bot/src/bot_api/controller/auth_controller.py @@ -84,13 +84,13 @@ class AuthController: self._auth_service.add_auth_user(dto) return "", 200 + @Route.post(f"{BasePath}/resend-confirmation-email-by-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/") async def register_id(self, id: str): - if not FeatureFlagsSettings.get_flag_from_dict( - self._technician_config.feature_flags, FeatureFlagsEnum.basic_registration - ): - return - result = await self._auth_service.confirm_email_async(id) return jsonify(result) diff --git a/bot/src/bot_api/controller/auth_discord_controller.py b/bot/src/bot_api/controller/auth_discord_controller.py index 8ad193cc..24d37afe 100644 --- a/bot/src/bot_api/controller/auth_discord_controller.py +++ b/bot/src/bot_api/controller/auth_discord_controller.py @@ -16,6 +16,7 @@ from bot_api.api import Api from bot_api.configuration.discord_authentication_settings import ( DiscordAuthenticationSettings, ) +from bot_core.exception.service_exception import ServiceException from bot_api.logging.api_logger import ApiLogger from bot_api.model.auth_user_dto import AuthUserDTO from bot_api.route.route import Route @@ -90,5 +91,10 @@ class AuthDiscordController: AuthRoleEnum.normal, ) - result = await self._auth_service.login_discord_async(dto, response["id"]) - return jsonify(result.to_dict()) + try: + result = await self._auth_service.login_discord_async(dto, response["id"]) + return jsonify(result.to_dict()) + except ServiceException as e: + r = jsonify({"email": dto.email}) + r.status_code = 403 + return r diff --git a/bot/src/bot_api/event/__init__.py b/bot/src/bot_api/event/__init__.py index 933a8fac..d2f6adb6 100644 --- a/bot/src/bot_api/event/__init__.py +++ b/bot/src/bot_api/event/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_api.event" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/exception/__init__.py b/bot/src/bot_api/exception/__init__.py deleted file mode 100644 index 1607622c..00000000 --- a/bot/src/bot_api/exception/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -bot sh-edraft.de Discord bot -~~~~~~~~~~~~~~~~~~~ - -Discord bot for customers of sh-edraft.de - -:copyright: (c) 2022 - 2023 sh-edraft.de -:license: MIT, see LICENSE for more details. - -""" - -__title__ = "bot_api.exception" -__author__ = "Sven Heidemann" -__license__ = "MIT" -__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" - -from collections import namedtuple - - -# imports: - -VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") diff --git a/bot/src/bot_api/filter/__init__.py b/bot/src/bot_api/filter/__init__.py index 5da317f5..7249b7f9 100644 --- a/bot/src/bot_api/filter/__init__.py +++ b/bot/src/bot_api/filter/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_api.filter" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/filter/discord/__init__.py b/bot/src/bot_api/filter/discord/__init__.py index 17145205..480edfe9 100644 --- a/bot/src/bot_api/filter/discord/__init__.py +++ b/bot/src/bot_api/filter/discord/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_api.filter.discord" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/logging/__init__.py b/bot/src/bot_api/logging/__init__.py index a044a459..02d5379b 100644 --- a/bot/src/bot_api/logging/__init__.py +++ b/bot/src/bot_api/logging/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_api.logging" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/model/__init__.py b/bot/src/bot_api/model/__init__.py index f811c99b..245f2ac7 100644 --- a/bot/src/bot_api/model/__init__.py +++ b/bot/src/bot_api/model/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_api.model" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/model/discord/__init__.py b/bot/src/bot_api/model/discord/__init__.py index 17902e62..9c01e3bc 100644 --- a/bot/src/bot_api/model/discord/__init__.py +++ b/bot/src/bot_api/model/discord/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_api.model.discord" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/model/error_dto.py b/bot/src/bot_api/model/error_dto.py index 867e581c..d24d7fdb 100644 --- a/bot/src/bot_api/model/error_dto.py +++ b/bot/src/bot_api/model/error_dto.py @@ -1,10 +1,7 @@ -import traceback from typing import Optional -from cpl_core.console import Console - from bot_api.abc.dto_abc import DtoABC -from bot_api.exception.service_error_code_enum import ServiceErrorCode +from bot_core.exception.service_error_code_enum import ServiceErrorCode class ErrorDTO(DtoABC): diff --git a/bot/src/bot_api/route/__init__.py b/bot/src/bot_api/route/__init__.py index 71418409..1fa9c21d 100644 --- a/bot/src/bot_api/route/__init__.py +++ b/bot/src/bot_api/route/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_api.route" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/route/route.py b/bot/src/bot_api/route/route.py index a72b28e3..2b283b14 100644 --- a/bot/src/bot_api/route/route.py +++ b/bot/src/bot_api/route/route.py @@ -8,8 +8,8 @@ from flask import request, jsonify from flask_cors import cross_origin from bot_api.abc.auth_service_abc import AuthServiceABC -from bot_api.exception.service_error_code_enum import ServiceErrorCode -from bot_api.exception.service_exception import ServiceException +from bot_core.exception.service_error_code_enum import ServiceErrorCode +from bot_core.exception.service_exception import ServiceException from bot_api.model.error_dto import ErrorDTO from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC from bot_data.model.auth_role_enum import AuthRoleEnum diff --git a/bot/src/bot_api/service/__init__.py b/bot/src/bot_api/service/__init__.py index e90a199d..875aa434 100644 --- a/bot/src/bot_api/service/__init__.py +++ b/bot/src/bot_api/service/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_api.service" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/service/auth_service.py b/bot/src/bot_api/service/auth_service.py index 94410b52..661ca15d 100644 --- a/bot/src/bot_api/service/auth_service.py +++ b/bot/src/bot_api/service/auth_service.py @@ -1,6 +1,5 @@ import hashlib import re -import textwrap import uuid from datetime import datetime, timedelta, timezone from threading import Thread @@ -19,8 +18,8 @@ from flask import request from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.configuration.authentication_settings import AuthenticationSettings from bot_api.configuration.frontend_settings import FrontendSettings -from bot_api.exception.service_error_code_enum import ServiceErrorCode -from bot_api.exception.service_exception import ServiceException +from bot_core.exception.service_error_code_enum import ServiceErrorCode +from bot_core.exception.service_exception import ServiceException from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria from bot_api.logging.api_logger import ApiLogger from bot_api.model.auth_user_dto import AuthUserDTO @@ -172,11 +171,7 @@ class AuthService(AuthServiceABC): mail.add_header("Content-Transfer-Encoding: quoted-printable") mail.add_receiver(str(email)) mail.subject = subject - 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)} - """ - ) + 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)}" thr = Thread(target=self._mailer.send_mail, args=[mail]) thr.start() @@ -599,3 +594,12 @@ class AuthService(AuthServiceABC): user.forgot_password_id = None self._auth_users.update_auth_user(user) 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) diff --git a/bot/src/bot_api/service/discord_service.py b/bot/src/bot_api/service/discord_service.py index 386b3046..0e05cc6c 100644 --- a/bot/src/bot_api/service/discord_service.py +++ b/bot/src/bot_api/service/discord_service.py @@ -4,8 +4,8 @@ from cpl_discord.service import DiscordBotServiceABC from cpl_query.extension import List from bot_api.abc.auth_service_abc import AuthServiceABC -from bot_api.exception.service_error_code_enum import ServiceErrorCode -from bot_api.exception.service_exception import ServiceException +from bot_core.exception.service_error_code_enum import ServiceErrorCode +from bot_core.exception.service_exception import ServiceException 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_filtered_result_dto import ServerFilteredResultDTO diff --git a/bot/src/bot_api/transformer/__init__.py b/bot/src/bot_api/transformer/__init__.py index b3ab743f..4fac8c96 100644 --- a/bot/src/bot_api/transformer/__init__.py +++ b/bot/src/bot_api/transformer/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_api.transformer" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/transformer/auth_user_transformer.py b/bot/src/bot_api/transformer/auth_user_transformer.py index 66506a3a..26f9f36a 100644 --- a/bot/src/bot_api/transformer/auth_user_transformer.py +++ b/bot/src/bot_api/transformer/auth_user_transformer.py @@ -35,21 +35,37 @@ class AuthUserTransformer(TransformerABC): @ServiceProviderABC.inject def _is_technician(user: User, bot: DiscordBotServiceABC, permissions: PermissionServiceABC): 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) + if member is None: + return permissions.is_member_technician_by_id(user.discord_id) + return permissions.is_member_technician(member) @staticmethod @ServiceProviderABC.inject def _is_admin(user: User, bot: DiscordBotServiceABC, permissions: PermissionServiceABC): guild = bot.get_guild(user.server.discord_id) + if guild is None: + return False + member = guild.get_member(user.discord_id) + if member is None: + return False return permissions.is_member_admin(member) @staticmethod @ServiceProviderABC.inject def _is_moderator(user: User, bot: DiscordBotServiceABC, permissions: PermissionServiceABC): guild = bot.get_guild(user.server.discord_id) + if guild is None: + return False + member = guild.get_member(user.discord_id) + if member is None: + return False return permissions.is_member_moderator(member) @classmethod diff --git a/bot/src/bot_core/__init__.py b/bot/src/bot_core/__init__.py index e1220bf6..c9ea2f89 100644 --- a/bot/src/bot_core/__init__.py +++ b/bot/src/bot_core/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_core" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_core/abc/__init__.py b/bot/src/bot_core/abc/__init__.py index 38117eb7..d1769a37 100644 --- a/bot/src/bot_core/abc/__init__.py +++ b/bot/src/bot_core/abc/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_core.abc" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_core/abc/permission_service_abc.py b/bot/src/bot_core/abc/permission_service_abc.py index fd13a219..3af5658e 100644 --- a/bot/src/bot_core/abc/permission_service_abc.py +++ b/bot/src/bot_core/abc/permission_service_abc.py @@ -19,3 +19,7 @@ class PermissionServiceABC(ABC): @abstractmethod def is_member_technician(self, member: discord.Member) -> bool: pass + + @abstractmethod + def is_member_technician_by_id(self, member_id: int) -> bool: + pass diff --git a/bot/src/bot_core/bot-core.json b/bot/src/bot_core/bot-core.json index b487a8c2..4abb52c9 100644 --- a/bot/src/bot_core/bot-core.json +++ b/bot/src/bot_core/bot-core.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "Sven Heidemann", "AuthorEmail": "sven.heidemann@sh-edraft.de", diff --git a/bot/src/bot_core/configuration/__init__.py b/bot/src/bot_core/configuration/__init__.py index 6cecd704..f0cf77c8 100644 --- a/bot/src/bot_core/configuration/__init__.py +++ b/bot/src/bot_core/configuration/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_core.configuration" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_core/core_extension/__init__.py b/bot/src/bot_core/core_extension/__init__.py index f08f3680..df47842d 100644 --- a/bot/src/bot_core/core_extension/__init__.py +++ b/bot/src/bot_core/core_extension/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_core.core_extension" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_core/events/__init__.py b/bot/src/bot_core/events/__init__.py index b06a8c59..6598aa0b 100644 --- a/bot/src/bot_core/events/__init__.py +++ b/bot/src/bot_core/events/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_core.events" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_core/exception/__init__.py b/bot/src/bot_core/exception/__init__.py index ea4dc40e..a58a683e 100644 --- a/bot/src/bot_core/exception/__init__.py +++ b/bot/src/bot_core/exception/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_core.exception" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_api/exception/service_error_code_enum.py b/bot/src/bot_core/exception/service_error_code_enum.py similarity index 100% rename from bot/src/bot_api/exception/service_error_code_enum.py rename to bot/src/bot_core/exception/service_error_code_enum.py diff --git a/bot/src/bot_api/exception/service_exception.py b/bot/src/bot_core/exception/service_exception.py similarity index 83% rename from bot/src/bot_api/exception/service_exception.py rename to bot/src/bot_core/exception/service_exception.py index 0b0ed95d..2292afe9 100644 --- a/bot/src/bot_api/exception/service_exception.py +++ b/bot/src/bot_core/exception/service_exception.py @@ -1,4 +1,4 @@ -from bot_api.exception.service_error_code_enum import ServiceErrorCode +from bot_core.exception.service_error_code_enum import ServiceErrorCode class ServiceException(Exception): diff --git a/bot/src/bot_core/helper/__init__.py b/bot/src/bot_core/helper/__init__.py index 7a755460..134d948d 100644 --- a/bot/src/bot_core/helper/__init__.py +++ b/bot/src/bot_core/helper/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_core.helper" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_core/logging/__init__.py b/bot/src/bot_core/logging/__init__.py index 870f1127..38e28e17 100644 --- a/bot/src/bot_core/logging/__init__.py +++ b/bot/src/bot_core/logging/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_core.logging" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_core/pipes/__init__.py b/bot/src/bot_core/pipes/__init__.py index ac3665d9..bf6b07dc 100644 --- a/bot/src/bot_core/pipes/__init__.py +++ b/bot/src/bot_core/pipes/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_core.pipes" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_core/service/__init__.py b/bot/src/bot_core/service/__init__.py index eb809109..ad13f0b4 100644 --- a/bot/src/bot_core/service/__init__.py +++ b/bot/src/bot_core/service/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_core.service" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_core/service/permission_service.py b/bot/src/bot_core/service/permission_service.py index de76e15a..0ca7e0f3 100644 --- a/bot/src/bot_core/service/permission_service.py +++ b/bot/src/bot_core/service/permission_service.py @@ -5,11 +5,11 @@ 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 -from bot_core.abc.permission_service_abc import PermissionServiceABC class PermissionService(PermissionServiceABC): @@ -112,3 +112,18 @@ class PermissionService(PermissionServiceABC): 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 diff --git a/bot/src/bot_data/__init__.py b/bot/src/bot_data/__init__.py index 2046b7b3..500ccf7d 100644 --- a/bot/src/bot_data/__init__.py +++ b/bot/src/bot_data/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_data" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_data/abc/__init__.py b/bot/src/bot_data/abc/__init__.py index 07f80535..1e7e321a 100644 --- a/bot/src/bot_data/abc/__init__.py +++ b/bot/src/bot_data/abc/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_data.abc" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_data/abc/user_warnings_repository_abc.py b/bot/src/bot_data/abc/user_warnings_repository_abc.py index bb5d9e9b..0fb36df5 100644 --- a/bot/src/bot_data/abc/user_warnings_repository_abc.py +++ b/bot/src/bot_data/abc/user_warnings_repository_abc.py @@ -18,6 +18,10 @@ class UserWarningsRepositoryABC(ABC): def get_user_warnings_by_id(self, id: int) -> UserWarnings: pass + @abstractmethod + def get_user_warnings_by_server_id(self, server_id: int) -> List[UserWarnings]: + pass + @abstractmethod def get_user_warnings_by_user_id(self, user_id: int) -> List[UserWarnings]: pass diff --git a/bot/src/bot_data/bot-data.json b/bot/src/bot_data/bot-data.json index 8b20043c..a7b0999f 100644 --- a/bot/src/bot_data/bot-data.json +++ b/bot/src/bot_data/bot-data.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "Sven Heidemann", "AuthorEmail": "sven.heidemann@sh-edraft.de", diff --git a/bot/src/bot_data/db_connection.py b/bot/src/bot_data/db_connection.py new file mode 100644 index 00000000..f67242e7 --- /dev/null +++ b/bot/src/bot_data/db_connection.py @@ -0,0 +1,50 @@ +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() diff --git a/bot/src/bot_data/db_context.py b/bot/src/bot_data/db_context.py index fb5e9f55..56e2f808 100644 --- a/bot/src/bot_data/db_context.py +++ b/bot/src/bot_data/db_context.py @@ -1,9 +1,12 @@ -import time +import uuid from cpl_core.database import DatabaseSettings 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_data.mysql_pool import MySQLPool class DBContext(DatabaseContext): @@ -11,36 +14,45 @@ class DBContext(DatabaseContext): self._logger = logger DatabaseContext.__init__(self) + self._pool: MySQLPool = None self._fails = 0 def connect(self, database_settings: DatabaseSettings): try: self._logger.debug(__name__, "Connecting to database") - self._db.connect(database_settings) + self._pool = MySQLPool(database_settings) + self._pool.execute(f"CREATE DATABASE IF NOT EXISTS `{database_settings.database}`;", commit=True) self._logger.info(__name__, "Connected to database") except Exception as e: self._logger.fatal(__name__, "Connecting to database failed", e) + @property + def cursor(self): + return self + def save_changes(self): - 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) + pass def select(self, statement: str) -> list[tuple]: try: - return super(DBContext, self).select(statement) + return self._pool.execute(statement) except Exception as e: if self._fails >= 3: - self._logger.fatal(__name__, f"Database error caused by {statement}", e) + self._logger.error(__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._fails += 1 try: - time.sleep(0.5) + self._logger.debug(__name__, "Retry select") return self.select(statement) except Exception as e: pass return [] + + def execute(self, statement: str): + return self._pool.execute(statement, commit=True) diff --git a/bot/src/bot_data/model/__init__.py b/bot/src/bot_data/model/__init__.py index deffc730..6350dee2 100644 --- a/bot/src/bot_data/model/__init__.py +++ b/bot/src/bot_data/model/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_data.model" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_data/model/auth_user.py b/bot/src/bot_data/model/auth_user.py index 47bdf41a..13c77bd6 100644 --- a/bot/src/bot_data/model/auth_user.py +++ b/bot/src/bot_data/model/auth_user.py @@ -258,6 +258,15 @@ class AuthUser(TableABC): """ ) + @property + def delete_relations_string(self) -> str: + return str( + f""" + DELETE FROM `AuthUserUsersRelations` + WHERE `AuthUserId` = {self._auth_user_id}; + """ + ) + @property def delete_string(self) -> str: return str( diff --git a/bot/src/bot_data/model/auto_role_rule.py b/bot/src/bot_data/model/auto_role_rule.py index 8729b6ec..992fdfe0 100644 --- a/bot/src/bot_data/model/auto_role_rule.py +++ b/bot/src/bot_data/model/auto_role_rule.py @@ -1,4 +1,5 @@ from datetime import datetime +from typing import Optional from cpl_core.database import TableABC from cpl_core.dependency_injection import ServiceProviderABC @@ -48,8 +49,10 @@ class AutoRoleRule(TableABC): @property @ServiceProviderABC.inject - def role_name(self, bot: DiscordBotServiceABC) -> str: + def role_name(self, bot: DiscordBotServiceABC) -> Optional[str]: guild = bot.get_guild(self.auto_role.server.discord_id) + if guild is None: + return None return guild.get_role(self.role_id).name @role_id.setter diff --git a/bot/src/bot_data/model/auto_role_rule_history.py b/bot/src/bot_data/model/auto_role_rule_history.py index c5a5ccd9..1acc86a2 100644 --- a/bot/src/bot_data/model/auto_role_rule_history.py +++ b/bot/src/bot_data/model/auto_role_rule_history.py @@ -1,3 +1,5 @@ +from typing import Optional + from cpl_core.dependency_injection import ServiceProviderABC from cpl_discord.service import DiscordBotServiceABC @@ -43,6 +45,8 @@ class AutoRoleRuleHistory(HistoryTableABC): @property @ServiceProviderABC.inject - def role_name(self, bot: DiscordBotServiceABC) -> str: + def role_name(self, bot: DiscordBotServiceABC) -> Optional[str]: guild = bot.get_guild(self.auto_role.server.discord_id) + if guild is None: + return None return guild.get_role(self.role_id).name diff --git a/bot/src/bot_data/model/level.py b/bot/src/bot_data/model/level.py index a20d268b..6002e407 100644 --- a/bot/src/bot_data/model/level.py +++ b/bot/src/bot_data/model/level.py @@ -2,6 +2,10 @@ from datetime import datetime from typing import Optional from cpl_core.database import TableABC +from cpl_core.dependency_injection import ServiceProviderABC +from cpl_discord.service import DiscordBotServiceABC +from cpl_query.extension import List +from discord import Role from bot_data.model.server import Server @@ -33,6 +37,15 @@ class Level(TableABC): def id(self) -> int: return self._id + @property + @ServiceProviderABC.inject + def icon_url(self, bot: DiscordBotServiceABC) -> Optional[str]: + guild = bot.get_guild(self.server.discord_id) + if guild is None: + return None + role = List(Role, guild.roles).where(lambda x: x.name == self._name).first_or_default() + return None if role is None else role.icon + @property def name(self) -> str: return self._name diff --git a/bot/src/bot_data/model/server.py b/bot/src/bot_data/model/server.py index d86c6e97..de9d5b78 100644 --- a/bot/src/bot_data/model/server.py +++ b/bot/src/bot_data/model/server.py @@ -1,4 +1,5 @@ from datetime import datetime +from typing import Optional from cpl_core.database import TableABC from cpl_core.dependency_injection import ServiceProviderABC @@ -30,14 +31,18 @@ class Server(TableABC): @property @ServiceProviderABC.inject - def name(self, bot: DiscordBotServiceABC) -> str: + def name(self, bot: DiscordBotServiceABC) -> Optional[str]: guild = bot.get_guild(self.discord_id) + if guild is None: + return None return None if guild is None else guild.name @property @ServiceProviderABC.inject - def icon_url(self, bot: DiscordBotServiceABC) -> str: + def icon_url(self, bot: DiscordBotServiceABC) -> Optional[str]: guild = bot.get_guild(self.discord_id) + if guild is None: + return None return None if guild is None else guild.icon.url @staticmethod diff --git a/bot/src/bot_data/model/server_config.py b/bot/src/bot_data/model/server_config.py index cf220355..72a0dd29 100644 --- a/bot/src/bot_data/model/server_config.py +++ b/bot/src/bot_data/model/server_config.py @@ -32,6 +32,7 @@ class ServerConfig(TableABC, ConfigurationModelABC): default_role_id: Optional[int], short_role_name_only_set_highest_role: bool, game_offer_notification_chat_id: int, + reset_member_after_rejoin: bool, feature_flags: dict[FeatureFlagsEnum], server: Server, afk_channel_ids: List[int], @@ -58,6 +59,7 @@ class ServerConfig(TableABC, ConfigurationModelABC): self._default_role_id = default_role_id self._short_role_name_only_set_highest_role = short_role_name_only_set_highest_role self._game_offer_notification_chat_id = game_offer_notification_chat_id + self._reset_member_after_rejoin = reset_member_after_rejoin self._feature_flags = feature_flags self._server = server @@ -88,6 +90,7 @@ class ServerConfig(TableABC, ConfigurationModelABC): None, False, guild.system_channel.id, + False, {}, server, List(int), @@ -234,6 +237,14 @@ class ServerConfig(TableABC, ConfigurationModelABC): def game_offer_notification_chat_id(self, value: int): self._game_offer_notification_chat_id = value + @property + def reset_member_after_rejoin(self) -> bool: + return self._reset_member_after_rejoin + + @reset_member_after_rejoin.setter + def reset_member_after_rejoin(self, value: bool): + self._reset_member_after_rejoin = value + @property def feature_flags(self) -> dict[FeatureFlagsEnum]: return self._feature_flags @@ -310,6 +321,7 @@ class ServerConfig(TableABC, ConfigurationModelABC): `DefaultRoleId`, `ShortRoleNameSetOnlyHighest`, `GameOfferNotificationChatId`, + `ResetMemberAfterRejoin`, `FeatureFlags`, `ServerId` ) VALUES ( @@ -330,6 +342,7 @@ class ServerConfig(TableABC, ConfigurationModelABC): {"NULL" if self._default_role_id is None else self._default_role_id}, {self._short_role_name_only_set_highest_role}, {self._game_offer_notification_chat_id}, + {self._reset_member_after_rejoin}, '{json.dumps(self._feature_flags)}', {self._server.id} ); @@ -357,7 +370,8 @@ class ServerConfig(TableABC, ConfigurationModelABC): `LoginMessageChannelId` = {self._login_message_channel_id}, `DefaultRoleId` = {"NULL" if self._default_role_id is None else self._default_role_id}, `ShortRoleNameSetOnlyHighest` = {self._short_role_name_only_set_highest_role}, - `GameOfferNotificationChatId` = {self._game_offer_notification_chat_id}, + `GameOfferNotificationChatId` = {"NULL" if self._game_offer_notification_chat_id is None else self._game_offer_notification_chat_id}, + `ResetMemberAfterRejoin` = {self._reset_member_after_rejoin}, `FeatureFlags` = '{json.dumps(self._feature_flags)}', `ServerId` = {self._server.id} WHERE `Id` = {self._id}; diff --git a/bot/src/bot_data/model/server_history.py b/bot/src/bot_data/model/server_history.py index e8c95934..f34ab64e 100644 --- a/bot/src/bot_data/model/server_history.py +++ b/bot/src/bot_data/model/server_history.py @@ -1,3 +1,5 @@ +from typing import Optional + from cpl_core.dependency_injection import ServiceProviderABC from cpl_discord.service import DiscordBotServiceABC @@ -32,12 +34,16 @@ class ServerHistory(HistoryTableABC): @property @ServiceProviderABC.inject - def name(self, bot: DiscordBotServiceABC) -> str: + def name(self, bot: DiscordBotServiceABC) -> Optional[str]: guild = bot.get_guild(self.discord_id) + if guild is None: + return None return None if guild is None else guild.name @property @ServiceProviderABC.inject - def icon_url(self, bot: DiscordBotServiceABC) -> str: + def icon_url(self, bot: DiscordBotServiceABC) -> Optional[str]: guild = bot.get_guild(self.discord_id) + if guild is None: + return None return None if guild is None else guild.icon.url diff --git a/bot/src/bot_data/model/short_role_name.py b/bot/src/bot_data/model/short_role_name.py index 4ddef4f1..d987f062 100644 --- a/bot/src/bot_data/model/short_role_name.py +++ b/bot/src/bot_data/model/short_role_name.py @@ -1,4 +1,5 @@ from datetime import datetime +from typing import Optional from cpl_core.database import TableABC from cpl_core.dependency_injection import ServiceProviderABC @@ -51,8 +52,10 @@ class ShortRoleName(TableABC): @property @ServiceProviderABC.inject - def role_name(self, bot: DiscordBotServiceABC) -> str: + def role_name(self, bot: DiscordBotServiceABC) -> Optional[str]: guild = bot.get_guild(self._server.discord_id) + if guild is None: + return None return guild.get_role(self.role_id).name @property diff --git a/bot/src/bot_data/model/short_role_name_history.py b/bot/src/bot_data/model/short_role_name_history.py index 90bbdc00..9c718af3 100644 --- a/bot/src/bot_data/model/short_role_name_history.py +++ b/bot/src/bot_data/model/short_role_name_history.py @@ -1,3 +1,5 @@ +from typing import Optional + from cpl_core.dependency_injection import ServiceProviderABC from cpl_discord.service import DiscordBotServiceABC @@ -47,8 +49,10 @@ class ShortRoleNameHistory(HistoryTableABC): @property @ServiceProviderABC.inject - def role_name(self, bot: DiscordBotServiceABC) -> str: + def role_name(self, bot: DiscordBotServiceABC) -> Optional[str]: guild = bot.get_guild(self._server.discord_id) + if guild is None: + return None return guild.get_role(self.role_id).name @property diff --git a/bot/src/bot_data/model/user.py b/bot/src/bot_data/model/user.py index bfc7be34..1343df1b 100644 --- a/bot/src/bot_data/model/user.py +++ b/bot/src/bot_data/model/user.py @@ -38,6 +38,11 @@ class User(TableABC): self._created_at = created_at if created_at is not None else self._created_at self._modified_at = modified_at if modified_at is not None else self._modified_at + def reset(self): + self._xp = 0 + self._message_count = 0 + self._reaction_count = 0 + @property def id(self) -> int: return self._user_id @@ -48,15 +53,19 @@ class User(TableABC): @property @ServiceProviderABC.inject - def name(self, bot: DiscordBotServiceABC) -> str: + def name(self, bot: DiscordBotServiceABC) -> Optional[str]: guild = bot.get_guild(self.server.discord_id) + if guild is None: + return None user = guild.get_member(self.discord_id) return None if user is None else user.name @property @ServiceProviderABC.inject - def icon_url(self, bot: DiscordBotServiceABC) -> str: + def icon_url(self, bot: DiscordBotServiceABC) -> Optional[str]: guild = bot.get_guild(self.server.discord_id) + if guild is None: + return None user = guild.get_member(self.discord_id) return None if user is None else user.display_icon @@ -132,7 +141,7 @@ class User(TableABC): @property @ServiceProviderABC.inject - def level(self, services: ServiceProviderABC) -> Level: + def level(self, services: ServiceProviderABC) -> Optional[Level]: from modules.level.service.level_service import LevelService levels: LevelService = services.get_service(LevelService) @@ -170,10 +179,12 @@ class User(TableABC): @property @ServiceProviderABC.inject - def profile_picture_url(self, bot: DiscordBotServiceABC) -> str: + def profile_picture_url(self, bot: DiscordBotServiceABC) -> Optional[str]: guild = bot.get_guild(self.server.discord_id) + if guild is None: + return None user = guild.get_member(self._discord_id) - return None if user is None else user.avatar.url + return None if user is None or user.avatar is None else user.avatar.url @staticmethod def get_select_all_string() -> str: diff --git a/bot/src/bot_data/model/user_warnings.py b/bot/src/bot_data/model/user_warnings.py index 99610a5f..40aeb064 100644 --- a/bot/src/bot_data/model/user_warnings.py +++ b/bot/src/bot_data/model/user_warnings.py @@ -59,6 +59,17 @@ class UserWarnings(TableABC): """ ) + @staticmethod + def get_select_by_server_id_string(id: int) -> str: + return str( + f""" + SELECT `UserWarnings`.* FROM `UserWarnings` + INNER JOIN `Users` + ON `Users`.`UserId` = `UserWarnings`.`UserId` + WHERE `Users`.`ServerId` = {id}; + """ + ) + @staticmethod def get_select_by_user_id_string(id: int) -> str: return str( diff --git a/bot/src/bot_data/mysql_pool.py b/bot/src/bot_data/mysql_pool.py new file mode 100644 index 00000000..7c7b3499 --- /dev/null +++ b/bot/src/bot_data/mysql_pool.py @@ -0,0 +1,104 @@ +# https://stackoverflow.com/questions/32658679/how-to-create-a-mysql-connection-pool-or-any-better-way-to-initialize-the-multip +import mysql.connector as sql +from cpl_core.database import DatabaseSettings +from cpl_core.utils import CredentialManager + + +class MySQLPool(object): + """ + create a pool when connect mysql, which will decrease the time spent in + request connection, create connection and close connection. + """ + + def __init__( + self, + database_settings: DatabaseSettings, + pool_size=5, + ): + res = { + "host": database_settings.host, + "port": database_settings.port, + "user": database_settings.user, + "password": CredentialManager.decrypt(database_settings.password), + "database": database_settings.database, + } + + self.dbconfig = res + self.pool = self.create_pool(pool_name="MySqlPool", pool_size=pool_size) + + def create_pool(self, pool_name="MySqlPool", pool_size=3): + """ + Create a connection pool, after created, the request of connecting + MySQL could get a connection from this pool instead of request to + create a connection. + :param pool_name: the name of pool, default is "mypool" + :param pool_size: the size of pool, default is 3 + :return: connection pool + """ + pool = sql.pooling.MySQLConnectionPool( + pool_name=pool_name, pool_size=pool_size, pool_reset_session=True, **self.dbconfig + ) + return pool + + def close(self, conn, cursor): + """ + A method used to close connection of mysql. + :param conn: + :param cursor: + :return: + """ + cursor.close() + conn.close() + + def execute(self, sql, args=None, commit=False): + """ + Execute a sql, it could be with args and with out args. The usage is + similar with execute() function in module pymysql. + :param sql: sql clause + :param args: args need by sql clause + :param commit: whether to commit + :return: if commit, return None, else, return result + """ + # get connection form connection pool instead of create one. + conn = self.pool.get_connection() + cursor = conn.cursor() + if args: + cursor.execute(sql, args) + else: + cursor.execute(sql) + if commit is True: + conn.commit() + self.close(conn, cursor) + return None + else: + res = cursor.fetchall() + self.close(conn, cursor) + return res + + def executemany(self, sql, args, commit=False): + """ + Execute with many args. Similar with executemany() function in pymysql. + args should be a sequence. + :param sql: sql clause + :param args: args + :param commit: commit or not. + :return: if commit, return None, else, return result + """ + # get connection form connection pool instead of create one. + conn = self.pool.get_connection() + cursor = conn.cursor() + cursor.executemany(sql, args) + if commit is True: + conn.commit() + self.close(conn, cursor) + return None + else: + res = cursor.fetchall() + self.close(conn, cursor) + return res + + def commit(self): + conn = self.pool.get_connection() + conn.commit() + cursor = conn.cursor() + self.close(conn, cursor) diff --git a/bot/src/bot_data/scripts/1.2.4/1_ResetMemberAfterRejoin_down.sql b/bot/src/bot_data/scripts/1.2.4/1_ResetMemberAfterRejoin_down.sql new file mode 100644 index 00000000..5b584865 --- /dev/null +++ b/bot/src/bot_data/scripts/1.2.4/1_ResetMemberAfterRejoin_down.sql @@ -0,0 +1,7 @@ +ALTER TABLE CFG_Server + DROP COLUMN ResetMemberAfterRejoin; + +ALTER TABLE CFG_ServerHistory + DROP COLUMN ResetMemberAfterRejoin; + + diff --git a/bot/src/bot_data/scripts/1.2.4/1_ResetMemberAfterRejoin_up.sql b/bot/src/bot_data/scripts/1.2.4/1_ResetMemberAfterRejoin_up.sql new file mode 100644 index 00000000..4595e89f --- /dev/null +++ b/bot/src/bot_data/scripts/1.2.4/1_ResetMemberAfterRejoin_up.sql @@ -0,0 +1,116 @@ +ALTER TABLE CFG_Server + ADD ResetMemberAfterRejoin BOOLEAN NOT NULL DEFAULT FALSE AFTER GameOfferNotificationChatId; + + + +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` + AFTER UPDATE + ON `CFG_Server` + FOR EACH ROW +BEGIN + INSERT INTO `CFG_ServerHistory` (`Id`, + `MessageDeleteTimer`, + `NotificationChatId`, + `MaxVoiceStateHours`, + `XpPerMessage`, + `XpPerReaction`, + `MaxMessageXpPerHour`, + `XpPerOntimeHour`, + `XpPerEventParticipation`, + `XpPerAchievement`, + `AFKCommandChannelId`, + `HelpVoiceChannelId`, + `TeamChannelId`, + `LoginMessageChannelId`, + `DefaultRoleId`, + `ShortRoleNameSetOnlyHighest`, + `GameOfferNotificationChatId`, + `ResetMemberAfterRejoin`, + `FeatureFlags`, + `ServerId`, + `DateFrom`, + `DateTo`) + VALUES (OLD.Id, + OLD.MessageDeleteTimer, + OLD.NotificationChatId, + OLD.MaxVoiceStateHours, + OLD.XpPerMessage, + OLD.XpPerReaction, + OLD.MaxMessageXpPerHour, + OLD.XpPerOntimeHour, + OLD.XpPerEventParticipation, + OLD.XpPerAchievement, + OLD.AFKCommandChannelId, + OLD.HelpVoiceChannelId, + OLD.TeamChannelId, + OLD.LoginMessageChannelId, + OLD.DefaultRoleId, + OLD.ShortRoleNameSetOnlyHighest, + OLD.GameOfferNotificationChatId, + OLD.ResetMemberAfterRejoin, + OLD.FeatureFlags, + OLD.ServerId, + OLD.LastModifiedAt, + CURRENT_TIMESTAMP(6)); +END;; + +DROP TRIGGER IF EXISTS `TR_CFG_ServerDelete`;; + +CREATE TRIGGER `TR_CFG_ServerDelete` + AFTER DELETE + ON `CFG_Server` + FOR EACH ROW +BEGIN + INSERT INTO `CFG_ServerHistory` (`Id`, + `MessageDeleteTimer`, + `NotificationChatId`, + `MaxVoiceStateHours`, + `XpPerMessage`, + `XpPerReaction`, + `MaxMessageXpPerHour`, + `XpPerOntimeHour`, + `XpPerEventParticipation`, + `XpPerAchievement`, + `AFKCommandChannelId`, + `HelpVoiceChannelId`, + `TeamChannelId`, + `LoginMessageChannelId`, + `DefaultRoleId`, + `ShortRoleNameSetOnlyHighest`, + `GameOfferNotificationChatId`, + `ResetMemberAfterRejoin`, + `ServerId`, + `FeatureFlags`, + `Deleted`, + `DateFrom`, + `DateTo`) + VALUES (OLD.Id, + OLD.MessageDeleteTimer, + OLD.NotificationChatId, + OLD.MaxVoiceStateHours, + OLD.XpPerMessage, + OLD.XpPerReaction, + OLD.MaxMessageXpPerHour, + OLD.XpPerOntimeHour, + OLD.XpPerEventParticipation, + OLD.XpPerAchievement, + OLD.AFKCommandChannelId, + OLD.HelpVoiceChannelId, + OLD.TeamChannelId, + OLD.LoginMessageChannelId, + OLD.DefaultRoleId, + OLD.ShortRoleNameSetOnlyHighest, + OLD.GameOfferNotificationChatId, + OLD.ResetMemberAfterRejoin, + OLD.FeatureFlags, + OLD.ServerId, + TRUE, + OLD.LastModifiedAt, + CURRENT_TIMESTAMP(6)); +END;; + diff --git a/bot/src/bot_data/service/__init__.py b/bot/src/bot_data/service/__init__.py index 5ff7280a..f58228bf 100644 --- a/bot/src/bot_data/service/__init__.py +++ b/bot/src/bot_data/service/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_data.service" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_data/service/auth_user_repository_service.py b/bot/src/bot_data/service/auth_user_repository_service.py index 70ebb786..1f657d3a 100644 --- a/bot/src/bot_data/service/auth_user_repository_service.py +++ b/bot/src/bot_data/service/auth_user_repository_service.py @@ -164,6 +164,7 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): def delete_auth_user(self, user: AuthUser): self._logger.trace(__name__, f"Send SQL command: {user.delete_string}") + self._context.cursor.execute(user.delete_relations_string) self._context.cursor.execute(user.delete_string) def add_auth_user_user_rel(self, rel: AuthUserUsersRelation): diff --git a/bot/src/bot_data/service/level_repository_service.py b/bot/src/bot_data/service/level_repository_service.py index 6897ddcc..7fa5e858 100644 --- a/bot/src/bot_data/service/level_repository_service.py +++ b/bot/src/bot_data/service/level_repository_service.py @@ -37,6 +37,8 @@ class LevelRepositoryService(LevelRepositoryABC): int(self._get_value_from_result(sql_result[3])), # min xp int(self._get_value_from_result(sql_result[4])), # permissions self._servers.get_server_by_id(sql_result[5]), # server + sql_result[6], # created_at + sql_result[7], # modified_at id=self._get_value_from_result(sql_result[0]), # id ) diff --git a/bot/src/bot_data/service/migration_service.py b/bot/src/bot_data/service/migration_service.py index a8caeb75..25df92af 100644 --- a/bot/src/bot_data/service/migration_service.py +++ b/bot/src/bot_data/service/migration_service.py @@ -1,13 +1,13 @@ import glob import os -from cpl_core.database.context import DatabaseContextABC from cpl_core.dependency_injection import ServiceProviderABC from cpl_query.extension import List from packaging import version import bot from bot_core.logging.database_logger import DatabaseLogger +from bot_data.db_context import DBContext from bot_data.model.migration import Migration from bot_data.model.migration_history import MigrationHistory @@ -17,13 +17,12 @@ class MigrationService: self, logger: DatabaseLogger, services: ServiceProviderABC, - db: DatabaseContextABC, + db: DBContext, ): self._logger = logger self._services = services self._db = db - self._cursor = db.cursor def _get_migration_history(self) -> List[MigrationHistory]: results = self._db.select( @@ -42,7 +41,7 @@ class MigrationService: return self._logger.debug(__name__, f"Migrate new migration {migration.migration_id} to old method") - self._cursor.execute(migration.change_id_string(f"{migration.migration_id}Migration")) + self._db.execute(migration.change_id_string(f"{migration.migration_id}Migration")) self._db.save_changes() def _migration_migrations_to_new(self, migration: MigrationHistory): @@ -50,12 +49,11 @@ class MigrationService: return self._logger.debug(__name__, f"Migrate old migration {migration.migration_id} to new method") - self._cursor.execute(migration.change_id_string(migration.migration_id.replace("Migration", ""))) + self._db.execute(migration.change_id_string(migration.migration_id.replace("Migration", ""))) self._db.save_changes() def _migrate_from_old_to_new(self): - self._cursor.execute("SHOW TABLES LIKE 'MigrationHistory'") - result = self._cursor.fetchone() + result = self._db.select("SHOW TABLES LIKE 'MigrationHistory'") if not result: return @@ -120,8 +118,7 @@ class MigrationService: active_statement = "" try: # check if table exists - self._cursor.execute("SHOW TABLES LIKE 'MigrationHistory'") - result = self._cursor.fetchone() + result = self._db.select("SHOW TABLES LIKE 'MigrationHistory'") if result: # there is a table named "tableName" self._logger.trace( @@ -142,9 +139,9 @@ class MigrationService: if statement in ["", "\n"]: continue active_statement = statement - self._cursor.execute(statement + ";") + self._db.execute(statement + ";") - self._cursor.execute( + self._db.execute( MigrationHistory(migration.name).insert_string if upgrade else MigrationHistory(migration.name).delete_string diff --git a/bot/src/bot_data/service/server_config_repository_service.py b/bot/src/bot_data/service/server_config_repository_service.py index 3ff90d50..f745dd1a 100644 --- a/bot/src/bot_data/service/server_config_repository_service.py +++ b/bot/src/bot_data/service/server_config_repository_service.py @@ -79,12 +79,13 @@ class ServerConfigRepositoryService(ServerConfigRepositoryABC): result[15], result[16], result[17], - json.loads(result[18]), - self._servers.get_server_by_id(result[19]), - self._get_afk_channel_ids(result[19]), - self._get_team_role_ids(result[19]), - result[20], + result[18], + json.loads(result[19]), + self._servers.get_server_by_id(result[20]), + self._get_afk_channel_ids(result[20]), + self._get_team_role_ids(result[20]), result[21], + result[22], id=result[0], ) diff --git a/bot/src/bot_data/service/user_message_count_per_hour_repository_service.py b/bot/src/bot_data/service/user_message_count_per_hour_repository_service.py index 91ef049c..b1e93bb5 100644 --- a/bot/src/bot_data/service/user_message_count_per_hour_repository_service.py +++ b/bot/src/bot_data/service/user_message_count_per_hour_repository_service.py @@ -2,6 +2,7 @@ from datetime import datetime from typing import Optional from cpl_core.database.context import DatabaseContextABC +from cpl_core.time import TimeFormatSettings from cpl_query.extension import List from bot_core.logging.database_logger import DatabaseLogger @@ -15,12 +16,14 @@ from bot_data.model.user_message_count_per_hour import UserMessageCountPerHour class UserMessageCountPerHourRepositoryService(UserMessageCountPerHourRepositoryABC): def __init__( self, + time_format: TimeFormatSettings, logger: DatabaseLogger, db_context: DatabaseContextABC, users: UserRepositoryABC, ): UserMessageCountPerHourRepositoryABC.__init__(self) + self._time_format = time_format self._logger = logger self._context = db_context self._users = users @@ -67,7 +70,12 @@ class UserMessageCountPerHourRepositoryService(UserMessageCountPerHourRepository ) -> UserMessageCountPerHour: sql = UserMessageCountPerHour.get_select_by_user_id_and_date_string(user_id, date) self._logger.trace(__name__, f"Send SQL command: {sql}") - return self._from_result(self._context.select(sql)[0]) + res = self._context.select(sql) + if len(res) > 0: + return self._from_result(res[0]) + + user = self._users.get_user_by_id(user_id) + return UserMessageCountPerHour(date.strftime(self._time_format.date_time_format), date.hour, 0, user) def find_user_message_count_per_hour_by_user_id_and_date( self, user_id: int, date: datetime diff --git a/bot/src/bot_data/service/user_warnings_repository_service.py b/bot/src/bot_data/service/user_warnings_repository_service.py index bae46987..e9e5b5d5 100644 --- a/bot/src/bot_data/service/user_warnings_repository_service.py +++ b/bot/src/bot_data/service/user_warnings_repository_service.py @@ -56,6 +56,20 @@ class UserWarningsRepositoryService(UserWarningsRepositoryABC): self._logger.trace(__name__, f"Send SQL command: {UserWarnings.get_select_by_id_string(id)}") return self._from_result(self._context.select(UserWarnings.get_select_by_id_string(id))[0]) + def get_user_warnings_by_server_id(self, server_id: int) -> List[UserWarnings]: + self._logger.trace( + __name__, + f"Send SQL command: {UserWarnings.get_select_by_server_id_string(server_id)}", + ) + + return List( + UserWarnings, + [ + self._from_result(warning) + for warning in self._context.select(UserWarnings.get_select_by_server_id_string(server_id)) + ], + ) + def get_user_warnings_by_user_id(self, user_id: int) -> List[UserWarnings]: self._logger.trace( __name__, diff --git a/bot/src/bot_graphql/__init__.py b/bot/src/bot_graphql/__init__.py index 0f5e9fb0..db43a23f 100644 --- a/bot/src/bot_graphql/__init__.py +++ b/bot/src/bot_graphql/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_graphql" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_graphql/abc/__init__.py b/bot/src/bot_graphql/abc/__init__.py index 3d11d11a..5d70ba23 100644 --- a/bot/src/bot_graphql/abc/__init__.py +++ b/bot/src/bot_graphql/abc/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_graphql.abc" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_graphql/abc/query_abc.py b/bot/src/bot_graphql/abc/query_abc.py index cfd18ac6..9dae04ba 100644 --- a/bot/src/bot_graphql/abc/query_abc.py +++ b/bot/src/bot_graphql/abc/query_abc.py @@ -7,8 +7,8 @@ from cpl_core.type import T from cpl_discord.service import DiscordBotServiceABC from cpl_query.extension import List -from bot_api.exception.service_error_code_enum import ServiceErrorCode -from bot_api.exception.service_exception import ServiceException +from bot_core.exception.service_error_code_enum import ServiceErrorCode +from bot_core.exception.service_exception import ServiceException from bot_api.route.route import Route from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum from bot_core.environment_variables import MAINTENANCE @@ -30,6 +30,7 @@ from bot_data.model.user_joined_game_server import UserJoinedGameServer from bot_data.model.user_joined_server import UserJoinedServer from bot_data.model.user_joined_voice_channel import UserJoinedVoiceChannel from bot_data.model.user_role_enum import UserRoleEnum +from bot_data.model.user_warnings import UserWarnings from bot_graphql.abc.filter_abc import FilterABC from bot_graphql.filter.page import Page from bot_graphql.filter.sort import Sort @@ -90,7 +91,7 @@ class QueryABC(ObjectType): for u in user.users: guild = bot.get_guild(u.server.discord_id) - if permissions.is_member_technician(guild.get_member(u.discord_id)): + if guild is not None and permissions.is_member_technician(guild.get_member(u.discord_id)): return True if config.get_configuration(MAINTENANCE): @@ -101,9 +102,7 @@ class QueryABC(ObjectType): element: Achievement = element for u in user.users: u: User = u - guild = bot.get_guild(u.server.discord_id) - member = guild.get_member(u.discord_id) - if permissions.is_member_moderator(member) and u.server.id == element.server.id: + if u.server.id == element.server.id: access = True break @@ -112,6 +111,8 @@ class QueryABC(ObjectType): for u in user.users: u: User = u guild = bot.get_guild(u.server.discord_id) + if guild is None: + continue member = guild.get_member(u.discord_id) if permissions.is_member_moderator(member) and u.server.id == element.server.id: access = True @@ -122,6 +123,8 @@ class QueryABC(ObjectType): for u in user.users: u: User = u guild = bot.get_guild(u.server.discord_id) + if guild is None: + continue member = guild.get_member(u.discord_id) if permissions.is_member_moderator(member) and u.server.id == element.auto_role.server.id: access = True @@ -138,6 +141,8 @@ class QueryABC(ObjectType): for u in user.users: u: User = u guild = bot.get_guild(u.server.discord_id) + if guild is None: + continue member = guild.get_member(u.discord_id) if permissions.is_member_moderator(member): access = True @@ -161,15 +166,30 @@ class QueryABC(ObjectType): for u in user.users: u: User = u guild = bot.get_guild(u.server.discord_id) + if guild is None: + continue member = guild.get_member(u.discord_id) if u.id == element.id or permissions.is_member_moderator(member): access = True break + elif type(element) == UserWarnings: + for u in user.users: + u: User = u + guild = bot.get_guild(u.server.discord_id) + if guild is None: + continue + member = guild.get_member(u.discord_id) + if u.id == element.user.id or permissions.is_member_moderator(member): + access = True + break + elif type(element) == UserJoinedServer: for u in user.users: u: User = u guild = bot.get_guild(u.server.discord_id) + if guild is None: + continue member = guild.get_member(u.discord_id) if u.id == element.user.id or permissions.is_member_moderator(member): access = True @@ -179,6 +199,8 @@ class QueryABC(ObjectType): for u in user.users: u: User = u guild = bot.get_guild(u.server.discord_id) + if guild is None: + continue member = guild.get_member(u.discord_id) if u.id == element.user.id or permissions.is_member_moderator(member): access = True @@ -188,6 +210,8 @@ class QueryABC(ObjectType): for u in user.users: u: User = u guild = bot.get_guild(u.server.discord_id) + if guild is None: + continue member = guild.get_member(u.discord_id) if u.id == element.user.id or permissions.is_member_moderator(member): access = True @@ -197,6 +221,8 @@ class QueryABC(ObjectType): for u in user.users: u: User = u guild = bot.get_guild(u.server.discord_id) + if guild is None: + continue member = guild.get_member(u.discord_id) if permissions.is_member_technician(member): access = True @@ -207,6 +233,8 @@ class QueryABC(ObjectType): for u in user.users: u: User = u guild = bot.get_guild(u.server.discord_id) + if guild is None: + continue member = guild.get_member(u.discord_id) if permissions.is_member_moderator(member) and u.server.id == element.server.id: access = True @@ -217,6 +245,8 @@ class QueryABC(ObjectType): for u in user.users: u: User = u guild = bot.get_guild(u.server.discord_id) + if guild is None: + continue member = guild.get_member(u.discord_id) if permissions.is_member_moderator(member) and u.server.id == element.server.id: access = True @@ -226,6 +256,8 @@ class QueryABC(ObjectType): for u in user.users: u: User = u guild = bot.get_guild(u.server.discord_id) + if guild is None: + continue member = guild.get_member(u.discord_id) if permissions.is_member_technician(member): access = True diff --git a/bot/src/bot_graphql/bot-graphql.json b/bot/src/bot_graphql/bot-graphql.json index d18cad0b..6ba826cd 100644 --- a/bot/src/bot_graphql/bot-graphql.json +++ b/bot/src/bot_graphql/bot-graphql.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "Sven Heidemann", "AuthorEmail": "sven.heidemann@sh-edraft.de", diff --git a/bot/src/bot_graphql/filter/__init__.py b/bot/src/bot_graphql/filter/__init__.py index a8e2ba20..480ad53a 100644 --- a/bot/src/bot_graphql/filter/__init__.py +++ b/bot/src/bot_graphql/filter/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_graphql.filter" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_graphql/filter/auto_role_rule_filter.py b/bot/src/bot_graphql/filter/auto_role_rule_filter.py index b9571d8f..f5360b5f 100644 --- a/bot/src/bot_graphql/filter/auto_role_rule_filter.py +++ b/bot/src/bot_graphql/filter/auto_role_rule_filter.py @@ -51,6 +51,8 @@ class AutoRoleRuleFilter(FilterABC): def get_role_name(x: AutoRoleRule): guild = self._bot.get_guild(x.auto_role.server.discord_id) + if guild is None: + return False name = guild.get_role(x.role_id).name return name == self._role_name or self._role_name in name diff --git a/bot/src/bot_graphql/filter/short_role_name_filter.py b/bot/src/bot_graphql/filter/short_role_name_filter.py index ea5a8bba..94b56153 100644 --- a/bot/src/bot_graphql/filter/short_role_name_filter.py +++ b/bot/src/bot_graphql/filter/short_role_name_filter.py @@ -57,6 +57,8 @@ class ShortRoleNameFilter(FilterABC): def get_role_name(x: ShortRoleName): guild = self._bot.get_guild(x.server.discord_id) + if guild is None: + return False name = guild.get_role(x.role_id).name return name == self._role_name or self._role_name in name diff --git a/bot/src/bot_graphql/filter/user_filter.py b/bot/src/bot_graphql/filter/user_filter.py index 53c130d5..90909de6 100644 --- a/bot/src/bot_graphql/filter/user_filter.py +++ b/bot/src/bot_graphql/filter/user_filter.py @@ -80,6 +80,8 @@ class UserFilter(FilterABC): def _get_member(user: User): guild = self._bot.get_guild(user.server.discord_id) + if guild is None: + return False member = guild.get_member(user.discord_id) return member is not None and (member.name == self._name or self._name in member.name) diff --git a/bot/src/bot_graphql/filter/user_warning_filter.py b/bot/src/bot_graphql/filter/user_warning_filter.py index 2c716c9e..b3614c1a 100644 --- a/bot/src/bot_graphql/filter/user_warning_filter.py +++ b/bot/src/bot_graphql/filter/user_warning_filter.py @@ -44,7 +44,7 @@ class UserWarningFilter(FilterABC): if self._user is not None: users = self._user.filter(query.select(lambda x: x.user)).select(lambda x: x.id) - query = query.where(lambda x: x.id in users) + query = query.where(lambda x: x.user.id in users) if self._description is not None: query = query.where(lambda x: x.description == self._description or self._description in x.description) diff --git a/bot/src/bot_graphql/graphql/level.gql b/bot/src/bot_graphql/graphql/level.gql index cc937291..15be156a 100644 --- a/bot/src/bot_graphql/graphql/level.gql +++ b/bot/src/bot_graphql/graphql/level.gql @@ -1,5 +1,6 @@ type Level implements TableWithHistoryQuery { id: ID + iconURL: String name: String color: String minXp: Int diff --git a/bot/src/bot_graphql/graphql/server.gql b/bot/src/bot_graphql/graphql/server.gql index 63d07b3f..80beb832 100644 --- a/bot/src/bot_graphql/graphql/server.gql +++ b/bot/src/bot_graphql/graphql/server.gql @@ -29,6 +29,9 @@ type Server implements TableWithHistoryQuery { activeUserCount: Int users(filter: UserFilter, page: Page, sort: Sort): [User] + userWarningCount: Int + userWarnings(filter: UserWarningFilter, page: Page, sort: Sort): [UserWarning] + achievementCount: Int achievements(filter: AchievementFilter, page: Page, sort: Sort): [Achievement] diff --git a/bot/src/bot_graphql/graphql/serverConfig.gql b/bot/src/bot_graphql/graphql/serverConfig.gql index bc2f1e24..a35b5a18 100644 --- a/bot/src/bot_graphql/graphql/serverConfig.gql +++ b/bot/src/bot_graphql/graphql/serverConfig.gql @@ -17,6 +17,7 @@ type ServerConfig implements TableWithHistoryQuery { defaultRoleId: String shortRoleNameOnlySetHighestRole: Boolean gameOfferNotificationChatId: String + resetMemberAfterRejoin: Boolean featureFlagCount: Int featureFlags: [FeatureFlag] @@ -50,7 +51,7 @@ type ServerConfigHistory implements HistoryTableQuery { loginMessageChannelId: String defaultRoleId: String shortRoleNameOnlySetHighestRole: Boolean - gameOfferNotificationChatId: String + resetMemberAfterRejoin: Boolean featureFlagCount: Int featureFlags: [FeatureFlag] @@ -103,6 +104,7 @@ input ServerConfigInput { defaultRoleId: String shortRoleNameOnlySetHighestRole: Boolean gameOfferNotificationChatId: String + resetMemberAfterRejoin: Boolean featureFlags: [FeatureFlagInput] afkChannelIds: [String] diff --git a/bot/src/bot_graphql/model/__init__.py b/bot/src/bot_graphql/model/__init__.py index ba50ca77..2e3ef392 100644 --- a/bot/src/bot_graphql/model/__init__.py +++ b/bot/src/bot_graphql/model/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_graphql.model" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_graphql/mutations/__init__.py b/bot/src/bot_graphql/mutations/__init__.py index 0510b006..54b0371b 100644 --- a/bot/src/bot_graphql/mutations/__init__.py +++ b/bot/src/bot_graphql/mutations/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_graphql.mutations" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_graphql/mutations/server_config_mutation.py b/bot/src/bot_graphql/mutations/server_config_mutation.py index 88669d83..b3434ee0 100644 --- a/bot/src/bot_graphql/mutations/server_config_mutation.py +++ b/bot/src/bot_graphql/mutations/server_config_mutation.py @@ -105,6 +105,11 @@ class ServerConfigMutation(QueryABC): if "gameOfferNotificationChatId" in input else server_config.game_offer_notification_chat_id ) + server_config.reset_member_after_rejoin = ( + input["resetMemberAfterRejoin"] + if "resetMemberAfterRejoin" in input + else server_config.reset_member_after_rejoin + ) server_config.feature_flags = ( dict( zip( diff --git a/bot/src/bot_graphql/mutations/short_role_name_mutation.py b/bot/src/bot_graphql/mutations/short_role_name_mutation.py index 14ae37a0..ec5ee9b2 100644 --- a/bot/src/bot_graphql/mutations/short_role_name_mutation.py +++ b/bot/src/bot_graphql/mutations/short_role_name_mutation.py @@ -7,6 +7,7 @@ from bot_data.model.short_role_name import ShortRoleName from bot_data.model.user_role_enum import UserRoleEnum from bot_graphql.abc.query_abc import QueryABC from bot_core.service.permission_service import PermissionService +from modules.short_role_name.service.short_role_name_service import ShortRoleNameService class ShortRoleNameMutation(QueryABC): @@ -17,6 +18,7 @@ class ShortRoleNameMutation(QueryABC): bot: DiscordBotServiceABC, db: DatabaseContextABC, permissions: PermissionService, + short_role_name_service: ShortRoleNameService, ): QueryABC.__init__(self, "ShortRoleNameMutation") @@ -25,6 +27,7 @@ class ShortRoleNameMutation(QueryABC): self._bot = bot self._db = db self._permissions = permissions + self._short_role_name_service = short_role_name_service self.set_field("createShortRoleName", self.resolve_create_short_role_name) self.set_field("updateShortRoleName", self.resolve_update_short_role_name) @@ -79,6 +82,7 @@ class ShortRoleNameMutation(QueryABC): short_role_name = self._short_role_names.get_short_role_name_by_id(id) self._can_user_mutate_data(short_role_name.server, UserRoleEnum.admin) + self._bot.loop.create_task(self._short_role_name_service.remove_short_role_from_members(short_role_name)) self._short_role_names.delete_short_role_name(short_role_name) self._db.save_changes() diff --git a/bot/src/bot_graphql/mutations/user_mutation.py b/bot/src/bot_graphql/mutations/user_mutation.py index 8d5fb779..e2494c52 100644 --- a/bot/src/bot_graphql/mutations/user_mutation.py +++ b/bot/src/bot_graphql/mutations/user_mutation.py @@ -86,5 +86,9 @@ class UserMutation(QueryABC): continue member = self._bot.get_guild(user.server.discord_id).get_member(user.discord_id) - author = self._users.get_user_by_id(int(warning["author"])) + if "author" not in warning: + author = Route.get_user().users.where(lambda u: u.server.id == user.server.id).single() + else: + author = self._users.get_user_by_id(int(warning["author"])) + self._user_warning_service.add_warnings(member, warning["description"], author.discord_id) diff --git a/bot/src/bot_graphql/queries/__init__.py b/bot/src/bot_graphql/queries/__init__.py index 81fafcdc..1a2fe384 100644 --- a/bot/src/bot_graphql/queries/__init__.py +++ b/bot/src/bot_graphql/queries/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_graphql.queries" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_graphql/queries/discord/__init__.py b/bot/src/bot_graphql/queries/discord/__init__.py index ae6338a4..cae32b89 100644 --- a/bot/src/bot_graphql/queries/discord/__init__.py +++ b/bot/src/bot_graphql/queries/discord/__init__.py @@ -15,7 +15,7 @@ __title__ = "bot_graphql.queries.discord" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/bot_graphql/queries/level_query.py b/bot/src/bot_graphql/queries/level_query.py index 5f726c5b..d4a539b7 100644 --- a/bot/src/bot_graphql/queries/level_query.py +++ b/bot/src/bot_graphql/queries/level_query.py @@ -1,6 +1,5 @@ from cpl_core.database.context import DatabaseContextABC -from bot_data.model.level import Level from bot_data.model.level_history import LevelHistory from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC @@ -9,33 +8,10 @@ class LevelQuery(DataQueryWithHistoryABC): def __init__(self, db: DatabaseContextABC): DataQueryWithHistoryABC.__init__(self, "Level", "LevelsHistory", LevelHistory, db) - self.set_field("id", self.resolve_id) - self.set_field("name", self.resolve_name) - self.set_field("color", self.resolve_color) - self.set_field("minXp", self.resolve_min_xp) - self.set_field("permissions", self.resolve_permissions) - self.set_field("server", self.resolve_server) - - @staticmethod - def resolve_id(level: Level, *_): - return level.id - - @staticmethod - def resolve_name(level: Level, *_): - return level.name - - @staticmethod - def resolve_color(level: Level, *_): - return level.color - - @staticmethod - def resolve_min_xp(level: Level, *_): - return level.min_xp - - @staticmethod - def resolve_permissions(level: Level, *_): - return level.permissions - - @staticmethod - def resolve_server(level: Level, *_): - return level.server + self.set_field("id", lambda x, *_: x.id) + self.set_field("iconURL", lambda x, *_: x.icon_url) + self.set_field("name", lambda x, *_: x.name) + self.set_field("color", lambda x, *_: x.color) + self.set_field("minXp", lambda x, *_: x.min_xp) + self.set_field("permissions", lambda x, *_: x.permissions) + self.set_field("server", lambda x, *_: x.server) diff --git a/bot/src/bot_graphql/queries/server_config_query.py b/bot/src/bot_graphql/queries/server_config_query.py index 3f45fdbf..28915665 100644 --- a/bot/src/bot_graphql/queries/server_config_query.py +++ b/bot/src/bot_graphql/queries/server_config_query.py @@ -37,6 +37,7 @@ class ServerConfigQuery(DataQueryWithHistoryABC): "gameOfferNotificationChatId", lambda config, *_: config.game_offer_notification_chat_id, ) + self.set_field("resetMemberAfterRejoin", lambda config, *_: config.reset_member_after_rejoin) self.add_collection( "featureFlag", lambda config, *_: List( diff --git a/bot/src/bot_graphql/queries/server_query.py b/bot/src/bot_graphql/queries/server_query.py index 9b8b9cbf..355b6576 100644 --- a/bot/src/bot_graphql/queries/server_query.py +++ b/bot/src/bot_graphql/queries/server_query.py @@ -8,7 +8,6 @@ from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC from bot_data.abc.client_repository_abc import ClientRepositoryABC from bot_data.abc.game_server_repository_abc import GameServerRepositoryABC -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.short_role_name_repository_abc import ShortRoleNameRepositoryABC @@ -17,6 +16,7 @@ from bot_data.abc.user_joined_voice_channel_repository_abc import ( UserJoinedVoiceChannelRepositoryABC, ) from bot_data.abc.user_repository_abc import UserRepositoryABC +from bot_data.abc.user_warnings_repository_abc import UserWarningsRepositoryABC from bot_data.model.server import Server from bot_data.model.server_config import ServerConfig from bot_data.model.server_history import ServerHistory @@ -28,7 +28,9 @@ from bot_graphql.filter.level_filter import LevelFilter from bot_graphql.filter.scheduled_event_filter import ScheduledEventFilter from bot_graphql.filter.short_role_name_filter import ShortRoleNameFilter from bot_graphql.filter.user_filter import UserFilter +from bot_graphql.filter.user_warning_filter import UserWarningFilter from bot_graphql.model.server_statistics import ServerStatistics +from modules.level.service.level_service import LevelService class ServerQuery(DataQueryWithHistoryABC): @@ -39,7 +41,7 @@ class ServerQuery(DataQueryWithHistoryABC): db: DatabaseContextABC, auto_roles: AutoRoleRepositoryABC, clients: ClientRepositoryABC, - levels: LevelRepositoryABC, + levels: LevelService, game_servers: GameServerRepositoryABC, users: UserRepositoryABC, ujs: UserJoinedServerRepositoryABC, @@ -48,6 +50,7 @@ class ServerQuery(DataQueryWithHistoryABC): short_role_names: ShortRoleNameRepositoryABC, scheduled_events: ScheduledEventRepositoryABC, server_configs: ServerConfigRepositoryABC, + user_warnings: UserWarningsRepositoryABC, ): DataQueryWithHistoryABC.__init__(self, "Server", "ServersHistory", ServerHistory, db) @@ -77,7 +80,7 @@ class ServerQuery(DataQueryWithHistoryABC): ) self.add_collection( "level", - lambda server, *_: self._levels.get_levels_by_server_id(server.id), + lambda server, *_: self._levels.get_levels_by_server_id(server.id).order_by_descending(lambda x: x.min_xp), LevelFilter, ) self.set_field( @@ -89,6 +92,11 @@ class ServerQuery(DataQueryWithHistoryABC): lambda server, *_: self._users.get_users_with_activity_by_server_id(server.id), UserFilter, ) + self.add_collection( + "userWarning", + lambda server, *_: user_warnings.get_user_warnings_by_server_id(server.id), + UserWarningFilter, + ) self.add_collection( "gameServer", lambda server, *_: game_servers.get_game_servers_by_server_id(server.id), diff --git a/bot/src/modules/achievements/__init__.py b/bot/src/modules/achievements/__init__.py index 5a515655..4d9e23a5 100644 --- a/bot/src/modules/achievements/__init__.py +++ b/bot/src/modules/achievements/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.achievements" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/achievements/achievements.json b/bot/src/modules/achievements/achievements.json index a7d12f1c..cf57f7b6 100644 --- a/bot/src/modules/achievements/achievements.json +++ b/bot/src/modules/achievements/achievements.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "Sven Heidemann", "AuthorEmail": "sven.heidemann@sh-edraft.de", diff --git a/bot/src/modules/achievements/commands/__init__.py b/bot/src/modules/achievements/commands/__init__.py index 795adef3..8eed285c 100644 --- a/bot/src/modules/achievements/commands/__init__.py +++ b/bot/src/modules/achievements/commands/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.achievements.commands" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/achievements/events/__init__.py b/bot/src/modules/achievements/events/__init__.py index 6ea099e1..61513c27 100644 --- a/bot/src/modules/achievements/events/__init__.py +++ b/bot/src/modules/achievements/events/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.achievements.events" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/achievements/model/__init__.py b/bot/src/modules/achievements/model/__init__.py index d2df4eff..f0a906e7 100644 --- a/bot/src/modules/achievements/model/__init__.py +++ b/bot/src/modules/achievements/model/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.achievements.model" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/auto_role/__init__.py b/bot/src/modules/auto_role/__init__.py index ca2e19ee..448cba17 100644 --- a/bot/src/modules/auto_role/__init__.py +++ b/bot/src/modules/auto_role/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.auto_role" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/auto_role/auto-role.json b/bot/src/modules/auto_role/auto-role.json index 4850d169..d50a714d 100644 --- a/bot/src/modules/auto_role/auto-role.json +++ b/bot/src/modules/auto_role/auto-role.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "", "AuthorEmail": "", diff --git a/bot/src/modules/auto_role/command/__init__.py b/bot/src/modules/auto_role/command/__init__.py index af18fdfa..f00ec6b7 100644 --- a/bot/src/modules/auto_role/command/__init__.py +++ b/bot/src/modules/auto_role/command/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.auto_role.command" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/auto_role/events/__init__.py b/bot/src/modules/auto_role/events/__init__.py index 20df0dce..e192433e 100644 --- a/bot/src/modules/auto_role/events/__init__.py +++ b/bot/src/modules/auto_role/events/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.auto_role.events" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/auto_role/helper/__init__.py b/bot/src/modules/auto_role/helper/__init__.py index f922ea6b..7ce856fe 100644 --- a/bot/src/modules/auto_role/helper/__init__.py +++ b/bot/src/modules/auto_role/helper/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.auto_role.helper" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/base/__init__.py b/bot/src/modules/base/__init__.py index 9a3b8f37..e086d6e8 100644 --- a/bot/src/modules/base/__init__.py +++ b/bot/src/modules/base/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.base" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/base/base.json b/bot/src/modules/base/base.json index 4f7f0d66..ce20f649 100644 --- a/bot/src/modules/base/base.json +++ b/bot/src/modules/base/base.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "", "AuthorEmail": "", diff --git a/bot/src/modules/base/command/__init__.py b/bot/src/modules/base/command/__init__.py index 95188d93..b3e469ea 100644 --- a/bot/src/modules/base/command/__init__.py +++ b/bot/src/modules/base/command/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.base.command" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/base/command/afk_command.py b/bot/src/modules/base/command/afk_command.py index 092c9788..211f5f88 100644 --- a/bot/src/modules/base/command/afk_command.py +++ b/bot/src/modules/base/command/afk_command.py @@ -1,3 +1,4 @@ +import discord from cpl_core.configuration import ConfigurationABC from cpl_discord.command import DiscordCommandABC from cpl_discord.service import DiscordBotServiceABC @@ -8,6 +9,7 @@ from discord.ext.commands import Context from bot_core.abc.client_utils_abc import ClientUtilsABC from bot_core.abc.message_service_abc import MessageServiceABC +from bot_core.abc.permission_service_abc import PermissionServiceABC from bot_core.helper.command_checks import CommandChecks from bot_core.logging.command_logger import CommandLogger from bot_data.model.server_config import ServerConfig @@ -22,6 +24,7 @@ class AFKCommand(DiscordCommandABC): bot: DiscordBotServiceABC, client_utils: ClientUtilsABC, translate: TranslatePipe, + permissions: PermissionServiceABC, ): DiscordCommandABC.__init__(self) @@ -29,6 +32,7 @@ class AFKCommand(DiscordCommandABC): self._config = config self._message_service = message_service self._bot = bot + self._permissions = permissions self._client_utils = client_utils self._t = translate @@ -37,11 +41,19 @@ class AFKCommand(DiscordCommandABC): @commands.hybrid_command() @commands.guild_only() @CommandChecks.check_is_ready() - async def afk(self, ctx: Context): + async def afk(self, ctx: Context, member: discord.Member = None): + is_mod = self._permissions.is_member_moderator(ctx.author) + if member is not None and not is_mod: + await self._message_service.send_ctx_msg(ctx, self._t.transform("common.no_permission_message")) + return + self._logger.debug(__name__, f"Received command afk {ctx}") settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild.id}") - if ctx.author.voice is None or ctx.author.voice.channel is None: + if member is None: + member = ctx.author + + if member.voice is None or member.voice.channel is None: await self._message_service.send_ctx_msg( ctx, self._t.transform("modules.base.afk_command_channel_missing_message"), @@ -54,7 +66,7 @@ class AFKCommand(DiscordCommandABC): ) channel: VoiceChannel = ctx.guild.get_channel(settings.afk_command_channel_id) try: - await ctx.author.move_to(channel) + await member.move_to(channel) self._client_utils.moved_user(ctx.guild.id) except Exception as e: self._logger.error( diff --git a/bot/src/modules/base/events/__init__.py b/bot/src/modules/base/events/__init__.py index e36fb3b7..24afa605 100644 --- a/bot/src/modules/base/events/__init__.py +++ b/bot/src/modules/base/events/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.base.events" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/base/events/base_on_member_join_event.py b/bot/src/modules/base/events/base_on_member_join_event.py index 4cd4f2e3..ef7da1a3 100644 --- a/bot/src/modules/base/events/base_on_member_join_event.py +++ b/bot/src/modules/base/events/base_on_member_join_event.py @@ -78,6 +78,12 @@ class BaseOnMemberJoinEvent(OnMemberJoinABC): user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id) if user is not None: self._user_joins.add_user_joined_server(UserJoinedServer(user, datetime.now())) + + server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{member.guild.id}") + if server_config.reset_member_after_rejoin: + user.reset() + self._users.update_user(user) + self._db.save_changes() return diff --git a/bot/src/modules/base/forms/__init__.py b/bot/src/modules/base/forms/__init__.py index 4c32358c..82a953fa 100644 --- a/bot/src/modules/base/forms/__init__.py +++ b/bot/src/modules/base/forms/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.base.forms" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/base/helper/__init__.py b/bot/src/modules/base/helper/__init__.py index df7174fe..b34aee0b 100644 --- a/bot/src/modules/base/helper/__init__.py +++ b/bot/src/modules/base/helper/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.base.helper" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/base/model/__init__.py b/bot/src/modules/base/model/__init__.py index 751bd5cb..8d24c846 100644 --- a/bot/src/modules/base/model/__init__.py +++ b/bot/src/modules/base/model/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.base.model" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/base/service/__init__.py b/bot/src/modules/base/service/__init__.py index 65c151ec..14ccaa6d 100644 --- a/bot/src/modules/base/service/__init__.py +++ b/bot/src/modules/base/service/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.base.service" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/base/service/user_warnings_service.py b/bot/src/modules/base/service/user_warnings_service.py index 125b82a2..7eaa8141 100644 --- a/bot/src/modules/base/service/user_warnings_service.py +++ b/bot/src/modules/base/service/user_warnings_service.py @@ -92,13 +92,10 @@ class UserWarningsService: elif existing_warnings.count() == 3: server = self._servers.get_server_by_discord_id(member.guild.id) user = self._users.get_user_by_discord_id_and_server_id(member.id, server.id) - levels = self._levels.get_levels_by_server_id(server.id) - new_level = levels.where(lambda l: l.min_xp > 0).order_by(lambda l: l.min_xp).last_or_default() - if new_level is not None: - user.xp = new_level.min_xp - self._users.update_user(user) - self._db.save_changes() + user.xp = 0 + self._users.update_user(user) + self._db.save_changes() await self.notify_user(member, self._t.transform("modules.base.warnings.third")) elif existing_warnings.count() >= 4: diff --git a/bot/src/modules/base/tasks/__init__.py b/bot/src/modules/base/tasks/__init__.py index 5a6527b3..e96231b9 100644 --- a/bot/src/modules/base/tasks/__init__.py +++ b/bot/src/modules/base/tasks/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.base.tasks" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/boot_log/__init__.py b/bot/src/modules/boot_log/__init__.py index f44630ce..37c61048 100644 --- a/bot/src/modules/boot_log/__init__.py +++ b/bot/src/modules/boot_log/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.boot_log" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/boot_log/boot-log.json b/bot/src/modules/boot_log/boot-log.json index 36c149cd..6e2ff722 100644 --- a/bot/src/modules/boot_log/boot-log.json +++ b/bot/src/modules/boot_log/boot-log.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "", "AuthorEmail": "", diff --git a/bot/src/modules/config/__init__.py b/bot/src/modules/config/__init__.py index e98a633a..7841f614 100644 --- a/bot/src/modules/config/__init__.py +++ b/bot/src/modules/config/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.config" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/config/config.json b/bot/src/modules/config/config.json index 511f21f9..6f481dd8 100644 --- a/bot/src/modules/config/config.json +++ b/bot/src/modules/config/config.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "", "AuthorEmail": "", diff --git a/bot/src/modules/config/events/__init__.py b/bot/src/modules/config/events/__init__.py index ee18320d..9e5ba995 100644 --- a/bot/src/modules/config/events/__init__.py +++ b/bot/src/modules/config/events/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.config.events" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/config/service/__init__.py b/bot/src/modules/config/service/__init__.py index 57eace87..c1202bca 100644 --- a/bot/src/modules/config/service/__init__.py +++ b/bot/src/modules/config/service/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.config.service" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/database/__init__.py b/bot/src/modules/database/__init__.py index 4c869766..692367c2 100644 --- a/bot/src/modules/database/__init__.py +++ b/bot/src/modules/database/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.database" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/database/database.json b/bot/src/modules/database/database.json index 79ef8549..cdbc3a33 100644 --- a/bot/src/modules/database/database.json +++ b/bot/src/modules/database/database.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "Sven Heidemann", "AuthorEmail": "sven.heidemann@sh-edraft.de", diff --git a/bot/src/modules/level/__init__.py b/bot/src/modules/level/__init__.py index 6c40cc3b..adc9d0e5 100644 --- a/bot/src/modules/level/__init__.py +++ b/bot/src/modules/level/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.level" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/level/command/__init__.py b/bot/src/modules/level/command/__init__.py index 4dae1895..7deb4c6d 100644 --- a/bot/src/modules/level/command/__init__.py +++ b/bot/src/modules/level/command/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.level.command" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/level/configuration/__init__.py b/bot/src/modules/level/configuration/__init__.py index 62d131d9..6238de17 100644 --- a/bot/src/modules/level/configuration/__init__.py +++ b/bot/src/modules/level/configuration/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.level.configuration" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/level/events/__init__.py b/bot/src/modules/level/events/__init__.py index 494be94c..fe7756a1 100644 --- a/bot/src/modules/level/events/__init__.py +++ b/bot/src/modules/level/events/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.level.events" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/level/level.json b/bot/src/modules/level/level.json index 83abafe7..4c6571d9 100644 --- a/bot/src/modules/level/level.json +++ b/bot/src/modules/level/level.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "", "AuthorEmail": "", diff --git a/bot/src/modules/level/level_seeder.py b/bot/src/modules/level/level_seeder.py index 19c7b773..9f296c30 100644 --- a/bot/src/modules/level/level_seeder.py +++ b/bot/src/modules/level/level_seeder.py @@ -104,7 +104,8 @@ class LevelSeeder(DataSeederABC): levels = levels.order_by_descending(lambda l: l.min_xp) position_above_levels = guild.roles.where(lambda r: r.name == self._level_header).single().position for role in guild.roles.order_by_descending(lambda r: r.position): - if levels.where(lambda l: l.name == role.name).count() == 0: + level = levels.where(lambda l: l.name == role.name).first_or_default() + if level is None: continue new_position = position_above_levels - ( @@ -117,7 +118,7 @@ class LevelSeeder(DataSeederABC): __name__, f"Moved {role.name} from {role.position} to {new_position}", ) - await role.edit(position=new_position) + await role.edit(permissions=Permissions(level.permissions), position=new_position) except Exception as e: self._logger.error(__name__, f"Cannot change position of {role.name}", e) diff --git a/bot/src/modules/level/service/__init__.py b/bot/src/modules/level/service/__init__.py index 02f8210b..198a8eb0 100644 --- a/bot/src/modules/level/service/__init__.py +++ b/bot/src/modules/level/service/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.level.service" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/level/service/level_service.py b/bot/src/modules/level/service/level_service.py index 8f05d4d5..e974aeee 100644 --- a/bot/src/modules/level/service/level_service.py +++ b/bot/src/modules/level/service/level_service.py @@ -1,9 +1,12 @@ +from typing import Optional + import discord from cpl_core.configuration import ConfigurationABC from cpl_core.database.context import DatabaseContextABC from cpl_core.logging import LoggerABC from cpl_discord.container import Guild, Role, Member from cpl_discord.service import DiscordBotServiceABC +from cpl_query.extension import List from cpl_translation import TranslatePipe from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum @@ -40,13 +43,26 @@ class LevelService: self._message_service = message_service self._t = t - def _check_for_feature(self, user: User): - server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{user.server.discord_id}") + def _check_for_feature(self, discord_id: int): + server_config: ServerConfig = self._config.get_configuration(f"ServerConfig_{discord_id}") if not FeatureFlagsSettings.get_flag_from_dict(server_config.feature_flags, FeatureFlagsEnum.level_module): raise Exception(f"Feature {FeatureFlagsEnum.level_module.value} disabled") - def get_level(self, user: User) -> Level: - self._check_for_feature(user) + def get_levels_by_server_id(self, server_id: int) -> List[Level]: + try: + self._check_for_feature(self._servers.get_server_by_id(server_id).discord_id) + except Exception as e: + self._logger.warn(__name__, f"Feature {FeatureFlagsEnum.level_module.value} disabled\n{e}") + return List(Level) + + return self._levels.get_levels_by_server_id(server_id) + + def get_level(self, user: User) -> Optional[Level]: + try: + self._check_for_feature(user.server.discord_id) + except Exception as e: + self._logger.warn(__name__, f"Feature {FeatureFlagsEnum.level_module.value} disabled\n{e}") + return None levels_by_server = self._levels.get_levels_by_server_id(user.server.id) if user.xp < 0: @@ -60,7 +76,7 @@ class LevelService: return levels.last() async def set_level(self, user: User): - self._check_for_feature(user) + self._check_for_feature(user.server.discord_id) level_names = self._levels.get_levels_by_server_id(user.server.id).select(lambda l: l.name) guild: Guild = self._bot.guilds.where(lambda g: g.id == user.server.discord_id).single() member: Member = guild.members.where(lambda m: m.id == user.discord_id).single() diff --git a/bot/src/modules/short_role_name/__init__.py b/bot/src/modules/short_role_name/__init__.py index 9d1ad394..36301488 100644 --- a/bot/src/modules/short_role_name/__init__.py +++ b/bot/src/modules/short_role_name/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.short_role_name" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/short_role_name/events/__init__.py b/bot/src/modules/short_role_name/events/__init__.py index e767db05..94ea80f7 100644 --- a/bot/src/modules/short_role_name/events/__init__.py +++ b/bot/src/modules/short_role_name/events/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.short_role_name.events" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/short_role_name/events/short_role_name_on_member_update_event.py b/bot/src/modules/short_role_name/events/short_role_name_on_member_update_event.py index 92b9a08e..1c4a1525 100644 --- a/bot/src/modules/short_role_name/events/short_role_name_on_member_update_event.py +++ b/bot/src/modules/short_role_name/events/short_role_name_on_member_update_event.py @@ -12,5 +12,5 @@ class ShortRoleNameOnMemberUpdateEvent(OnMemberUpdateABC): @EventChecks.check_is_ready async def on_member_update(self, before: discord.member.Member, after: discord.member.Member): - if before.roles != after.roles or before.name != after.name: + if before.roles != after.roles or before.name != after.name or before.display_name != after.display_name: await self._service.check_short_role_names(after) diff --git a/bot/src/modules/short_role_name/service/__init__.py b/bot/src/modules/short_role_name/service/__init__.py index 10277e21..506b79aa 100644 --- a/bot/src/modules/short_role_name/service/__init__.py +++ b/bot/src/modules/short_role_name/service/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.short_role_name.service" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/short_role_name/service/short_role_name_service.py b/bot/src/modules/short_role_name/service/short_role_name_service.py index 5a2e8af8..2063fdd8 100644 --- a/bot/src/modules/short_role_name/service/short_role_name_service.py +++ b/bot/src/modules/short_role_name/service/short_role_name_service.py @@ -30,6 +30,41 @@ class ShortRoleNameService: self._server = server self._short_role_names = short_role_names + def _remove_short_role_name_from_name(self, short_role_name: ShortRoleName, name: str) -> str: + return ( + name.replace(f" [{short_role_name.short_name}]", "") + .replace(f"[{short_role_name.short_name}] ", "") + .replace(f"[{short_role_name.short_name}]", "") + ) + + async def remove_short_role_from_members(self, short_role_name: ShortRoleName): + guild = self._bot.get_guild(short_role_name.server.discord_id) + settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{guild.id}") + for member in guild.members: + try: + member_roles = List(discord.Role, member.roles) + highest_role: Optional[discord.Role] = ( + member_roles.last_or_default() if settings.short_role_name_only_set_highest_role else None + ) + member_role_ids = member_roles.select(lambda x: x.id) + + if ( + short_role_name.role_id not in member_role_ids + or highest_role + and highest_role.id != short_role_name.role_id + ): + continue + + self._logger.debug(__name__, f"Update member {member.id}") + await member.edit( + nick=self._remove_short_role_name_from_name( + short_role_name, member.nick if member.nick is not None else member.name + ) + ) + self._logger.debug(__name__, f"Updated member {member.id} {member.name}") + except Exception as e: + self._logger.error(__name__, f"Renaming member {member.name} failed", e) + async def check_short_role_names(self, member: discord.Member): self._logger.debug(__name__, f"Started short role name check for {member.id}") settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{member.guild.id}") @@ -53,9 +88,7 @@ class ShortRoleNameService: for short_role_name in self._short_role_names.get_short_role_names_by_server_id(server.id): short_role_name: ShortRoleName = short_role_name - new_nick = new_nick.replace(f" [{short_role_name.short_name}]", "") - new_nick = new_nick.replace(f"[{short_role_name.short_name}] ", "") - new_nick = new_nick.replace(f"[{short_role_name.short_name}]", "") + new_nick = self._remove_short_role_name_from_name(short_role_name, new_nick) if ( short_role_name.role_id not in member_role_ids diff --git a/bot/src/modules/short_role_name/short-role-name.json b/bot/src/modules/short_role_name/short-role-name.json index 42ffeb41..2eda5832 100644 --- a/bot/src/modules/short_role_name/short-role-name.json +++ b/bot/src/modules/short_role_name/short-role-name.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "", "AuthorEmail": "", diff --git a/bot/src/modules/special_offers/__init__.py b/bot/src/modules/special_offers/__init__.py index c4bb30aa..29702c71 100644 --- a/bot/src/modules/special_offers/__init__.py +++ b/bot/src/modules/special_offers/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.special_offers" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/special_offers/special-offers.json b/bot/src/modules/special_offers/special-offers.json index ec7d544d..ade43b0b 100644 --- a/bot/src/modules/special_offers/special-offers.json +++ b/bot/src/modules/special_offers/special-offers.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "", "AuthorEmail": "", diff --git a/bot/src/modules/technician/__init__.py b/bot/src/modules/technician/__init__.py index af28e6c4..86d228aa 100644 --- a/bot/src/modules/technician/__init__.py +++ b/bot/src/modules/technician/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.technician" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/technician/command/__init__.py b/bot/src/modules/technician/command/__init__.py index b66a249c..1390bc8e 100644 --- a/bot/src/modules/technician/command/__init__.py +++ b/bot/src/modules/technician/command/__init__.py @@ -15,7 +15,7 @@ __title__ = "modules.technician.command" __author__ = "Sven Heidemann" __license__ = "MIT" __copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de" -__version__ = "1.2.3" +__version__ = "1.2.8" from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple("VersionInfo", "major minor micro") -version_info = VersionInfo(major="1", minor="2", micro="3") +version_info = VersionInfo(major="1", minor="2", micro="8") diff --git a/bot/src/modules/technician/technician.json b/bot/src/modules/technician/technician.json index dfdf7f18..37bfacf2 100644 --- a/bot/src/modules/technician/technician.json +++ b/bot/src/modules/technician/technician.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "", "AuthorEmail": "", diff --git a/bot/tools/checks/checks.json b/bot/tools/checks/checks.json index 50d69325..d9f7165f 100644 --- a/bot/tools/checks/checks.json +++ b/bot/tools/checks/checks.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "Sven Heidemann", "AuthorEmail": "sven.heidemann@sh-edraft.de", diff --git a/bot/tools/get_version/get-version.json b/bot/tools/get_version/get-version.json index 538a045e..f1d57d66 100644 --- a/bot/tools/get_version/get-version.json +++ b/bot/tools/get_version/get-version.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "Sven Heidemann", "AuthorEmail": "sven.heidemann@sh-edraft.de", diff --git a/bot/tools/migration_to_sql/migration-to-sql.json b/bot/tools/migration_to_sql/migration-to-sql.json index b3de0fc5..e64838eb 100644 --- a/bot/tools/migration_to_sql/migration-to-sql.json +++ b/bot/tools/migration_to_sql/migration-to-sql.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "", "AuthorEmail": "", diff --git a/bot/tools/post_build/post-build.json b/bot/tools/post_build/post-build.json index 0c5e5cf4..cd3a05cd 100644 --- a/bot/tools/post_build/post-build.json +++ b/bot/tools/post_build/post-build.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "Sven Heidemann", "AuthorEmail": "sven.heidemann@sh-edraft.de", diff --git a/bot/tools/set_version/set-version.json b/bot/tools/set_version/set-version.json index 9f196731..dc604d30 100644 --- a/bot/tools/set_version/set-version.json +++ b/bot/tools/set_version/set-version.json @@ -4,7 +4,7 @@ "Version": { "Major": "1", "Minor": "2", - "Micro": "3" + "Micro": "8" }, "Author": "Sven Heidemann", "AuthorEmail": "sven.heidemann@sh-edraft.de", diff --git a/web/package-lock.json b/web/package-lock.json index b19c0429..eee2f07a 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "web", - "version": "1.2.0", + "version": "1.2.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "web", - "version": "1.2.0", + "version": "1.2.4", "dependencies": { "@angular/animations": "^15.1.4", "@angular/common": "^15.1.4", diff --git a/web/package.json b/web/package.json index 0b1829b7..7e1d96e5 100644 --- a/web/package.json +++ b/web/package.json @@ -1,56 +1,56 @@ { - "name": "web", - "version": "1.2.3", - "scripts": { - "ng": "ng", - "update-version": "ts-node update-version.ts", - "prestart": "npm run update-version", - "start": "ng serve", - "prebuild": "npm run update-version", - "build": "ng build", - "watch": "ng build --watch --configuration development", - "test": "ng test", - "gv": "echo $npm_package_version", - "predocker-build": "npm run update-version", - "docker-build": "export VERSION=$npm_package_version; ng build; docker build -t sh-edraft.de/sdb-web:$VERSION .", - "docker-build-dev": "export VERSION=$npm_package_version; ng build --configuration development; docker build -t sh-edraft.de/sdb-web:$VERSION .", - "docker-build-stage": "export VERSION=$npm_package_version; ng build --configuration staging; docker build -t sh-edraft.de/sdb-web:$VERSION ." - }, - "private": true, - "dependencies": { - "@angular/animations": "^15.1.4", - "@angular/common": "^15.1.4", - "@angular/compiler": "^15.1.4", - "@angular/core": "^15.1.4", - "@angular/forms": "^15.1.4", - "@angular/platform-browser": "^15.1.4", - "@angular/platform-browser-dynamic": "^15.1.4", - "@angular/router": "^15.1.4", - "@auth0/angular-jwt": "^5.1.0", - "@microsoft/signalr": "^6.0.9", - "@ngx-translate/core": "^14.0.0", - "@ngx-translate/http-loader": "^7.0.0", - "@types/socket.io-client": "^3.0.0", - "moment": "^2.29.4", - "primeicons": "^6.0.1", - "primeng": "^15.2.0", - "rxjs": "~7.5.0", - "socket.io-client": "^4.5.3", - "zone.js": "~0.11.4" - }, - "devDependencies": { - "@angular-devkit/build-angular": "^15.1.5", - "@angular/cli": "~15.1.5", - "@angular/compiler-cli": "^15.1.4", - "@types/jasmine": "~4.0.0", - "@types/node": "^18.11.9", - "jasmine-core": "~4.1.0", - "karma": "~6.3.0", - "karma-chrome-launcher": "~3.1.0", - "karma-coverage": "~2.2.0", - "karma-jasmine": "~5.0.0", - "karma-jasmine-html-reporter": "~1.7.0", - "tslib": "^2.4.1", - "typescript": "~4.9.5" - } -} + "name": "web", + "version": "1.2.7", + "scripts": { + "ng": "ng", + "update-version": "ts-node update-version.ts", + "prestart": "npm run update-version", + "start": "ng serve", + "prebuild": "npm run update-version", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "test": "ng test", + "gv": "echo $npm_package_version", + "predocker-build": "npm run update-version", + "docker-build": "export VERSION=$npm_package_version; ng build; docker build -t sh-edraft.de/sdb-web:$VERSION .", + "docker-build-dev": "export VERSION=$npm_package_version; ng build --configuration development; docker build -t sh-edraft.de/sdb-web:$VERSION .", + "docker-build-stage": "export VERSION=$npm_package_version; ng build --configuration staging; docker build -t sh-edraft.de/sdb-web:$VERSION ." + }, + "private": true, + "dependencies": { + "@angular/animations": "^15.1.4", + "@angular/common": "^15.1.4", + "@angular/compiler": "^15.1.4", + "@angular/core": "^15.1.4", + "@angular/forms": "^15.1.4", + "@angular/platform-browser": "^15.1.4", + "@angular/platform-browser-dynamic": "^15.1.4", + "@angular/router": "^15.1.4", + "@auth0/angular-jwt": "^5.1.0", + "@microsoft/signalr": "^6.0.9", + "@ngx-translate/core": "^14.0.0", + "@ngx-translate/http-loader": "^7.0.0", + "@types/socket.io-client": "^3.0.0", + "moment": "^2.29.4", + "primeicons": "^6.0.1", + "primeng": "^15.2.0", + "rxjs": "~7.5.0", + "socket.io-client": "^4.5.3", + "zone.js": "~0.11.4" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^15.1.5", + "@angular/cli": "~15.1.5", + "@angular/compiler-cli": "^15.1.4", + "@types/jasmine": "~4.0.0", + "@types/node": "^18.11.9", + "jasmine-core": "~4.1.0", + "karma": "~6.3.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.0.0", + "karma-jasmine-html-reporter": "~1.7.0", + "tslib": "^2.4.1", + "typescript": "~4.9.5" + } +} \ No newline at end of file diff --git a/web/src/app/models/config/server-config.model.ts b/web/src/app/models/config/server-config.model.ts index 616dbecc..bf31a525 100644 --- a/web/src/app/models/config/server-config.model.ts +++ b/web/src/app/models/config/server-config.model.ts @@ -20,6 +20,7 @@ export interface ServerConfig extends DataWithHistory { defaultRoleId?: string; shortRoleNameOnlySetHighestRole?: boolean; gameOfferNotificationChatId?: string; + resetMemberAfterRejoin?: boolean; featureFlags: FeatureFlag[]; afkChannelIds: string[]; moderatorRoleIds: string[]; diff --git a/web/src/app/models/graphql/mutations.model.ts b/web/src/app/models/graphql/mutations.model.ts index bdac7b0c..586f3928 100644 --- a/web/src/app/models/graphql/mutations.model.ts +++ b/web/src/app/models/graphql/mutations.model.ts @@ -340,6 +340,7 @@ export class Mutations { $defaultRoleId: String, $shortRoleNameOnlySetHighestRole: Boolean, $gameOfferNotificationChatId: String, + $resetMemberAfterRejoin: Boolean, $featureFlags: [FeatureFlagInput], $afkChannelIds: [String], $moderatorRoleIds: [String], @@ -365,6 +366,7 @@ export class Mutations { defaultRoleId: $defaultRoleId, shortRoleNameOnlySetHighestRole: $shortRoleNameOnlySetHighestRole, gameOfferNotificationChatId: $gameOfferNotificationChatId, + resetMemberAfterRejoin: $resetMemberAfterRejoin, featureFlags: $featureFlags, afkChannelIds: $afkChannelIds, moderatorRoleIds: $moderatorRoleIds, @@ -388,6 +390,7 @@ export class Mutations { defaultRoleId shortRoleNameOnlySetHighestRole gameOfferNotificationChatId + resetMemberAfterRejoin featureFlags { key value diff --git a/web/src/app/models/graphql/queries.model.ts b/web/src/app/models/graphql/queries.model.ts index d5ceb096..818b3d5f 100644 --- a/web/src/app/models/graphql/queries.model.ts +++ b/web/src/app/models/graphql/queries.model.ts @@ -155,6 +155,7 @@ export class Queries { levelCount levels(filter: $filter, page: $page, sort: $sort) { id + iconURL name color minXp @@ -376,6 +377,22 @@ export class Queries { } `; + static liteUsersQuery = ` + query UsersList($serverId: ID, $filter: UserFilter, $page: Page, $sort: Sort) { + servers(filter: {id: $serverId}) { + userCount + users(filter: $filter, page: $page, sort: $sort) { + id + discordId + name + + createdAt + modifiedAt + } + } + } + `; + static userProfile = ` query UserProfile($serverId: ID, $userId: ID, $page: Page, $sort: Sort) { userCount @@ -502,6 +519,29 @@ export class Queries { } `; + static userWarningsQuery = ` + query userWarnings($serverId: ID, $filter: UserWarningFilter, $page: Page, $sort: Sort) { + servers(filter: {id: $serverId}) { + userWarningCount + userWarnings(filter: $filter, page: $page, sort: $sort) { + id + user { + id + name + } + description + author { + id + name + } + + createdAt + modifiedAt + } + } + } + `; + static autoRolesQuery = ` query AutoRoleQuery($serverId: ID, $filter: AutoRoleFilter, $page: Page, $sort: Sort) { servers(filter: {id: $serverId}) { @@ -637,6 +677,7 @@ export class Queries { defaultRoleId shortRoleNameOnlySetHighestRole gameOfferNotificationChatId + resetMemberAfterRejoin featureFlags { key value diff --git a/web/src/app/modules/auth/components/login/login.component.ts b/web/src/app/modules/auth/components/login/login.component.ts index 6244a373..be1c51ba 100644 --- a/web/src/app/modules/auth/components/login/login.component.ts +++ b/web/src/app/modules/auth/components/login/login.component.ts @@ -69,6 +69,17 @@ export class LoginComponent implements OnInit { this.spinnerService.hideSpinner(); } + openConfirmationMailInfo(email: string) { + this.confirmDialog.confirmDialog( + this.translate.instant( + "auth.login.message.confirm_email"), + this.translate.instant( + "auth.login.message.confirm_email_d", + { email: email } + ) + ); + } + checkDiscordLogin() { this.route.queryParams.pipe(catchError(err => { this.spinnerService.hideSpinner(); @@ -87,19 +98,31 @@ export class LoginComponent implements OnInit { this.spinnerService.hideSpinner(); this.router.navigate(["auth", "login"]).then(() => { }); - this.state = ""; - this.code = ""; + this.confirmDialog.confirmDialog( + this.translate.instant( + "auth.login.message.confirm_email"), + this.translate.instant( + "auth.login.message.confirm_email_resend" + ), + () => { + this.authService.resendConfirmationMailByMail(err.error.email).subscribe(mail => { + this.openConfirmationMailInfo(err.error.email); + } + ); + + this.state = ""; + this.code = ""; + }, + () => { + this.state = ""; + this.code = ""; + } + ); + return throwError(() => err); })).subscribe(token => { if (token.firstLogin) { - this.confirmDialog.confirmDialog( - this.translate.instant( - "auth.login.message.confirm_email"), - this.translate.instant( - "auth.login.message.confirm_email_d", - { email: this.authService.getEMailFromDecodedToken(this.authService.getDecodedToken(token)) } - ) - ); + this.openConfirmationMailInfo(this.authService.getEMailFromDecodedToken(this.authService.getDecodedToken(token)) ?? ""); } this.authService.saveToken(token); diff --git a/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.ts b/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.ts index 8bab8927..2d49e508 100644 --- a/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.ts +++ b/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.ts @@ -1,7 +1,6 @@ import { Component, EventEmitter, Input, Output, ViewChild } from "@angular/core"; import { ToastService } from "../../../../services/toast/toast.service"; import { TranslateService } from "@ngx-translate/core"; -import { elementAt } from "rxjs"; interface UploadEvent { originalEvent: Event; @@ -60,22 +59,21 @@ export class DataImportAndExportComponent { const fileReader = new FileReader(); fileReader.onload = () => { if (!fileReader.result) return; - const newData: any[] = JSON.parse(fileReader.result.toString()); + let incomingData: any[] = JSON.parse(fileReader.result.toString()); this.upload.clear(); - newData.forEach(element => { - element.id = 0; - }); - this.data.forEach(element => { - const existingElement = newData.find(x => this.validator(x, element)); + + let newData: any[]; + newData = []; + + incomingData.forEach(element => { + const existingElement = this.data.find(x => this.validator(x, element)); if (existingElement) { - const index = this.data.indexOf(element); - const oldId = element.id; - element = existingElement; - element.id = oldId; - this.data[index] = element; - newData.splice(newData.indexOf(existingElement), 1); + this.data[this.data.indexOf(existingElement)] = element; + } else { + newData.push(element); } }); + this.callback(this.data, false); this.callback(newData, true); this.data.push(...newData); diff --git a/web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts b/web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts index bf1e7a72..89259635 100644 --- a/web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts +++ b/web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts @@ -1,19 +1,15 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; import { Router } from "@angular/router"; -import { TranslateService } from "@ngx-translate/core"; import { debounceTime, Subject, throwError } from "rxjs"; -import { ConfirmationDialogService } from "src/app/services/confirmation-dialog/confirmation-dialog.service"; import { DataService } from "src/app/services/data/data.service"; import { SpinnerService } from "src/app/services/spinner/spinner.service"; -import { ToastService } from "src/app/services/toast/toast.service"; import { Server, ServerFilter } from "../../../../../models/data/server.model"; import { catchError, takeUntil } from "rxjs/operators"; import { Queries } from "../../../../../models/graphql/queries.model"; import { Page } from "../../../../../models/graphql/filter/page.model"; import { Sort } from "../../../../../models/graphql/filter/sort.model"; import { Query } from "../../../../../models/graphql/query.model"; -import { SidebarService } from "../../../../../services/sidebar/sidebar.service"; import { ServerService } from "../../../../../services/server.service"; @Component({ @@ -47,7 +43,7 @@ export class DashboardComponent implements OnInit, OnDestroy { private spinnerService: SpinnerService, private fb: FormBuilder, private router: Router, - private serverService: ServerService, + private serverService: ServerService ) { } diff --git a/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.html b/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.html index 45e43f36..bed61c7d 100644 --- a/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.html +++ b/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.html @@ -3,7 +3,8 @@
- @@ -17,17 +18,20 @@ {{'view.server.achievements.achievements' | translate}}
- +
-
@@ -179,7 +183,8 @@ {{'common.operator' | translate}}: - + {{achievement.operator}} @@ -200,7 +205,8 @@ - + {{achievement.value}} @@ -209,7 +215,8 @@ - + {{achievement.value}} @@ -241,16 +248,21 @@
- + + (click)="onRowEditInit(dt, achievement, ri)" + [disabled]="!user || !user.isModerator && !user.isAdmin"> + (click)="deleteAchievement(achievement)" + [disabled]="!user || !user.isModerator && !user.isAdmin"> + icon="pi pi-check-circle" (click)="onRowEditSave(achievement, ri)" + [disabled]="!user || !user.isModerator && !user.isAdmin"> + icon="pi pi-times-circle" (click)="onRowEditCancel(ri)" + [disabled]="!user || !user.isModerator && !user.isAdmin">
diff --git a/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.ts b/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.ts index e2b6e508..547e42f7 100644 --- a/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.ts +++ b/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.ts @@ -87,7 +87,7 @@ export class AchievementComponent extends ComponentWithTable implements OnInit, private route: ActivatedRoute) { super("achievement", ["id", "name", "description", "attribute", "operator", "value"], (oldElement: Achievement, newElement: Achievement) => { - return oldElement.name === newElement.name; + return oldElement.id === newElement.id; }); } diff --git a/web/src/app/modules/view/server/config/components/config/config.component.html b/web/src/app/modules/view/server/config/components/config/config.component.html index 8bc387f3..1a5fd307 100644 --- a/web/src/app/modules/view/server/config/components/config/config.component.html +++ b/web/src/app/modules/view/server/config/components/config/config.component.html @@ -14,14 +14,16 @@
{{'view.server.config.bot.message_delete_timer' | translate}}:
+ placeholder="{{'view.server.config.bot.message_delete_timer' | translate}}"> +
{{'view.server.config.bot.notification_chat_id' | translate}}:
-
@@ -30,14 +32,16 @@
{{'view.server.config.bot.max_voice_state_hours' | translate}}:
+ placeholder="{{'view.server.config.bot.max_voice_state_hours' | translate}}"> +
{{'view.server.config.bot.xp_per_message' | translate}}:
-
+
@@ -45,7 +49,8 @@
{{'view.server.config.bot.xp_per_reaction' | translate}}:
-
+
@@ -54,7 +59,8 @@
{{'view.server.config.bot.max_message_xp_per_hour' | translate}}:
+ placeholder="{{'view.server.config.bot.max_message_xp_per_hour' | translate}}"> +
@@ -62,7 +68,8 @@
{{'view.server.config.bot.xp_per_ontime_hour' | translate}}:
+ placeholder="{{'view.server.config.bot.xp_per_ontime_hour' | translate}}"> +
@@ -70,7 +77,8 @@
{{'view.server.config.bot.xp_per_event_participation' | translate}}:
+ placeholder="{{'view.server.config.bot.xp_per_event_participation' | translate}}"> +
@@ -78,7 +86,8 @@
{{'view.server.config.bot.xp_per_achievement' | translate}}:
+ placeholder="{{'view.server.config.bot.xp_per_achievement' | translate}}"> +
@@ -86,14 +95,16 @@
{{'view.server.config.bot.xp_for_birthday' | translate}}:
+ placeholder="{{'view.server.config.bot.xp_for_birthday' | translate}}"> +
{{'view.server.config.bot.afk_command_channel_id' | translate}}:
-
@@ -101,7 +112,8 @@
{{'view.server.config.bot.help_voice_channel_id' | translate}}:
-
@@ -109,7 +121,8 @@
{{'view.server.config.bot.team_channel_id' | translate}}:
-
@@ -117,7 +130,8 @@
{{'view.server.config.bot.login_message_channel_id' | translate}}:
-
@@ -125,15 +139,18 @@
{{'view.server.config.bot.default_role_id' | translate}}:
-
-
{{'view.server.config.bot.short_role_name_only_set_highest_role' | translate}}:
- {{'view.server.config.bot.short_role_name_only_set_highest_role' | translate}}: +
+
@@ -141,17 +158,31 @@
{{'view.server.config.bot.game_offer_notification_chat_id' | translate}}:
-
+
+
+
{{'view.server.config.bot.reset_member_after_rejoin' | translate}}:
+ +
+
+
- - - +
diff --git a/web/src/app/modules/view/server/config/components/config/config.component.ts b/web/src/app/modules/view/server/config/components/config/config.component.ts index 0c39cd02..80356584 100644 --- a/web/src/app/modules/view/server/config/components/config/config.component.ts +++ b/web/src/app/modules/view/server/config/components/config/config.component.ts @@ -126,6 +126,7 @@ export class ConfigComponent implements OnInit { defaultRoleId: this.config.defaultRoleId, shortRoleNameOnlySetHighestRole: this.config.shortRoleNameOnlySetHighestRole, gameOfferNotificationChatId: this.config.gameOfferNotificationChatId, + resetMemberAfterRejoin: this.config.resetMemberAfterRejoin, featureFlags: this.config.featureFlags, afkChannelIds: this.config.afkChannelIds, moderatorRoleIds: this.config.moderatorRoleIds, diff --git a/web/src/app/modules/view/server/levels/components/levels/levels.component.html b/web/src/app/modules/view/server/levels/components/levels/levels.component.html index 0af4809d..2263c5f1 100644 --- a/web/src/app/modules/view/server/levels/components/levels/levels.component.html +++ b/web/src/app/modules/view/server/levels/components/levels/levels.component.html @@ -1,238 +1,250 @@

- {{'view.server.levels.header' | translate}} + {{'view.server.levels.header' | translate}}

-
- +
+ - -
-
-
- {{levels.length}} {{'common.of' | translate}} - {{dt.totalRecords}} - - {{'view.server.levels.levels' | translate}} -
+ +
+
+
+ {{levels.length}} {{'common.of' | translate}} + {{dt.totalRecords}} + + {{'view.server.levels.levels' | translate}} +
- -
+ +
-
- - - -
-
- +
+ + + +
+
+
- - - -
-
{{'common.id' | translate}}
- -
- + + + +
+
{{'common.id' | translate}}
+ +
+ - -
-
{{'common.name' | translate}}
- -
- + +
+
{{'common.icon' | translate}}
+
+ - -
-
{{'common.color' | translate}}
- -
- + +
+
{{'common.name' | translate}}
+ +
+ - -
-
{{'common.min_xp' | translate}}
- -
- + +
+
{{'common.color' | translate}}
+ +
+ - -
-
{{'common.permissions' | translate}}
- -
- + +
+
{{'common.min_xp' | translate}}
+ +
+ - -
-
{{'common.created_at' | translate}}
-
- + +
+
{{'common.permissions' | translate}}
+ +
+ - -
-
{{'common.modified_at' | translate}}
-
- + +
+
{{'common.created_at' | translate}}
+
+ - -
-
{{'common.actions' | translate}}
-
- - + +
+
{{'common.modified_at' | translate}}
+
+ - - -
- -
- - -
- -
- - - - - - - - -
+ +
+
{{'common.actions' | translate}}
+
+ + - - - - {{'common.id' | translate}}: - - - {{level.id}} - - - {{level.id}} - - - + + +
+ +
+ + + + +
+ +
+ + + + + + + + +
- - {{'common.name' | translate}}: - - - - - - {{level.name}} - - - + + + + {{'common.id' | translate}}: + + + {{level.id}} + + + {{level.id}} + + + - - {{'common.color' | translate}}: - - - - - - {{level.color}} - - - + + + - - {{'common.min_xp' | translate}}: - - - - - - {{level.minXp}} - - - + + {{'common.name' | translate}}: + + + + + + {{level.name}} + + + - - {{'common.permissions' | translate}}: - - - - - - {{level.permissions}} - - - + + {{'common.color' | translate}}: + + + + + + {{level.color}} + + + - - {{'common.created_at' | translate}}: - - - {{level.createdAt | date:'dd.MM.yy HH:mm'}} - - - {{level.createdAt | date:'dd.MM.yy HH:mm'}} - - - - - {{'common.modified_at' | translate}}: - - - {{level.modifiedAt | date:'dd.MM.yy HH:mm'}} - - - {{level.modifiedAt | date:'dd.MM.yy HH:mm'}} - - - - -
- - - + + {{'common.min_xp' | translate}}: + + + + + + {{level.minXp}} + + + - - -
- - -
+ + {{'common.permissions' | translate}}: + + + + + + {{level.permissions}} + + + - - - - {{'common.no_entries_found' | translate}} - - - + + {{'common.created_at' | translate}}: + + + {{level.createdAt | date:'dd.MM.yy HH:mm'}} + + + {{level.createdAt | date:'dd.MM.yy HH:mm'}} + + + + + {{'common.modified_at' | translate}}: + + + {{level.modifiedAt | date:'dd.MM.yy HH:mm'}} + + + {{level.modifiedAt | date:'dd.MM.yy HH:mm'}} + + + + +
+ + + - - - -
+ + +
+ + + + + + + + {{'common.no_entries_found' | translate}} + + + + + + +
+
diff --git a/web/src/app/modules/view/server/levels/components/levels/levels.component.ts b/web/src/app/modules/view/server/levels/components/levels/levels.component.ts index 85558bc0..32e713cd 100644 --- a/web/src/app/modules/view/server/levels/components/levels/levels.component.ts +++ b/web/src/app/modules/view/server/levels/components/levels/levels.component.ts @@ -19,7 +19,7 @@ import { Table } from "primeng/table"; import { User } from "../../../../../../models/data/user.model"; import { LevelMutationResult, UpdateUserMutationResult } from "../../../../../../models/graphql/result.model"; import { Mutations } from "../../../../../../models/graphql/mutations.model"; -import { forkJoin, Subject, throwError } from "rxjs"; +import { Subject, throwError } from "rxjs"; import { Server } from "../../../../../../models/data/server.model"; import { UserDTO } from "../../../../../../models/auth/auth-user.dto"; import { ComponentWithTable } from "../../../../../../base/component-with-table"; @@ -72,8 +72,8 @@ export class LevelsComponent extends ComponentWithTable implements OnInit, OnDes private sidebar: SidebarService, private route: ActivatedRoute ) { - super("level", ["id", "name", "color", "min_xp", "permissions"], (oldElement: Level, newElement: Level) => { - return oldElement.name === newElement.name; + super("level", ["id", "icon", "name", "color", "min_xp", "permissions"], (oldElement: Level, newElement: Level) => { + return oldElement.id === newElement.id; }); } diff --git a/web/src/app/modules/view/server/members/members.component.html b/web/src/app/modules/view/server/members/members.component.html index da87353e..e060c58e 100644 --- a/web/src/app/modules/view/server/members/members.component.html +++ b/web/src/app/modules/view/server/members/members.component.html @@ -1,5 +1,5 @@

- {{'view.server.members.header' | translate}} + {{ 'view.server.members.header' | translate }}

@@ -12,10 +12,10 @@
- {{members.length}} {{'common.of' | translate}} - {{dt.totalRecords}} + {{ members.length }} {{ 'common.of' | translate }} + {{ dt.totalRecords }} - {{'view.server.members.members' | translate}} + {{ 'view.server.members.members' | translate }}
-
{{'common.id' | translate}}
+
{{ 'common.id' | translate }}
-
{{'common.discord_id' | translate}}
+
{{ 'common.discord_id' | translate }}
-
{{'common.name' | translate}}
+
{{ 'common.name' | translate }}
-
{{'common.xp' | translate}}
+
{{ 'common.xp' | translate }}
-
{{'common.ontime' | translate}}
+
{{ 'common.ontime' | translate }}
-
{{'common.game_ontime' | translate}}
+
{{ 'common.game_ontime' | translate }}
-
{{'common.activity' | translate}}
+
{{ 'common.activity' | translate }}
-
{{'common.left_server' | translate}}
+
{{ 'common.left_server' | translate }}
-
{{'common.level' | translate}}
+
{{ 'common.level' | translate }}
-
{{'common.created_at' | translate}}
+
{{ 'common.created_at' | translate }}
-
{{'common.modified_at' | translate}}
+
{{ 'common.modified_at' | translate }}
-
{{'common.actions' | translate}}
+
{{ 'common.actions' | translate }}
@@ -156,124 +156,124 @@ - {{'common.id' | translate}}: + {{ 'common.id' | translate }}: - {{member.id}} + {{ member.id }} - {{member.id}} + {{ member.id }} - {{'common.discord_id' | translate}}: + {{ 'common.discord_id' | translate }}: - {{member.discordId}} + {{ member.discordId }} - {{member.discordId}} + {{ member.discordId }} - {{'common.name' | translate}}: + {{ 'common.name' | translate }}: - {{member.name}} + {{ member.name }} - {{member.name}} + {{ member.name }} - {{'common.xp' | translate}}: + {{ 'common.xp' | translate }}: - {{member.xp}} + {{ member.xp }} - {{'common.ontime' | translate}}: + {{ 'common.ontime' | translate }}: - {{member.ontime}} + {{ member.ontime }} - {{member.ontime}} + {{ member.ontime }} - {{'common.game_ontime' | translate}}: + {{ 'common.game_ontime' | translate }}: - {{member.gameOntime}} + {{ member.gameOntime }} - {{member.gameOntime}} + {{ member.gameOntime }} - {{'common.activity' | translate}}: + {{ 'common.activity' | translate }}: - {{member.activityScore}} + {{ member.activityScore }} - {{member.activityScore}} + {{ member.activityScore }} - {{'common.left_server' | translate}}: + {{ 'common.left_server' | translate }}: - {{!member.leftServer | bool}} + {{ !member.leftServer | bool }} - {{!member.leftServer | bool}} + {{ !member.leftServer | bool }} - {{'common.level' | translate}}: + {{ 'common.level' | translate }}: - {{member.level.name}} + {{ member.level?.name }} - {{'common.created_at' | translate}}: + {{ 'common.created_at' | translate }}: - {{member.createdAt | date:'dd.MM.yy HH:mm'}} + {{ member.createdAt | date:'dd.MM.yy HH:mm' }} - {{member.createdAt | date:'dd.MM.yy HH:mm'}} + {{ member.createdAt | date:'dd.MM.yy HH:mm' }} - {{'common.modified_at' | translate}}: + {{ 'common.modified_at' | translate }}: - {{member.modifiedAt | date:'dd.MM.yy HH:mm'}} + {{ member.modifiedAt | date:'dd.MM.yy HH:mm' }} - {{member.modifiedAt | date:'dd.MM.yy HH:mm'}} + {{ member.modifiedAt | date:'dd.MM.yy HH:mm' }} @@ -298,7 +298,7 @@ - {{'common.no_entries_found' | translate}} + {{ 'common.no_entries_found' | translate }} diff --git a/web/src/app/modules/view/server/members/members.component.ts b/web/src/app/modules/view/server/members/members.component.ts index ded4f2a4..d691311d 100644 --- a/web/src/app/modules/view/server/members/members.component.ts +++ b/web/src/app/modules/view/server/members/members.component.ts @@ -64,7 +64,9 @@ export class MembersComponent extends ComponentWithTable implements OnInit, OnDe level: FormControl }>; - filter: UserFilter = {}; + filter: UserFilter = { + leftServer: false + }; page: Page = { pageSize: undefined, pageIndex: undefined @@ -145,7 +147,7 @@ export class MembersComponent extends ComponentWithTable implements OnInit, OnDe id: new FormControl(null), discordId: new FormControl(null), name: [""], - leftServer: new FormControl(null), + leftServer: new FormControl(false), level: new FormControl(null) }); diff --git a/web/src/app/modules/view/server/profile/profile.component.html b/web/src/app/modules/view/server/profile/profile.component.html index c5c6fd3d..e2dbbe47 100644 --- a/web/src/app/modules/view/server/profile/profile.component.html +++ b/web/src/app/modules/view/server/profile/profile.component.html @@ -1,5 +1,5 @@

- {{'view.server.profile.header' | translate}} + {{ 'view.server.profile.header' | translate }}

@@ -11,27 +11,27 @@
-

{{user.name}}

+

{{ user.name }}

-
{{'common.id' | translate}}:
-
{{user.id}}
+
{{ 'common.id' | translate }}:
+
{{ user.id }}
-
{{'common.discord_id' | translate}}:
-
{{user.discordId}}
+
{{ 'common.discord_id' | translate }}:
+
{{ user.discordId }}
-
{{'view.server.profile.message_count' | translate}}:
-
{{user.messageCount}}
+
{{ 'view.server.profile.message_count' | translate }}:
+
{{ user.messageCount }}
-
{{'view.server.profile.reaction_count' | translate}}:
-
{{user.reactionCount}}
+
{{ 'view.server.profile.reaction_count' | translate }}:
+
{{ user.reactionCount }}
-
{{'view.server.profile.birthday' | translate}}:
-
{{user.birthday}}
+
{{ 'view.server.profile.birthday' | translate }}:
+
{{ user.birthday }}
@@ -39,16 +39,16 @@
-
{{'view.server.profile.left_server' | translate}}:
-
{{user.leftServer | bool}}
+
{{ 'view.server.profile.left_server' | translate }}:
+
{{ user.leftServer | bool }}
-
{{'common.created_at' | translate}}:
-
{{user.createdAt | date:'dd.MM.yyyy HH:mm:ss'}}
+
{{ 'common.created_at' | translate }}:
+
{{ user.createdAt | date:'dd.MM.yyyy HH:mm:ss' }}
-
{{'common.modified_at' | translate}}:
-
{{user.modifiedAt | date:'dd.MM.yyyy HH:mm:ss'}}
+
{{ 'common.modified_at' | translate }}:
+
{{ user.modifiedAt | date:'dd.MM.yyyy HH:mm:ss' }}
@@ -68,22 +68,22 @@ [readonly]="isModerator && !isEditing">
- {{user.level.name}} + {{ user.level.name }}
-
{{'common.ontime' | translate}}:
-
{{user.ontime}}
+
{{ 'common.ontime' | translate }}:
+
{{ user.ontime }}
-
{{'common.game_ontime' | translate}}:
-
{{user.gameOntime}}
+
{{ 'common.game_ontime' | translate }}:
+
{{ user.gameOntime }}
-
{{'common.activity' | translate}}:
-
{{user.activityScore}}
+
{{ 'common.activity' | translate }}:
+
{{ user.activityScore }}
@@ -99,7 +99,7 @@
-

{{'common.user_warnings' | translate}}

+

{{ 'common.user_warnings' | translate }}

@@ -113,25 +113,25 @@
-
{{'common.description' | translate}}
+
{{ 'common.description' | translate }}
-
{{'common.author' | translate}}
+
{{ 'common.author' | translate }}
-
{{'common.created_at' | translate}}
+
{{ 'common.created_at' | translate }}
-
{{'common.actions' | translate}}
+
{{ 'common.actions' | translate }}
@@ -144,29 +144,29 @@ - {{value.description}} + {{ value.description }} - {{value.author?.name}} + {{ value.author?.name }} - {{value.author?.name}} + {{ value.author?.name }} - {{'common.created_at' | translate}}: + {{ 'common.created_at' | translate }}: - {{value.createdAt | date:'dd.MM.yy HH:mm'}} + {{ value.createdAt | date:'dd.MM.yy HH:mm' }} - {{value.createdAt | date:'dd.MM.yy HH:mm'}} + {{ value.createdAt | date:'dd.MM.yy HH:mm' }} @@ -196,18 +196,18 @@
-
{{'common.name' | translate}}:
-
{{achievement.name}}
+
{{ 'common.name' | translate }}:
+
{{ achievement.name }}
-
{{'common.description' | translate}}:
-
{{achievement.description}}
+
{{ 'common.description' | translate }}:
+
{{ achievement.description }}
-
{{'view.server.profile.achievements.time' | translate}}:
-
{{achievement.createdAt | date:'dd.MM.yyyy HH:mm:ss'}}
+
{{ 'view.server.profile.achievements.time' | translate }}:
+
{{ achievement.createdAt | date:'dd.MM.yyyy HH:mm:ss' }}
@@ -219,30 +219,30 @@
-
{{'common.id' | translate}}:
-
{{join.id}}
+
{{ 'common.id' | translate }}:
+
{{ join.id }}
{{'view.server.profile.joined_voice_channel.time' | translate}}: + style="flex: 0.35;">{{ 'view.server.profile.joined_voice_channel.time' | translate }}:
-
{{join.time}} {{'general.hours' | translate}}
+
{{ join.time }} {{ 'general.hours' | translate }}
-
{{'view.server.profile.joined_voice_channel.channel' | translate}}:
-
{{join.channelName}}
+
{{ 'view.server.profile.joined_voice_channel.channel' | translate }}:
+
{{ join.channelName }}
-
{{'common.joined_at' | translate}}:
-
{{join.joinedOn | date:'dd.MM.yyyy HH:mm:ss'}}
+
{{ 'common.joined_at' | translate }}:
+
{{ join.joinedOn | date:'dd.MM.yyyy HH:mm:ss' }}
-
{{'common.leaved_at' | translate}}:
-
{{join.leavedOn | date:'dd.MM.yyyy HH:mm:ss'}}
+
{{ 'common.leaved_at' | translate }}:
+
{{ join.leavedOn | date:'dd.MM.yyyy HH:mm:ss' }}
@@ -254,30 +254,30 @@
-
{{'common.id' | translate}}:
-
{{join.id}}
+
{{ 'common.id' | translate }}:
+
{{ join.id }}
{{'view.server.profile.joined_game_server.time' | translate}}: + style="flex: 0.35;">{{ 'view.server.profile.joined_game_server.time' | translate }}:
-
{{join.time}} {{'general.hours' | translate}}
+
{{ join.time }} {{ 'general.hours' | translate }}
-
{{'view.server.profile.joined_game_server.name' | translate}}:
-
{{join.gameServer}}
+
{{ 'view.server.profile.joined_game_server.name' | translate }}:
+
{{ join.gameServer }}
-
{{'common.joined_at' | translate}}:
-
{{join.joinedOn | date:'dd.MM.yyyy HH:mm:ss'}}
+
{{ 'common.joined_at' | translate }}:
+
{{ join.joinedOn | date:'dd.MM.yyyy HH:mm:ss' }}
-
{{'common.leaved_at' | translate}}:
-
{{join.leavedOn | date:'dd.MM.yyyy HH:mm:ss'}}
+
{{ 'common.leaved_at' | translate }}:
+
{{ join.leavedOn | date:'dd.MM.yyyy HH:mm:ss' }}
@@ -287,13 +287,13 @@
-
{{'common.joined_at' | translate}}:
-
{{join.joinedOn | date:'dd.MM.yyyy HH:mm:ss'}}
+
{{ 'common.joined_at' | translate }}:
+
{{ join.joinedOn | date:'dd.MM.yyyy HH:mm:ss' }}
-
{{'common.leaved_at' | translate}}:
-
{{join.leavedOn | date:'dd.MM.yyyy HH:mm:ss'}}
+
{{ 'common.leaved_at' | translate }}:
+
{{ join.leavedOn | date:'dd.MM.yyyy HH:mm:ss' }}
diff --git a/web/src/app/modules/view/server/scheduled-events/components/scheduled-events/scheduled-events.component.ts b/web/src/app/modules/view/server/scheduled-events/components/scheduled-events/scheduled-events.component.ts index e37e66d6..ff31e343 100644 --- a/web/src/app/modules/view/server/scheduled-events/components/scheduled-events/scheduled-events.component.ts +++ b/web/src/app/modules/view/server/scheduled-events/components/scheduled-events/scheduled-events.component.ts @@ -87,17 +87,17 @@ export class ScheduledEventsComponent extends ComponentWithTable implements OnIn private route: ActivatedRoute) { super("ScheduledEvent", ["id", "interval", "name", "description", "channel_id", "start_time", "end_time", "type", "location"], (oldElement: ScheduledEvent, newElement: ScheduledEvent) => { - return oldElement.name === newElement.name; + return oldElement.id === newElement.id; }); } public ngOnInit(): void { this.loading = true; - this.setFilterForm(); this.data.getServerFromRoute(this.route).then(async server => { this.server = server; let authUser = await this.authService.getLoggedInUser(); this.user = authUser?.users?.find(u => u.server == this.server.id) ?? null; + this.setFilterForm(); }); } diff --git a/web/src/app/modules/view/server/server-routing.module.ts b/web/src/app/modules/view/server/server-routing.module.ts index 310e44a5..512ea409 100644 --- a/web/src/app/modules/view/server/server-routing.module.ts +++ b/web/src/app/modules/view/server/server-routing.module.ts @@ -8,19 +8,50 @@ import { MemberRoles } from "../../../models/auth/auth-user.dto"; const routes: Routes = [ { path: "", component: ServerDashboardComponent }, - { path: "members", component: MembersComponent, canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } }, + { + path: "members", + component: MembersComponent, + canActivate: [AuthGuard], + data: { memberRole: MemberRoles.Moderator } + }, { path: "members/:memberId", component: ProfileComponent }, + { + path: "user-warnings", + loadChildren: () => import("./user-warning/user-warning.module").then(m => m.UserWarningModule), + canActivate: [AuthGuard], + data: { memberRole: MemberRoles.Moderator } + }, { path: "auto-roles", loadChildren: () => import("./auto-role/auto-role.module").then(m => m.AutoRoleModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } }, - { path: "levels", loadChildren: () => import("./levels/levels.module").then(m => m.LevelsModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } }, - { path: "achievements", loadChildren: () => import("./achievements/achievements.module").then(m => m.AchievementsModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } }, - { path: "short-role-names", loadChildren: () => import("./short-role-name/short-role-name.module").then(m => m.ShortRoleNameModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } }, - { path: "scheduled-events", loadChildren: () => import("./scheduled-events/scheduled-events.module").then(m => m.ScheduledEventsModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } }, - { path: "config", loadChildren: () => import("./config/config.module").then(m => m.ConfigModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Admin } } + { + path: "levels", loadChildren: () => import("./levels/levels.module").then(m => m.LevelsModule) + }, + { + path: "achievements", + loadChildren: () => import("./achievements/achievements.module").then(m => m.AchievementsModule) + }, + { + path: "short-role-names", + loadChildren: () => import("./short-role-name/short-role-name.module").then(m => m.ShortRoleNameModule), + canActivate: [AuthGuard], + data: { memberRole: MemberRoles.Moderator } + }, + { + path: "scheduled-events", + loadChildren: () => import("./scheduled-events/scheduled-events.module").then(m => m.ScheduledEventsModule), + canActivate: [AuthGuard], + data: { memberRole: MemberRoles.Moderator } + }, + { + path: "config", + loadChildren: () => import("./config/config.module").then(m => m.ConfigModule), + canActivate: [AuthGuard], + data: { memberRole: MemberRoles.Admin } + } ]; @NgModule({ diff --git a/web/src/app/modules/view/server/short-role-name/components/short-role-names/short-role-names.component.ts b/web/src/app/modules/view/server/short-role-name/components/short-role-names/short-role-names.component.ts index f20fe69e..f74130e4 100644 --- a/web/src/app/modules/view/server/short-role-name/components/short-role-names/short-role-names.component.ts +++ b/web/src/app/modules/view/server/short-role-name/components/short-role-names/short-role-names.component.ts @@ -16,7 +16,12 @@ import { Sort, SortDirection } from "../../../../../../models/graphql/filter/sor import { Subject, throwError } from "rxjs"; import { UserDTO } from "../../../../../../models/auth/auth-user.dto"; import { Queries } from "../../../../../../models/graphql/queries.model"; -import { ShortRoleNameListQuery, Query, SingleDiscordQuery, ShortRoleNamePositionsQuery } from "../../../../../../models/graphql/query.model"; +import { + Query, + ShortRoleNameListQuery, + ShortRoleNamePositionsQuery, + SingleDiscordQuery +} from "../../../../../../models/graphql/query.model"; import { catchError, debounceTime, takeUntil } from "rxjs/operators"; import { LazyLoadEvent, MenuItem } from "primeng/api"; import { Table } from "primeng/table"; @@ -74,7 +79,7 @@ export class ShortRoleNamesComponent extends ComponentWithTable implements OnIni private route: ActivatedRoute ) { super("short-role-names", ["id", "name", "role", "position"], (oldElement: ShortRoleName, newElement: ShortRoleName) => { - return oldElement.shortName === newElement.shortName && + return oldElement.id === newElement.id && oldElement.roleId === newElement.roleId; }); } diff --git a/web/src/app/modules/view/server/user-warning/components/user-warning/user-warning.component.html b/web/src/app/modules/view/server/user-warning/components/user-warning/user-warning.component.html new file mode 100644 index 00000000..53fa79b4 --- /dev/null +++ b/web/src/app/modules/view/server/user-warning/components/user-warning/user-warning.component.html @@ -0,0 +1,213 @@ +

+ {{'common.user_warnings' | translate}} +

+
+
+ + + +
+
+
+ {{userWarnings.length}} {{'common.of' | translate}} + {{dt.totalRecords}} + + {{'common.user_warnings' | translate}} +
+ + +
+ +
+ + + +
+
+
+ + + + +
+
{{'common.id' | translate}}
+ +
+ + + +
+
{{'common.description' | translate}}
+ +
+ + + +
+
{{'common.member' | translate}}
+ +
+ + + +
+
{{'common.author' | translate}}
+ +
+ + + +
+
{{'common.created_at' | translate}}
+
+ + + +
+
{{'common.modified_at' | translate}}
+
+ + + +
+
{{'common.actions' | translate}}
+
+ + + + + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + + + +
+ + + + + {{'common.id' | translate}}: + + + {{userWarning.id}} + + + {{userWarning.id}} + + + + + + {{'common.description' | translate}}: + + + + {{userWarning.description}} + + + {{userWarning.description}} + + + + + + {{'common.member' | translate}}: + + + + {{userWarning.user.name}} + + + {{userWarning.user.name}} + + + + + + {{'common.author' | translate}}: + + + {{'common.you' | translate}} + + + {{userWarning.author.name}} + + + + + + {{'common.created_at' | translate}}: + {{userWarning.createdAt | date:'dd.MM.yy HH:mm'}} + + + + {{'common.modified_at' | translate}}: + {{userWarning.modifiedAt | date:'dd.MM.yy HH:mm'}} + + +
+ + + + +
+ + +
+ + + + + {{'common.no_entries_found' | translate}} + + + + + + +
+
+
+ diff --git a/web/src/app/modules/view/server/user-warning/components/user-warning/user-warning.component.scss b/web/src/app/modules/view/server/user-warning/components/user-warning/user-warning.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/web/src/app/modules/view/server/user-warning/components/user-warning/user-warning.component.spec.ts b/web/src/app/modules/view/server/user-warning/components/user-warning/user-warning.component.spec.ts new file mode 100644 index 00000000..f9f5fbee --- /dev/null +++ b/web/src/app/modules/view/server/user-warning/components/user-warning/user-warning.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from "@angular/core/testing"; + +import { UserWarningComponent } from "./user-warning.component"; + +describe("AchievementComponent", () => { + let component: UserWarningComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [UserWarningComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(UserWarningComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/web/src/app/modules/view/server/user-warning/components/user-warning/user-warning.component.ts b/web/src/app/modules/view/server/user-warning/components/user-warning/user-warning.component.ts new file mode 100644 index 00000000..507d9554 --- /dev/null +++ b/web/src/app/modules/view/server/user-warning/components/user-warning/user-warning.component.ts @@ -0,0 +1,261 @@ +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; +import { Page } from "../../../../../../models/graphql/filter/page.model"; +import { Sort, SortDirection } from "../../../../../../models/graphql/filter/sort.model"; +import { Subject, throwError } from "rxjs"; +import { Server } from "../../../../../../models/data/server.model"; +import { UserDTO } from "../../../../../../models/auth/auth-user.dto"; +import { Queries } from "../../../../../../models/graphql/queries.model"; +import { AuthService } from "../../../../../../services/auth/auth.service"; +import { SpinnerService } from "../../../../../../services/spinner/spinner.service"; +import { ToastService } from "../../../../../../services/toast/toast.service"; +import { ConfirmationDialogService } from "../../../../../../services/confirmation-dialog/confirmation-dialog.service"; +import { TranslateService } from "@ngx-translate/core"; +import { DataService } from "../../../../../../services/data/data.service"; +import { SidebarService } from "../../../../../../services/sidebar/sidebar.service"; +import { ActivatedRoute } from "@angular/router"; +import { UserListQuery, UserWarningQuery } from "../../../../../../models/graphql/query.model"; +import { catchError, debounceTime, takeUntil } from "rxjs/operators"; +import { LazyLoadEvent } from "primeng/api"; +import { Table } from "primeng/table"; +import { User } from "../../../../../../models/data/user.model"; +import { UpdateUserMutationResult } from "../../../../../../models/graphql/result.model"; +import { Mutations } from "../../../../../../models/graphql/mutations.model"; +import { ComponentWithTable } from "../../../../../../base/component-with-table"; +import { UserWarning, UserWarningFilter } from "../../../../../../models/data/user_warning.model"; + +@Component({ + selector: "app-user-warning", + templateUrl: "./user-warning.component.html", + styleUrls: ["./user-warning.component.scss"] +}) +export class UserWarningComponent extends ComponentWithTable implements OnInit, OnDestroy { + public userWarnings: UserWarning[] = []; + public users: User[] = []; + public loading = true; + + public filterForm!: FormGroup<{ + id: FormControl, + description: FormControl, + user: FormControl, + author: FormControl, + }>; + + public filter: UserWarningFilter = {}; + public page: Page = { + pageSize: undefined, + pageIndex: undefined + }; + public sort: Sort = { + sortColumn: undefined, + sortDirection: undefined + }; + + public totalRecords: number = 0; + + public clonedUserWarning: { [s: string]: UserWarning; } = {}; + + private unsubscriber = new Subject(); + private server: Server = {}; + public user: UserDTO | null = null; + + query: string = Queries.userWarningsQuery; + + public constructor( + private authService: AuthService, + private spinner: SpinnerService, + private toastService: ToastService, + private confirmDialog: ConfirmationDialogService, + private fb: FormBuilder, + private translate: TranslateService, + private data: DataService, + private sidebar: SidebarService, + private route: ActivatedRoute) { + super("UserWarning", ["id", "description", "member", "author"], + (oldElement: UserWarning, newElement: UserWarning) => { + return oldElement.id === newElement.id; + }); + } + + public ngOnInit(): void { + this.setFilterForm(); + + this.loading = true; + this.data.getServerFromRoute(this.route).then(async server => { + this.server = server; + this.spinner.showSpinner(); + let authUser = await this.authService.getLoggedInUser(); + this.user = authUser?.users?.find(u => u.server == this.server.id) ?? null; + + this.data.query(Queries.liteUsersQuery, { + serverId: this.server.id, filter: { + leftServer: false + } + }, + (x: { servers: Server[] }) => { + return x.servers[0]; + } + ).subscribe(data => { + this.users = data.users; + }); + this.spinner.hideSpinner(); + this.loadNextPage(); + }); + } + + public ngOnDestroy(): void { + this.unsubscriber.next(); + this.unsubscriber.complete(); + } + + public loadNextPage(): void { + this.data.query(Queries.userWarningsQuery, { + serverId: this.server.id, filter: this.filter, page: this.page, sort: this.sort + }, + (x: { servers: Server[] }) => { + return x.servers[0]; + } + ).subscribe(data => { + this.totalRecords = data.userWarningCount; + this.userWarnings = data.userWarnings; + this.loading = false; + }); + } + + public setFilterForm(): void { + this.filterForm = this.fb.group({ + id: new FormControl(null), + description: new FormControl(null), + user: new FormControl(null), + author: new FormControl(null) + }); + + this.filterForm.valueChanges.pipe( + takeUntil(this.unsubscriber), + debounceTime(600) + ).subscribe(changes => { + if (changes.id) { + this.filter.id = changes.id; + } else { + this.filter.id = undefined; + } + + if (changes.description) { + this.filter.description = changes.description; + } else { + this.filter.description = undefined; + } + + if (changes.user) { + this.filter.user = { name: changes.user }; + } else { + this.filter.user = undefined; + } + + if (changes.author) { + this.filter.author = { name: changes.author }; + } else { + this.filter.author = undefined; + } + + if (this.page.pageSize) + this.page.pageSize = 10; + + if (this.page.pageIndex) + this.page.pageIndex = 0; + + this.loadNextPage(); + }); + } + + public newUserWarningTemplate: UserWarning = { + createdAt: "", + modifiedAt: "" + }; + + public nextPage(event: LazyLoadEvent): void { + this.page.pageSize = event.rows ?? 0; + if (event.first != null && event.rows != null) + this.page.pageIndex = event.first / event.rows; + this.sort.sortColumn = event.sortField ?? undefined; + this.sort.sortDirection = event.sortOrder === 1 ? SortDirection.ASC : event.sortOrder === -1 ? SortDirection.DESC : SortDirection.ASC; + + this.loadNextPage(); + } + + public resetFilters(): void { + this.filterForm.reset(); + } + + public onRowEditInit(table: Table, user: User, index: number): void { + this.clonedUserWarning[index] = { ...user }; + } + + public override onRowEditSave(newUserWarning: UserWarning, index: number): void { + if (this.isEditingNew && JSON.stringify(newUserWarning) === JSON.stringify(this.newUserWarningTemplate)) { + this.isEditingNew = false; + this.userWarnings.splice(index, 1); + return; + } + + if (!newUserWarning.id && !this.isEditingNew) { + return; + } + + this.updateUserByWarning(newUserWarning.user?.id ?? 0, this.userWarnings.filter(uw => uw.user?.id == newUserWarning.user?.id)); + this.isEditingNew = false; + } + + public onRowEditCancel(index: number): void { + if (this.isEditingNew) { + this.userWarnings.splice(index, 1); + delete this.clonedUserWarning[index]; + this.isEditingNew = false; + return; + } + + this.userWarnings[index] = this.clonedUserWarning[index]; + delete this.clonedUserWarning[index]; + } + + public addUserWarning(table: Table): void { + const newUserWarning = JSON.parse(JSON.stringify(this.newUserWarningTemplate)); + + this.userWarnings = [newUserWarning, ...this.userWarnings]; + + table.initRowEdit(newUserWarning); + + const index = this.userWarnings.findIndex(l => l.id == newUserWarning.id); + this.onRowEditInit(table, newUserWarning, index); + + this.isEditingNew = true; + } + + public deleteUserWarning(userWarning: UserWarning): void { + this.userWarnings.splice(this.userWarnings.findIndex(uw => uw.id == userWarning.id), 1); + this.updateUserByWarning(userWarning.user?.id ?? 0, this.userWarnings.filter(uw => uw.user?.id == userWarning.user?.id)); + } + + public updateUserByWarning(userId: number, userWarnings: UserWarning[]) { + this.spinner.showSpinner(); + this.data.mutation(Mutations.updateUser, { + id: userId, + userWarnings: userWarnings?.map(userWarning => { + return { + id: userWarning.id, + user: userWarning.user?.id ?? undefined, + description: userWarning.description, + author: userWarning.author?.id ?? undefined + }; + }) + } + ).pipe(catchError(err => { + this.spinner.hideSpinner(); + return throwError(err); + })).subscribe(_ => { + this.spinner.hideSpinner(); + this.toastService.success(this.translate.instant("view.server.user_warning.message.user_warning_updated"), this.translate.instant("view.server.user_warning.message.user_warning_updated")); + this.loadNextPage(); + }); + } +} diff --git a/web/src/app/modules/view/server/user-warning/user-warning-routing.module.ts b/web/src/app/modules/view/server/user-warning/user-warning-routing.module.ts new file mode 100644 index 00000000..827021d6 --- /dev/null +++ b/web/src/app/modules/view/server/user-warning/user-warning-routing.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from "@angular/core"; +import { RouterModule, Routes } from "@angular/router"; +import { UserWarningComponent } from "./components/user-warning/user-warning.component"; + +const routes: Routes = [ + + { path: "", component: UserWarningComponent } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class UserWarningRoutingModule { + +} diff --git a/web/src/app/modules/view/server/user-warning/user-warning.module.ts b/web/src/app/modules/view/server/user-warning/user-warning.module.ts new file mode 100644 index 00000000..df78033a --- /dev/null +++ b/web/src/app/modules/view/server/user-warning/user-warning.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { UserWarningRoutingModule } from "./user-warning-routing.module"; +import { SharedModule } from "../../../shared/shared.module"; +import { UserWarningComponent } from "./components/user-warning/user-warning.component"; + + +@NgModule({ + declarations: [ + UserWarningComponent + ], + imports: [ + CommonModule, + UserWarningRoutingModule, + SharedModule + ] +}) +export class UserWarningModule { +} diff --git a/web/src/app/services/auth/auth.service.ts b/web/src/app/services/auth/auth.service.ts index f51db323..58db32e7 100644 --- a/web/src/app/services/auth/auth.service.ts +++ b/web/src/app/services/auth/auth.service.ts @@ -2,7 +2,7 @@ import { HttpClient, HttpHeaders } from "@angular/common/http"; import { Injectable } from "@angular/core"; import { Router } from "@angular/router"; import { JwtHelperService } from "@auth0/angular-jwt"; -import { BehaviorSubject, firstValueFrom, Observable, Subject, Subscription, throwError } from "rxjs"; +import { BehaviorSubject, firstValueFrom, Observable, Subscription, throwError } from "rxjs"; import { catchError } from "rxjs/operators"; import { AdminUpdateUserDTO } from "src/app/models/auth/admin-update-user.dto"; import { AuthRoles } from "src/app/models/auth/auth-roles.enum"; @@ -16,7 +16,6 @@ import { GetFilteredAuthUsersResultDTO } from "src/app/models/selection/auth-use import { SettingsService } from "../settings/settings.service"; import { SpinnerService } from "../spinner/spinner.service"; import { DiscordAuthURL } from "../../models/auth/discord-auth-url.dto"; -import { OAuthDTO } from "../../models/auth/oauth.dto"; @Injectable({ providedIn: "root" @@ -108,6 +107,14 @@ export class AuthService { }); } + resendConfirmationMailByMail(email: string): Observable { + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/resend-confirmation-email-by-mail/${email}`, { + headers: new HttpHeaders({ + "Content-Type": "application/json" + }) + }); + } + getEMailFromforgotPasswordId(id: string): Observable { return this.http.post(`${this.appsettings.getApiURL()}/api/auth/confirm-forgot-password/${id}`, { headers: new HttpHeaders({ @@ -173,23 +180,6 @@ export class AuthService { }); } - // /api/auth/discord/register?code= - discordRegister(oAuthDTO: OAuthDTO) { - return this.http.post(`${this.appsettings.getApiURL()}/api/auth/discord/register`, oAuthDTO, { - headers: new HttpHeaders({ - "Content-Type": "application/json" - }) - }); - } - - // discordGetUser(code: string, state: string) { - // return this.http.get(`${this.appsettings.getApiURL()}/api/auth/discord/get-user?code=${code}&state=${state}`, { - // headers: new HttpHeaders({ - // 'Content-Type': 'application/json' - // }) - // }); - // } - /* utils */ saveToken(token: TokenDTO): void { localStorage.setItem("jwt", token.token); diff --git a/web/src/app/services/error-handler/error-handler.service.ts b/web/src/app/services/error-handler/error-handler.service.ts index 89786ef2..12803e86 100644 --- a/web/src/app/services/error-handler/error-handler.service.ts +++ b/web/src/app/services/error-handler/error-handler.service.ts @@ -11,13 +11,14 @@ export class ErrorHandlerService implements ErrorHandler { constructor( private auth: AuthService, - private toast: ToastService, - ) { } + private toast: ToastService + ) { + } handleError(error: HttpErrorResponse): Observable { if (error && error.error) { - let message = 'Unbekannter Fehler'; - let header = 'Fehler'; + let message = "Unbekannter Fehler"; + let header = "Fehler"; const errorDto: ErrorDTO = error.error; if (errorDto.errorCode === ServiceErrorCode.Unauthorized) { @@ -26,7 +27,7 @@ export class ErrorHandlerService implements ErrorHandler { } if (errorDto.errorCode !== undefined) { - header = 'Fehlercode: ' + errorDto.errorCode; + header = "Fehlercode: " + errorDto.errorCode; } if (errorDto.message) { @@ -37,6 +38,7 @@ export class ErrorHandlerService implements ErrorHandler { this.toast.error(header, message); } else { + this.toast.error("ERROR", error.message); console.error(error.message); } diff --git a/web/src/app/services/sidebar/sidebar.service.ts b/web/src/app/services/sidebar/sidebar.service.ts index b5c887f6..4aa35ef5 100644 --- a/web/src/app/services/sidebar/sidebar.service.ts +++ b/web/src/app/services/sidebar/sidebar.service.ts @@ -27,6 +27,7 @@ export class SidebarService { serverDashboard: MenuItem = {}; serverProfile: MenuItem = {}; serverMembers: MenuItem = {}; + serverUserWarnings: MenuItem = {}; serverAutoRoles: MenuItem = {}; serverLevels: MenuItem = {}; serverAchievements: MenuItem = {}; @@ -89,6 +90,12 @@ export class SidebarService { visible: true, routerLink: `server/${this.server?.id}/members` }; + this.serverUserWarnings = { + label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.user_warnings") : "", + icon: "pi pi-exclamation-triangle", + visible: true, + routerLink: `server/${this.server?.id}/user-warnings` + }; this.serverAutoRoles = { label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.auto_roles") : "", @@ -137,7 +144,7 @@ export class SidebarService { icon: "pi pi-server", visible: false, expanded: true, - items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels, this.serverAchievements, this.serverScheduledEvents, this.serverShortRoleNames, this.serverConfig] + items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverUserWarnings, this.serverAutoRoles, this.serverLevels, this.serverAchievements, this.serverScheduledEvents, this.serverShortRoleNames, this.serverConfig] }; this.adminConfig = { label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "", @@ -194,9 +201,10 @@ export class SidebarService { if (this.server) { this.serverMenu.visible = true; this.serverMembers.visible = isTechnicianAndFullAccessActive || user?.isModerator; + this.serverUserWarnings.visible = isTechnicianAndFullAccessActive || user?.isModerator; this.serverAutoRoles.visible = isTechnicianAndFullAccessActive || this.hasFeature("AutoRoleModule") && user?.isModerator; - this.serverLevels.visible = isTechnicianAndFullAccessActive || this.hasFeature("LevelModule") && user?.isModerator; - this.serverAchievements.visible = isTechnicianAndFullAccessActive || this.hasFeature("AchievementsModule") && user?.isModerator; + this.serverLevels.visible = true; + this.serverAchievements.visible = true; this.serverScheduledEvents.visible = isTechnicianAndFullAccessActive || this.hasFeature("ScheduledEvents") && user?.isModerator; this.serverShortRoleNames.visible = isTechnicianAndFullAccessActive || this.hasFeature("ShortRoleName") && user?.isAdmin; diff --git a/web/src/assets/i18n/de.json b/web/src/assets/i18n/de.json index a17ac8e9..fd0be6ab 100644 --- a/web/src/assets/i18n/de.json +++ b/web/src/assets/i18n/de.json @@ -93,7 +93,8 @@ "login_with_discord": "Mit Discord einloggen", "message": { "confirm_email": "E-Mail Bestätigen", - "confirm_email_d": "Sie müssen die E-Mail {{email}} Bestätigen, in dem Sie den Link öffnen, welchen wir Ihnen zugesendet haben." + "confirm_email_d": "Sie müssen die E-Mail {{email}} Bestätigen, in dem Sie den Link öffnen, welchen wir Ihnen zugesendet haben.", + "confirm_email_resend": "Sollen wir die Bestätigungsmail neu verschicken?" }, "password": "Passwort", "password_required": "Passwort benötigt", @@ -180,6 +181,7 @@ "value": "Wert", "xp": "XP" }, + "icon": "Icon", "id": "Id", "import": "Importieren", "interval": "Interval", @@ -189,6 +191,7 @@ "left_server": "Aktiv", "level": "Level", "location": "Ort", + "member": "Mitglied", "message_id": "Nachricht Id", "min_xp": "Min. XP", "modified_at": "Bearbeitet am", @@ -217,7 +220,8 @@ "user_warnings": "Verwarnungen", "users": "Benutzer", "value": "Wert", - "xp": "XP" + "xp": "XP", + "you": "Du" }, "dialog": { "abort": "Abbrechen", @@ -347,7 +351,8 @@ "members": "Mitglieder", "profile": "Dein Profil", "scheduled_events": "Geplante Events", - "short_role_names": "Rollen Kürzel" + "short_role_names": "Rollen Kürzel", + "user_warnings": "Verwarnungen" }, "server_empty": "Kein Server ausgewählt", "settings": "Einstellungen", @@ -370,6 +375,12 @@ "save": "Speichern", "wrong_password": "Falsches Passwort" }, + "change_password": { + "message": { + "error": "Fehler", + "password_cannot_be_changed": "Passwort konnte nicht geändert werden" + } + }, "dashboard": { "filter": { "name": "Name" @@ -455,6 +466,7 @@ "message_delete_timer": "Zeit bis zum löschen einer Botnachricht in sekunden", "moderator_roles": "Moderator Rollen", "notification_chat_id": "Benachrichtungskanal", + "reset_member_after_rejoin": "Mitglied nach erneutem Beitritt zurücksetzen", "short_role_name_only_set_highest_role": "Bei Rollen Kürzeln nur die höchste Rolle verwenden", "team_channel_id": "Team chat", "xp_for_birthday": "XP für Geburtstag", @@ -620,6 +632,11 @@ "short_role_names_update_failed_d": "Die Bearbeitung des Levels ist fehlgeschlagen!" }, "short_role_names": "Rollen Kürzel" + }, + "user_warning": { + "message": { + "user_warning_updated": "Verwarnungen wurde bearbeitet" + } } }, "user_settings": { diff --git a/web/src/assets/i18n/en.json b/web/src/assets/i18n/en.json index 66b67e7a..d8523901 100644 --- a/web/src/assets/i18n/en.json +++ b/web/src/assets/i18n/en.json @@ -93,7 +93,8 @@ "login_with_discord": "Login with discord", "message": { "confirm_email": "Confirm E-Mail", - "confirm_email_d": "You have to confirm your email {{email}} Please confirm your account through the link in the email." + "confirm_email_d": "You have to confirm your email {{email}} Please confirm your account through the link in the email.", + "confirm_email_resend": "Should we resend the confirmation email?" }, "password": "Password", "password_required": "Passwort required", @@ -180,6 +181,7 @@ "value": "Value", "xp": "XP" }, + "icon": "Icon", "id": "Id", "import": "Import", "interval": "interval", @@ -189,6 +191,7 @@ "left_server": "Active", "level": "Level", "location": "Location", + "member": "Member", "message_id": "Message Id", "min_xp": "Min. XP", "modified_at": "Modified at", @@ -217,7 +220,8 @@ "user_warnings": "User warnings", "users": "User", "value": "Value", - "xp": "XP" + "xp": "XP", + "you": "You" }, "dialog": { "abort": "Abort", @@ -347,7 +351,8 @@ "members": "Members", "profile": "Your profile", "scheduled_events": "Scheduled events", - "short_role_names": "Short role names" + "short_role_names": "Short role names", + "user_warnings": "User warnings" }, "server_empty": "No server selected", "settings": "Settings", @@ -370,6 +375,12 @@ "save": "Save", "wrong_password": "Wrong password" }, + "change_password": { + "message": { + "error": "Error", + "password_cannot_be_changed": "Password change failed" + } + }, "dashboard": { "filter": { "name": "Name" @@ -455,6 +466,7 @@ "message_delete_timer": "Time to wait before delete bot messages", "moderator_roles": "Moderator roles", "notification_chat_id": "Notification channel", + "reset_member_after_rejoin": "Reset member after rejoin", "short_role_name_only_set_highest_role": "For role abbreviations use only the highest role", "team_channel_id": "Team chat", "xp_for_birthday": "XP for birthday", @@ -620,6 +632,11 @@ "short_role_names_update_failed_d": "Short role name editing failed!" }, "short_role_names": "Level" + }, + "user_warning": { + "message": { + "user_warning_updated": "Updated user warnings" + } } }, "user_settings": { diff --git a/web/src/assets/version.json b/web/src/assets/version.json index 5ff7884e..0e91b5bb 100644 --- a/web/src/assets/version.json +++ b/web/src/assets/version.json @@ -1,7 +1,7 @@ { - "WebVersion": { - "Major": "1", - "Minor": "2", - "Micro": "3" - } -} + "WebVersion": { + "Major": "1", + "Minor": "2", + "Micro": "7" + } +} \ No newline at end of file