Compare commits
No commits in common. "89ee16d1b5a8504e0ab9aa85305f24dbbcd59605" and "f8992638d443321d4bc8476d2cf21d29f080c82e" have entirely different histories.
89ee16d1b5
...
f8992638d4
9
.gitmodules
vendored
9
.gitmodules
vendored
@ -1,9 +0,0 @@
|
|||||||
[submodule "kdb-bot/src/bot/config"]
|
|
||||||
path = kdb-bot/src/bot/config
|
|
||||||
url = https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot.config.git
|
|
||||||
[submodule "kdb-bot/src/bot_api/config"]
|
|
||||||
path = kdb-bot/src/bot_api/config
|
|
||||||
url = https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot.api.config.git
|
|
||||||
[submodule "kdb-bot/docker"]
|
|
||||||
path = kdb-bot/docker
|
|
||||||
url = https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot.docker.git
|
|
26
cpl-workspace.json
Normal file
26
cpl-workspace.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"WorkspaceSettings": {
|
||||||
|
"DefaultProject": "bot",
|
||||||
|
"Projects": {
|
||||||
|
"bot": "src/bot/bot.json",
|
||||||
|
"bot-core": "src/bot_core/bot-core.json",
|
||||||
|
"bot-data": "src/bot_data/bot-data.json",
|
||||||
|
"admin": "src/modules/admin/admin.json",
|
||||||
|
"auto-role": "src/modules/auto_role/auto-role.json",
|
||||||
|
"base": "src/modules/base/base.json",
|
||||||
|
"boot-log": "src/modules/boot_log/boot-log.json",
|
||||||
|
"database": "src/modules/database/database.json",
|
||||||
|
"moderator": "src/modules/moderator/moderator.json",
|
||||||
|
"permission": "src/modules/permission/permission.json"
|
||||||
|
},
|
||||||
|
"Scripts": {
|
||||||
|
"prod": "export KDB_ENVIRONMENT=production; export KDB_NAME=KDB-Prod; cpl start;",
|
||||||
|
"stage": "export KDB_ENVIRONMENT=staging; export KDB_NAME=KDB-Stage; cpl start;",
|
||||||
|
"dev": "export KDB_ENVIRONMENT=development; export KDB_NAME=KDB-Dev; cpl start;",
|
||||||
|
|
||||||
|
"build-docker": "cpl b; docker-compose down; docker build -t kdb .",
|
||||||
|
"compose": "docker-compose up -d",
|
||||||
|
"docker": "cpl build-docker; cpl compose;"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
64
docker-compose.yml
Normal file
64
docker-compose.yml
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
kdb_prod_1:
|
||||||
|
kdb_staging_1:
|
||||||
|
kdb_db_1:
|
||||||
|
kdb_db_2:
|
||||||
|
|
||||||
|
services:
|
||||||
|
kdb_prod_1:
|
||||||
|
image: kdb/kdb:0.2.1
|
||||||
|
container_name: kdb_prod_1
|
||||||
|
depends_on:
|
||||||
|
- kdb_db_1
|
||||||
|
volumes:
|
||||||
|
- kdb_prod_1:/app
|
||||||
|
environment:
|
||||||
|
KDB_ENVIRONMENT: "production"
|
||||||
|
KDB_TOKEN: ""
|
||||||
|
KDB_PREFIX: "!k "
|
||||||
|
restart: 'no'
|
||||||
|
|
||||||
|
kdb_staging_1:
|
||||||
|
image: kdb/kdb:0.2.1
|
||||||
|
container_name: kdb_staging_1
|
||||||
|
depends_on:
|
||||||
|
- kdb_db_1
|
||||||
|
volumes:
|
||||||
|
- kdb_staging_1:/app
|
||||||
|
environment:
|
||||||
|
KDB_ENVIRONMENT: "staging"
|
||||||
|
KDB_TOKEN: ""
|
||||||
|
KDB_PREFIX: "!kt "
|
||||||
|
restart: 'no'
|
||||||
|
|
||||||
|
kdb_db_1:
|
||||||
|
image: mysql:latest
|
||||||
|
container_name: kdb_db_1
|
||||||
|
command: mysqld --default-authentication-plugin=mysql_native_password
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: "kd_kdb"
|
||||||
|
MYSQL_USER: "kd_kdb"
|
||||||
|
MYSQL_PASSWORD: "kd_kdb"
|
||||||
|
MYSQL_DATABASE: "kd_kdb"
|
||||||
|
ports:
|
||||||
|
- "3307:3306"
|
||||||
|
volumes:
|
||||||
|
- kdb_db_1:/var/lib/mysql
|
||||||
|
|
||||||
|
kdb_db_2:
|
||||||
|
image: mysql:latest
|
||||||
|
container_name: kdb_db_2
|
||||||
|
command: mysqld --default-authentication-plugin=mysql_native_password
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: "kd_kdb"
|
||||||
|
MYSQL_USER: "kd_kdb"
|
||||||
|
MYSQL_PASSWORD: "kd_kdb"
|
||||||
|
MYSQL_DATABASE: "kd_kdb"
|
||||||
|
ports:
|
||||||
|
- "3308:3306"
|
||||||
|
volumes:
|
||||||
|
- kdb_db_2:/var/lib/mysql
|
18
dockerfile
Normal file
18
dockerfile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM python:3.10.7-bullseye
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ./dist/bot/build/ .
|
||||||
|
|
||||||
|
RUN pip install cpl-core --extra-index-url https://pip.sh-edraft.de
|
||||||
|
RUN pip install cpl-discord --extra-index-url https://pip.sh-edraft.de
|
||||||
|
RUN pip install cpl-query --extra-index-url https://pip.sh-edraft.de
|
||||||
|
RUN pip install cpl-translation --extra-index-url https://pip.sh-edraft.de
|
||||||
|
RUN apt-get update -y
|
||||||
|
RUN apt-get install nano -y
|
||||||
|
|
||||||
|
ENV KDB_TOKEN=""
|
||||||
|
ENV KDB_PREFIX="!kdb "
|
||||||
|
ENV KDB_ENVIRONMENT="production"
|
||||||
|
|
||||||
|
CMD [ "bash", "/app/bot/bot"]
|
@ -1,9 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2022-2023 sh-edraft.de
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,2 +0,0 @@
|
|||||||
# kd_discord_bot
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
|||||||
{
|
|
||||||
"WorkspaceSettings": {
|
|
||||||
"DefaultProject": "bot",
|
|
||||||
"Projects": {
|
|
||||||
"bot": "src/bot/bot.json",
|
|
||||||
"bot-api": "src/bot_api/bot-api.json",
|
|
||||||
"bot-core": "src/bot_core/bot-core.json",
|
|
||||||
"bot-data": "src/bot_data/bot-data.json",
|
|
||||||
"auto-role": "src/modules/auto_role/auto-role.json",
|
|
||||||
"base": "src/modules/base/base.json",
|
|
||||||
"boot-log": "src/modules/boot_log/boot-log.json",
|
|
||||||
"database": "src/modules/database/database.json",
|
|
||||||
"level": "src/modules/level/level.json",
|
|
||||||
"permission": "src/modules/permission/permission.json",
|
|
||||||
"stats": "src/modules/stats/stats.json",
|
|
||||||
"technician": "src/modules/technician/technician.json",
|
|
||||||
"get-version": "tools/get_version/get-version.json",
|
|
||||||
"post-build": "tools/post_build/post-build.json",
|
|
||||||
"set-version": "tools/set_version/set-version.json"
|
|
||||||
},
|
|
||||||
"Scripts": {
|
|
||||||
"sv": "cpl set-version $ARGS",
|
|
||||||
"set-version": "cpl run set-version $ARGS --dev; echo '';",
|
|
||||||
|
|
||||||
"gv": "cpl get-version",
|
|
||||||
"get-version": "export VERSION=$(cpl run get-version --dev); echo $VERSION;",
|
|
||||||
|
|
||||||
"pre-build": "cpl set-version $ARGS",
|
|
||||||
"post-build": "cpl run post-build --dev",
|
|
||||||
|
|
||||||
"pre-prod": "cpl build",
|
|
||||||
"prod": "export KDB_ENVIRONMENT=production; export KDB_NAME=KDB-Prod; cpl start;",
|
|
||||||
|
|
||||||
"pre-stage": "cpl build",
|
|
||||||
"stage": "export KDB_ENVIRONMENT=staging; export KDB_NAME=KDB-Stage; cpl start;",
|
|
||||||
|
|
||||||
"pre-dev": "cpl build",
|
|
||||||
"dev": "export KDB_ENVIRONMENT=development; export KDB_NAME=KDB-Dev; cpl start;",
|
|
||||||
|
|
||||||
"docker-build": "cpl build $ARGS; docker build -t kdb-bot/kdb-bot:$(cpl gv) .;",
|
|
||||||
"dc-up": "docker-compose up -d",
|
|
||||||
"dc-down": "docker-compose down",
|
|
||||||
"docker": "cpl dc-down; cpl docker-build; cpl dc-up;"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
Subproject commit 48c2683965611c9a96ebbb908f8dcb4d0d7d71f2
|
|
@ -1,18 +0,0 @@
|
|||||||
# syntax=docker/dockerfile:1
|
|
||||||
FROM python:3.10.6-alpine
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
COPY ./dist/bot/build/kdb-bot/ .
|
|
||||||
COPY ./dist/bot/build/requirements.txt .
|
|
||||||
|
|
||||||
RUN python -m pip install --upgrade pip
|
|
||||||
|
|
||||||
RUN apk update
|
|
||||||
RUN apk add --update alpine-sdk linux-headers
|
|
||||||
RUN apk add bash
|
|
||||||
RUN apk add nano
|
|
||||||
|
|
||||||
RUN pip install -r requirements.txt --extra-index-url https://pip.sh-edraft.de
|
|
||||||
RUN pip install flask[async]
|
|
||||||
|
|
||||||
CMD [ "bash", "/app/bot/bot"]
|
|
@ -1 +0,0 @@
|
|||||||
Subproject commit e6faabbd8b9fe0dbd00533ea1647e7094ea8b19e
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'bot_api.abc'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,92 +0,0 @@
|
|||||||
from abc import ABC, abstractmethod
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria
|
|
||||||
from bot_api.model.auth_user_dto import AuthUserDTO
|
|
||||||
from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO
|
|
||||||
from bot_api.model.email_string_dto import EMailStringDTO
|
|
||||||
from bot_api.model.o_auth_dto import OAuthDTO
|
|
||||||
from bot_api.model.reset_password_dto import ResetPasswordDTO
|
|
||||||
from bot_api.model.token_dto import TokenDTO
|
|
||||||
from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO
|
|
||||||
from bot_data.model.auth_user import AuthUser
|
|
||||||
|
|
||||||
|
|
||||||
class AuthServiceABC(ABC):
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def __init__(self): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def generate_token(self, user: AuthUser) -> str: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def decode_token(self, token: str) -> dict: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_decoded_token_from_request(self) -> dict: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def find_decoded_token_from_request(self) -> Optional[dict]: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def get_all_auth_users_async(self) -> List[AuthUserDTO]: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def get_auth_user_by_email_async(self, email: str, with_password: bool = False) -> AuthUserDTO: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def find_auth_user_by_email_async(self, email: str) -> AuthUserDTO: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def add_auth_user_async(self, user_dto: AuthUserDTO): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def add_auth_user_by_oauth_async(self, dto: OAuthDTO): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO, dc_id: int) -> OAuthDTO: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def delete_auth_user_by_email_async(self, email: str): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def delete_auth_user_async(self, user_dto: AuthUserDTO): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def verify_login(self, token_str: str) -> bool: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def login_discord_async(self, oauth_dto: AuthUserDTO) -> TokenDTO: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def revoke_async(self, token_dto: TokenDTO): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def confirm_email_async(self, id: str) -> bool: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def forgot_password_async(self, email: str): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def confirm_forgot_password_async(self, id: str) -> EMailStringDTO: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def reset_password_async(self, rp_dto: ResetPasswordDTO): pass
|
|
@ -1,13 +0,0 @@
|
|||||||
from abc import ABC, abstractmethod
|
|
||||||
|
|
||||||
|
|
||||||
class DtoABC(ABC):
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def __init__(self): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def from_dict(self, values: dict): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def to_dict(self) -> dict: pass
|
|
@ -1,17 +0,0 @@
|
|||||||
from abc import ABC, abstractmethod
|
|
||||||
|
|
||||||
|
|
||||||
class SelectCriteriaABC(ABC):
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
page_index: int,
|
|
||||||
page_size: int,
|
|
||||||
sort_direction: str,
|
|
||||||
sort_column: str
|
|
||||||
):
|
|
||||||
self.page_index = page_index
|
|
||||||
self.page_size = page_size
|
|
||||||
self.sort_direction = sort_direction
|
|
||||||
self.sort_column = sort_column
|
|
@ -1,16 +0,0 @@
|
|||||||
from abc import abstractmethod
|
|
||||||
|
|
||||||
from cpl_core.database import TableABC
|
|
||||||
|
|
||||||
from bot_api.abc.dto_abc import DtoABC
|
|
||||||
|
|
||||||
|
|
||||||
class TransformerABC:
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@abstractmethod
|
|
||||||
def to_db(dto: DtoABC) -> TableABC: pass
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@abstractmethod
|
|
||||||
def to_dto(db: TableABC) -> DtoABC: pass
|
|
@ -1,156 +0,0 @@
|
|||||||
import re
|
|
||||||
import sys
|
|
||||||
import textwrap
|
|
||||||
import uuid
|
|
||||||
from functools import partial
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
import eventlet
|
|
||||||
from cpl_core.dependency_injection import ServiceProviderABC
|
|
||||||
from cpl_core.utils import CredentialManager
|
|
||||||
from eventlet import wsgi
|
|
||||||
from flask import Flask, request, jsonify, Response
|
|
||||||
from flask_cors import CORS
|
|
||||||
from flask_socketio import SocketIO
|
|
||||||
from werkzeug.exceptions import NotFound
|
|
||||||
|
|
||||||
from bot_api.configuration.api_settings import ApiSettings
|
|
||||||
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_api.logging.api_logger import ApiLogger
|
|
||||||
from bot_api.model.error_dto import ErrorDTO
|
|
||||||
from bot_api.route.route import Route
|
|
||||||
|
|
||||||
|
|
||||||
class Api(Flask):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
logger: ApiLogger,
|
|
||||||
services: ServiceProviderABC,
|
|
||||||
api_settings: ApiSettings,
|
|
||||||
frontend_settings: FrontendSettings,
|
|
||||||
auth_settings: AuthenticationSettings,
|
|
||||||
*args, **kwargs
|
|
||||||
):
|
|
||||||
if not args:
|
|
||||||
kwargs.setdefault('import_name', __name__)
|
|
||||||
|
|
||||||
Flask.__init__(self, *args, **kwargs)
|
|
||||||
|
|
||||||
self._logger = logger
|
|
||||||
self._services = services
|
|
||||||
self._api_settings = api_settings
|
|
||||||
self._auth_settings = auth_settings
|
|
||||||
|
|
||||||
self._cors = CORS(self, support_credentials=True)
|
|
||||||
|
|
||||||
# register hooks
|
|
||||||
self.before_request(self.before_request_hook)
|
|
||||||
self.after_request(self.after_request_hook)
|
|
||||||
|
|
||||||
# register error handler
|
|
||||||
exc_class, code = self._get_exc_class_and_code(Exception)
|
|
||||||
self.register_error_handler(exc_class, self.handle_exception)
|
|
||||||
|
|
||||||
# websockets
|
|
||||||
self._socketio = SocketIO(self, cors_allowed_origins='*', path='/api/socket.io')
|
|
||||||
self._socketio.on_event('connect', self.on_connect)
|
|
||||||
self._socketio.on_event('disconnect', self.on_disconnect)
|
|
||||||
|
|
||||||
self._requests = {}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_methods_from_registered_route() -> Union[list[str], str]:
|
|
||||||
methods = ['Unknown']
|
|
||||||
if request.path in Route.registered_routes and len(Route.registered_routes[request.path]) >= 1 and 'methods' in Route.registered_routes[request.path][1]:
|
|
||||||
methods = Route.registered_routes[request.path][1]['methods']
|
|
||||||
|
|
||||||
if len(methods) == 1:
|
|
||||||
return methods[0]
|
|
||||||
return methods
|
|
||||||
|
|
||||||
def _register_routes(self):
|
|
||||||
for path, f in Route.registered_routes.items():
|
|
||||||
route = f[0]
|
|
||||||
kwargs = f[1]
|
|
||||||
cls = None
|
|
||||||
qual_name_split = route.__qualname__.split('.')
|
|
||||||
if len(qual_name_split) > 0:
|
|
||||||
cls_type = vars(sys.modules[route.__module__])[qual_name_split[0]]
|
|
||||||
cls = self._services.get_service(cls_type)
|
|
||||||
|
|
||||||
partial_f = partial(route, self if cls is None else cls)
|
|
||||||
partial_f.__name__ = route.__name__
|
|
||||||
self.route(path, **kwargs)(partial_f)
|
|
||||||
|
|
||||||
def handle_exception(self, e: Exception):
|
|
||||||
self._logger.error(__name__, f'Caught error', e)
|
|
||||||
|
|
||||||
if isinstance(e, ServiceException):
|
|
||||||
ex: ServiceException = e
|
|
||||||
self._logger.error(__name__, ex.get_detailed_message())
|
|
||||||
error = ErrorDTO(ex.error_code, ex.message)
|
|
||||||
return jsonify(error.to_dict()), 500
|
|
||||||
elif isinstance(e, NotFound):
|
|
||||||
self._logger.error(__name__, e.description)
|
|
||||||
error = ErrorDTO(ServiceErrorCode.NotFound, e.description)
|
|
||||||
return jsonify(error.to_dict()), 404
|
|
||||||
else:
|
|
||||||
tracking_id = uuid.uuid4()
|
|
||||||
user_message = f'Tracking Id: {tracking_id}'
|
|
||||||
self._logger.error(__name__, user_message, e)
|
|
||||||
error = ErrorDTO(None, user_message)
|
|
||||||
return jsonify(error.to_dict()), 400
|
|
||||||
|
|
||||||
def before_request_hook(self):
|
|
||||||
request_id = uuid.uuid4()
|
|
||||||
self._requests[request] = request_id
|
|
||||||
method = request.access_control_request_method
|
|
||||||
|
|
||||||
self._logger.info(__name__, f'Received {request_id} @ {self._get_methods_from_registered_route() if method is None else method} {request.url} from {request.remote_addr}')
|
|
||||||
|
|
||||||
headers = str(request.headers).replace('\n', '\n\t\t')
|
|
||||||
data = request.get_data()
|
|
||||||
data = '' if len(data) == 0 else str(data.decode(encoding="utf-8"))
|
|
||||||
|
|
||||||
text = textwrap.dedent(f'Request: {request_id}:\n\tHeader:\n\t\t{headers}\n\tUser-Agent: {request.user_agent.string}\n\tBody: {data}')
|
|
||||||
self._logger.trace(__name__, text)
|
|
||||||
|
|
||||||
def after_request_hook(self, response: Response):
|
|
||||||
method = request.access_control_request_method
|
|
||||||
request_id = f'{self._get_methods_from_registered_route() if method is None else method} {request.url} from {request.remote_addr}'
|
|
||||||
if request in self._requests:
|
|
||||||
request_id = self._requests[request]
|
|
||||||
|
|
||||||
self._logger.info(__name__, f'Answered {request_id}')
|
|
||||||
|
|
||||||
headers = str(request.headers).replace('\n', '\n\t\t')
|
|
||||||
data = request.get_data()
|
|
||||||
data = '' if len(data) == 0 else str(data.decode(encoding="utf-8"))
|
|
||||||
|
|
||||||
text = textwrap.dedent(f'Request: {request_id}:\n\tHeader:\n\t\t{headers}\n\tResponse: {data}')
|
|
||||||
self._logger.trace(__name__, text)
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
self._logger.info(__name__, f'Starting API {self._api_settings.host}:{self._api_settings.port}')
|
|
||||||
self._register_routes()
|
|
||||||
self.secret_key = CredentialManager.decrypt(self._auth_settings.secret_key)
|
|
||||||
# from waitress import serve
|
|
||||||
# https://docs.pylonsproject.org/projects/waitress/en/stable/arguments.html
|
|
||||||
# serve(self, host=self._apt_settings.host, port=self._apt_settings.port, threads=10, connection_limit=1000, channel_timeout=10)
|
|
||||||
wsgi.server(
|
|
||||||
eventlet.listen((self._api_settings.host, self._api_settings.port)),
|
|
||||||
self,
|
|
||||||
log_output=False
|
|
||||||
)
|
|
||||||
|
|
||||||
def on_connect(self):
|
|
||||||
self._logger.info(__name__, f'Client connected')
|
|
||||||
|
|
||||||
def on_disconnect(self):
|
|
||||||
self._logger.info(__name__, f'Client disconnected')
|
|
@ -1,52 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from cpl_core.configuration import ConfigurationABC
|
|
||||||
from cpl_core.dependency_injection import ServiceCollectionABC
|
|
||||||
from cpl_core.environment import ApplicationEnvironmentABC
|
|
||||||
from cpl_core.mailing import EMailClientABC, EMailClient
|
|
||||||
from cpl_discord.discord_event_types_enum import DiscordEventTypesEnum
|
|
||||||
from cpl_discord.service.discord_collection_abc import DiscordCollectionABC
|
|
||||||
from flask import Flask
|
|
||||||
|
|
||||||
from bot_api.abc.auth_service_abc import AuthServiceABC
|
|
||||||
from bot_api.api import Api
|
|
||||||
from bot_api.api_thread import ApiThread
|
|
||||||
from bot_api.controller.auth_controller import AuthController
|
|
||||||
from bot_api.controller.auth_discord_controller import AuthDiscordController
|
|
||||||
from bot_api.controller.discord.server_controller import ServerController
|
|
||||||
from bot_api.controller.gui_controller import GuiController
|
|
||||||
from bot_api.event.bot_api_on_ready_event import BotApiOnReadyEvent
|
|
||||||
from bot_api.service.auth_service import AuthService
|
|
||||||
from bot_api.service.discord_service import DiscordService
|
|
||||||
from bot_core.abc.module_abc import ModuleABC
|
|
||||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
|
||||||
|
|
||||||
|
|
||||||
class ApiModule(ModuleABC):
|
|
||||||
|
|
||||||
def __init__(self, dc: DiscordCollectionABC):
|
|
||||||
ModuleABC.__init__(self, dc, FeatureFlagsEnum.api_module)
|
|
||||||
|
|
||||||
def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
|
|
||||||
cwd = env.working_directory
|
|
||||||
env.set_working_directory(os.path.dirname(os.path.realpath(__file__)))
|
|
||||||
config.add_json_file(f'config/apisettings.json', optional=False)
|
|
||||||
config.add_json_file(f'config/apisettings.{env.environment_name}.json', optional=True)
|
|
||||||
config.add_json_file(f'config/apisettings.{env.host_name}.json', optional=True)
|
|
||||||
env.set_working_directory(cwd)
|
|
||||||
|
|
||||||
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
|
|
||||||
services.add_singleton(EMailClientABC, EMailClient)
|
|
||||||
|
|
||||||
services.add_singleton(ApiThread)
|
|
||||||
services.add_singleton(Flask, Api)
|
|
||||||
|
|
||||||
services.add_transient(AuthServiceABC, AuthService)
|
|
||||||
services.add_transient(AuthController)
|
|
||||||
services.add_transient(AuthDiscordController)
|
|
||||||
services.add_transient(GuiController)
|
|
||||||
services.add_transient(DiscordService)
|
|
||||||
services.add_transient(ServerController)
|
|
||||||
|
|
||||||
# cpl-discord
|
|
||||||
self._dc.add_event(DiscordEventTypesEnum.on_ready.value, BotApiOnReadyEvent)
|
|
@ -1,24 +0,0 @@
|
|||||||
import threading
|
|
||||||
|
|
||||||
from bot_api.api import Api
|
|
||||||
from bot_api.logging.api_logger import ApiLogger
|
|
||||||
|
|
||||||
|
|
||||||
class ApiThread(threading.Thread):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
logger: ApiLogger,
|
|
||||||
api: Api
|
|
||||||
):
|
|
||||||
threading.Thread.__init__(self, daemon=True)
|
|
||||||
|
|
||||||
self._logger = logger
|
|
||||||
self._api = api
|
|
||||||
|
|
||||||
def run(self) -> None:
|
|
||||||
try:
|
|
||||||
self._logger.trace(__name__, f'Try to start {type(self._api).__name__}')
|
|
||||||
self._api.start()
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, 'Start failed', e)
|
|
@ -1,26 +0,0 @@
|
|||||||
from cpl_core.application import ApplicationExtensionABC
|
|
||||||
from cpl_core.configuration import ConfigurationABC
|
|
||||||
from cpl_core.dependency_injection import ServiceProviderABC
|
|
||||||
|
|
||||||
from bot_api.abc.auth_service_abc import AuthServiceABC
|
|
||||||
from bot_api.configuration.authentication_settings import AuthenticationSettings
|
|
||||||
from bot_api.route.route import Route
|
|
||||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
|
||||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
|
||||||
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
|
|
||||||
|
|
||||||
|
|
||||||
class AppApiExtension(ApplicationExtensionABC):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
ApplicationExtensionABC.__init__(self)
|
|
||||||
|
|
||||||
async def run(self, config: ConfigurationABC, services: ServiceProviderABC):
|
|
||||||
feature_flags: FeatureFlagsSettings = config.get_configuration(FeatureFlagsSettings)
|
|
||||||
if not feature_flags.get_flag(FeatureFlagsEnum.api_module):
|
|
||||||
return
|
|
||||||
|
|
||||||
auth_settings: AuthenticationSettings = config.get_configuration(AuthenticationSettings)
|
|
||||||
auth_users: AuthUserRepositoryABC = services.get_service(AuthUserRepositoryABC)
|
|
||||||
auth: AuthServiceABC = services.get_service(AuthServiceABC)
|
|
||||||
Route.init_authorize(auth_users, auth)
|
|
@ -1 +0,0 @@
|
|||||||
Subproject commit e6046881b562982008583afa973b39ff08b6a3c7
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'bot_api.configuration'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,35 +0,0 @@
|
|||||||
import traceback
|
|
||||||
|
|
||||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
|
||||||
from cpl_core.console import Console
|
|
||||||
|
|
||||||
|
|
||||||
class ApiSettings(ConfigurationModelABC):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
ConfigurationModelABC.__init__(self)
|
|
||||||
|
|
||||||
self._port = 80
|
|
||||||
self._host = ''
|
|
||||||
self._redirect_to_https = False
|
|
||||||
|
|
||||||
@property
|
|
||||||
def port(self) -> int:
|
|
||||||
return self._port
|
|
||||||
|
|
||||||
@property
|
|
||||||
def host(self) -> str:
|
|
||||||
return self._host
|
|
||||||
|
|
||||||
@property
|
|
||||||
def redirect_to_https(self) -> bool:
|
|
||||||
return self._redirect_to_https
|
|
||||||
|
|
||||||
def from_dict(self, settings: dict):
|
|
||||||
try:
|
|
||||||
self._port = int(settings['Port'])
|
|
||||||
self._host = settings['Host']
|
|
||||||
self._redirect_to_https = bool(settings['RedirectToHTTPS'])
|
|
||||||
except Exception as e:
|
|
||||||
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings')
|
|
||||||
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')
|
|
@ -1,48 +0,0 @@
|
|||||||
import traceback
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
|
||||||
from cpl_core.console import Console
|
|
||||||
|
|
||||||
|
|
||||||
class AuthenticationSettings(ConfigurationModelABC):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
ConfigurationModelABC.__init__(self)
|
|
||||||
|
|
||||||
self._secret_key = ''
|
|
||||||
self._issuer = ''
|
|
||||||
self._audience = ''
|
|
||||||
self._token_expire_time = 0
|
|
||||||
self._refresh_token_expire_time = 0
|
|
||||||
|
|
||||||
@property
|
|
||||||
def secret_key(self) -> str:
|
|
||||||
return self._secret_key
|
|
||||||
|
|
||||||
@property
|
|
||||||
def issuer(self) -> str:
|
|
||||||
return self._issuer
|
|
||||||
|
|
||||||
@property
|
|
||||||
def audience(self) -> str:
|
|
||||||
return self._audience
|
|
||||||
|
|
||||||
@property
|
|
||||||
def token_expire_time(self) -> int:
|
|
||||||
return self._token_expire_time
|
|
||||||
|
|
||||||
@property
|
|
||||||
def refresh_token_expire_time(self) -> int:
|
|
||||||
return self._refresh_token_expire_time
|
|
||||||
|
|
||||||
def from_dict(self, settings: dict):
|
|
||||||
try:
|
|
||||||
self._secret_key = settings['SecretKey']
|
|
||||||
self._issuer = settings['Issuer']
|
|
||||||
self._audience = settings['Audience']
|
|
||||||
self._token_expire_time = int(settings['TokenExpireTime'])
|
|
||||||
self._refresh_token_expire_time = int(settings['RefreshTokenExpireTime'])
|
|
||||||
except Exception as e:
|
|
||||||
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings')
|
|
||||||
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')
|
|
@ -1,48 +0,0 @@
|
|||||||
import traceback
|
|
||||||
|
|
||||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
|
||||||
from cpl_core.console import Console
|
|
||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
|
|
||||||
class DiscordAuthenticationSettings(ConfigurationModelABC):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
ConfigurationModelABC.__init__(self)
|
|
||||||
|
|
||||||
self._client_secret = ''
|
|
||||||
self._redirect_url = ''
|
|
||||||
self._scope = List()
|
|
||||||
self._token_url = ''
|
|
||||||
self._auth_url = ''
|
|
||||||
|
|
||||||
@property
|
|
||||||
def client_secret(self) -> str:
|
|
||||||
return self._client_secret
|
|
||||||
|
|
||||||
@property
|
|
||||||
def redirect_url(self) -> str:
|
|
||||||
return self._redirect_url
|
|
||||||
|
|
||||||
@property
|
|
||||||
def scope(self) -> List[str]:
|
|
||||||
return self._scope
|
|
||||||
|
|
||||||
@property
|
|
||||||
def token_url(self) -> str:
|
|
||||||
return self._token_url
|
|
||||||
|
|
||||||
@property
|
|
||||||
def auth_url(self) -> str:
|
|
||||||
return self._auth_url
|
|
||||||
|
|
||||||
def from_dict(self, settings: dict):
|
|
||||||
try:
|
|
||||||
self._client_secret = settings['ClientSecret']
|
|
||||||
self._redirect_url = settings['RedirectURL']
|
|
||||||
self._scope = List(str, settings['Scope'])
|
|
||||||
self._token_url = settings['TokenURL']
|
|
||||||
self._auth_url = settings['AuthURL']
|
|
||||||
except Exception as e:
|
|
||||||
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings')
|
|
||||||
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')
|
|
@ -1,23 +0,0 @@
|
|||||||
import traceback
|
|
||||||
|
|
||||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
|
||||||
from cpl_core.console import Console
|
|
||||||
|
|
||||||
|
|
||||||
class FrontendSettings(ConfigurationModelABC):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
ConfigurationModelABC.__init__(self)
|
|
||||||
|
|
||||||
self._url = ''
|
|
||||||
|
|
||||||
@property
|
|
||||||
def url(self) -> str:
|
|
||||||
return self._url
|
|
||||||
|
|
||||||
def from_dict(self, settings: dict):
|
|
||||||
try:
|
|
||||||
self._url = settings['URL']
|
|
||||||
except Exception as e:
|
|
||||||
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings')
|
|
||||||
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')
|
|
@ -1,55 +0,0 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
|
||||||
from cpl_cli.configuration.version_settings_name_enum import VersionSettingsNameEnum
|
|
||||||
|
|
||||||
|
|
||||||
class VersionSettings(ConfigurationModelABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
major: str = None,
|
|
||||||
minor: str = None,
|
|
||||||
micro: str = None
|
|
||||||
):
|
|
||||||
ConfigurationModelABC.__init__(self)
|
|
||||||
|
|
||||||
self._major: Optional[str] = major
|
|
||||||
self._minor: Optional[str] = minor
|
|
||||||
self._micro: Optional[str] = micro
|
|
||||||
|
|
||||||
@property
|
|
||||||
def major(self) -> str:
|
|
||||||
return self._major
|
|
||||||
|
|
||||||
@property
|
|
||||||
def minor(self) -> str:
|
|
||||||
return self._minor
|
|
||||||
|
|
||||||
@property
|
|
||||||
def micro(self) -> str:
|
|
||||||
return self._micro
|
|
||||||
|
|
||||||
def to_str(self) -> str:
|
|
||||||
if self._micro is None:
|
|
||||||
return f'{self._major}.{self._minor}'
|
|
||||||
else:
|
|
||||||
return f'{self._major}.{self._minor}.{self._micro}'
|
|
||||||
|
|
||||||
def from_dict(self, settings: dict):
|
|
||||||
self._major = settings[VersionSettingsNameEnum.major.value]
|
|
||||||
self._minor = settings[VersionSettingsNameEnum.minor.value]
|
|
||||||
micro = settings[VersionSettingsNameEnum.micro.value]
|
|
||||||
if micro != '':
|
|
||||||
self._micro = micro
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
version = {
|
|
||||||
VersionSettingsNameEnum.major.value: self._major,
|
|
||||||
VersionSettingsNameEnum.minor.value: self._minor,
|
|
||||||
}
|
|
||||||
|
|
||||||
if self._micro is not None:
|
|
||||||
version[VersionSettingsNameEnum.micro.value] = self._micro
|
|
||||||
|
|
||||||
return version
|
|
@ -1,155 +0,0 @@
|
|||||||
from cpl_core.configuration import ConfigurationABC
|
|
||||||
from cpl_core.environment import ApplicationEnvironmentABC
|
|
||||||
from cpl_core.mailing import EMailClientABC, EMailClientSettings
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
from flask import request, jsonify, Response
|
|
||||||
|
|
||||||
from bot_api.abc.auth_service_abc import AuthServiceABC
|
|
||||||
from bot_api.api import Api
|
|
||||||
from bot_api.exception.service_error_code_enum import ServiceErrorCode
|
|
||||||
from bot_api.exception.service_exception import ServiceException
|
|
||||||
from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria
|
|
||||||
from bot_api.json_processor import JSONProcessor
|
|
||||||
from bot_api.logging.api_logger import ApiLogger
|
|
||||||
from bot_api.model.auth_user_dto import AuthUserDTO
|
|
||||||
from bot_api.model.reset_password_dto import ResetPasswordDTO
|
|
||||||
from bot_api.model.token_dto import TokenDTO
|
|
||||||
from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO
|
|
||||||
from bot_api.route.route import Route
|
|
||||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
|
||||||
|
|
||||||
|
|
||||||
class AuthController:
|
|
||||||
BasePath = '/api/auth'
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
config: ConfigurationABC,
|
|
||||||
env: ApplicationEnvironmentABC,
|
|
||||||
logger: ApiLogger,
|
|
||||||
t: TranslatePipe,
|
|
||||||
api: Api,
|
|
||||||
mail_settings: EMailClientSettings,
|
|
||||||
mailer: EMailClientABC,
|
|
||||||
auth_service: AuthServiceABC
|
|
||||||
):
|
|
||||||
self._config = config
|
|
||||||
self._env = env
|
|
||||||
self._logger = logger
|
|
||||||
self._t = t
|
|
||||||
self._api = api
|
|
||||||
self._mail_settings = mail_settings
|
|
||||||
self._mailer = mailer
|
|
||||||
self._auth_service = auth_service
|
|
||||||
|
|
||||||
@Route.get(f'{BasePath}/users')
|
|
||||||
@Route.authorize(role=AuthRoleEnum.admin)
|
|
||||||
async def get_all_users(self) -> Response:
|
|
||||||
result = await self._auth_service.get_all_auth_users_async()
|
|
||||||
return jsonify(result.select(lambda x: x.to_dict()).to_list())
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/users/get/filtered')
|
|
||||||
@Route.authorize(role=AuthRoleEnum.admin)
|
|
||||||
async def get_filtered_users(self) -> Response:
|
|
||||||
dto: AuthUserSelectCriteria = JSONProcessor.process(AuthUserSelectCriteria, request.get_json(force=True, silent=True))
|
|
||||||
result = await self._auth_service.get_filtered_auth_users_async(dto)
|
|
||||||
result.result = result.result.select(lambda x: x.to_dict()).to_list()
|
|
||||||
return jsonify(result.to_dict())
|
|
||||||
|
|
||||||
@Route.get(f'{BasePath}/users/get/<email>')
|
|
||||||
@Route.authorize
|
|
||||||
async def get_user_from_email(self, email: str) -> Response:
|
|
||||||
result = await self._auth_service.get_auth_user_by_email_async(email)
|
|
||||||
return jsonify(result.to_dict())
|
|
||||||
|
|
||||||
@Route.get(f'{BasePath}/users/find/<email>')
|
|
||||||
@Route.authorize
|
|
||||||
async def find_user_from_email(self, email: str) -> Response:
|
|
||||||
result = await self._auth_service.find_auth_user_by_email_async(email)
|
|
||||||
return jsonify(result.to_dict())
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/register')
|
|
||||||
async def register(self):
|
|
||||||
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
|
|
||||||
await self._auth_service.add_auth_user_async(dto)
|
|
||||||
return '', 200
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/register-by-id/<id>')
|
|
||||||
async def register_id(self, id: str):
|
|
||||||
result = await self._auth_service.confirm_email_async(id)
|
|
||||||
return jsonify(result)
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/login')
|
|
||||||
async def login(self) -> Response:
|
|
||||||
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
|
|
||||||
result = await self._auth_service.login_async(dto)
|
|
||||||
return jsonify(result.to_dict())
|
|
||||||
|
|
||||||
@Route.get(f'{BasePath}/verify-login')
|
|
||||||
async def verify_login(self):
|
|
||||||
token = None
|
|
||||||
result = False
|
|
||||||
if 'Authorization' in request.headers:
|
|
||||||
bearer = request.headers.get('Authorization')
|
|
||||||
token = bearer.split()[1]
|
|
||||||
|
|
||||||
if token is not None:
|
|
||||||
result = self._auth_service.verify_login(token)
|
|
||||||
|
|
||||||
return jsonify(result)
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/forgot-password/<email>')
|
|
||||||
async def forgot_password(self, email: str):
|
|
||||||
await self._auth_service.forgot_password_async(email)
|
|
||||||
return '', 200
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/confirm-forgot-password/<id>')
|
|
||||||
async def confirm_forgot_password(self, id: str):
|
|
||||||
result = await self._auth_service.confirm_forgot_password_async(id)
|
|
||||||
return jsonify(result.to_dict())
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/reset-password')
|
|
||||||
async def reset_password(self):
|
|
||||||
dto: ResetPasswordDTO = JSONProcessor.process(ResetPasswordDTO, request.get_json(force=True, silent=True))
|
|
||||||
await self._auth_service.reset_password_async(dto)
|
|
||||||
return '', 200
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/update-user')
|
|
||||||
@Route.authorize
|
|
||||||
async def update_user(self):
|
|
||||||
dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True))
|
|
||||||
await self._auth_service.update_user_async(dto)
|
|
||||||
return '', 200
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/update-user-as-admin')
|
|
||||||
@Route.authorize(role=AuthRoleEnum.admin)
|
|
||||||
async def update_user_as_admin(self):
|
|
||||||
dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True))
|
|
||||||
await self._auth_service.update_user_as_admin_async(dto)
|
|
||||||
return '', 200
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/refresh')
|
|
||||||
@Route.authorize
|
|
||||||
async def refresh(self) -> Response:
|
|
||||||
dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True))
|
|
||||||
result = await self._auth_service.refresh_async(dto)
|
|
||||||
return jsonify(result.to_dict())
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/revoke')
|
|
||||||
async def revoke(self):
|
|
||||||
dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True))
|
|
||||||
await self._auth_service.revoke_async(dto)
|
|
||||||
return '', 200
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/delete-user')
|
|
||||||
@Route.authorize(role=AuthRoleEnum.admin)
|
|
||||||
async def delete_user(self):
|
|
||||||
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
|
|
||||||
await self._auth_service.delete_auth_user_async(dto)
|
|
||||||
return '', 200
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/delete-user-by-mail/<email>')
|
|
||||||
@Route.authorize(role=AuthRoleEnum.admin)
|
|
||||||
async def delete_user_by_mail(self, email: str):
|
|
||||||
await self._auth_service.delete_auth_user_by_email_async(email)
|
|
||||||
return '', 200
|
|
@ -1,99 +0,0 @@
|
|||||||
import os
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
from cpl_core.configuration import ConfigurationABC
|
|
||||||
from cpl_core.environment import ApplicationEnvironmentABC
|
|
||||||
from cpl_core.mailing import EMailClientABC, EMailClientSettings
|
|
||||||
from cpl_core.utils import CredentialManager
|
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
from flask import jsonify, Response
|
|
||||||
from flask import request, session
|
|
||||||
from requests_oauthlib import OAuth2Session
|
|
||||||
|
|
||||||
from bot_api.abc.auth_service_abc import AuthServiceABC
|
|
||||||
from bot_api.api import Api
|
|
||||||
from bot_api.configuration.discord_authentication_settings import DiscordAuthenticationSettings
|
|
||||||
from bot_api.json_processor import JSONProcessor
|
|
||||||
from bot_api.logging.api_logger import ApiLogger
|
|
||||||
from bot_api.model.auth_user_dto import AuthUserDTO
|
|
||||||
from bot_api.model.o_auth_dto import OAuthDTO
|
|
||||||
from bot_api.route.route import Route
|
|
||||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
|
||||||
|
|
||||||
# Disable SSL requirement
|
|
||||||
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
|
|
||||||
|
|
||||||
|
|
||||||
class AuthDiscordController:
|
|
||||||
BasePath = '/api/auth/discord'
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
auth_settings: DiscordAuthenticationSettings,
|
|
||||||
config: ConfigurationABC,
|
|
||||||
env: ApplicationEnvironmentABC,
|
|
||||||
logger: ApiLogger,
|
|
||||||
bot: DiscordBotServiceABC,
|
|
||||||
t: TranslatePipe,
|
|
||||||
api: Api,
|
|
||||||
mail_settings: EMailClientSettings,
|
|
||||||
mailer: EMailClientABC,
|
|
||||||
auth_service: AuthServiceABC
|
|
||||||
):
|
|
||||||
self._auth_settings = auth_settings
|
|
||||||
self._config = config
|
|
||||||
self._env = env
|
|
||||||
self._logger = logger
|
|
||||||
self._bot = bot
|
|
||||||
self._t = t
|
|
||||||
self._api = api
|
|
||||||
self._mail_settings = mail_settings
|
|
||||||
self._mailer = mailer
|
|
||||||
self._auth_service = auth_service
|
|
||||||
|
|
||||||
def _get_user_from_discord_response(self) -> dict:
|
|
||||||
discord = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, state=request.args.get('state'), scope=self._auth_settings.scope)
|
|
||||||
token = discord.fetch_token(
|
|
||||||
self._auth_settings.token_url,
|
|
||||||
client_secret=CredentialManager.decrypt(self._auth_settings.client_secret),
|
|
||||||
authorization_response=request.url,
|
|
||||||
)
|
|
||||||
discord = OAuth2Session(self._bot.user.id, token=token)
|
|
||||||
return discord.get('https://discordapp.com/api' + '/users/@me').json()
|
|
||||||
|
|
||||||
@Route.get(f'{BasePath}/get-url')
|
|
||||||
async def get_url(self):
|
|
||||||
oauth = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, scope=self._auth_settings.scope)
|
|
||||||
login_url, state = oauth.authorization_url(self._auth_settings.auth_url)
|
|
||||||
return jsonify({'loginUrl': login_url})
|
|
||||||
|
|
||||||
@Route.get(f'{BasePath}/create-user')
|
|
||||||
async def discord_create_user(self) -> Response:
|
|
||||||
response = self._get_user_from_discord_response()
|
|
||||||
result = await self._auth_service.add_auth_user_by_discord_async(AuthUserDTO(
|
|
||||||
0,
|
|
||||||
response['username'],
|
|
||||||
response['discriminator'],
|
|
||||||
response['email'],
|
|
||||||
str(uuid.uuid4()),
|
|
||||||
None,
|
|
||||||
AuthRoleEnum.normal
|
|
||||||
), response['id'])
|
|
||||||
return jsonify(result.to_dict())
|
|
||||||
|
|
||||||
@Route.get(f'{BasePath}/login')
|
|
||||||
async def discord_login(self) -> Response:
|
|
||||||
response = self._get_user_from_discord_response()
|
|
||||||
dto = AuthUserDTO(
|
|
||||||
0,
|
|
||||||
response['username'],
|
|
||||||
response['discriminator'],
|
|
||||||
response['email'],
|
|
||||||
str(uuid.uuid4()),
|
|
||||||
None,
|
|
||||||
AuthRoleEnum.normal
|
|
||||||
)
|
|
||||||
|
|
||||||
result = await self._auth_service.login_discord_async(dto)
|
|
||||||
return jsonify(result.to_dict())
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'bot_api.controller.discord'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,65 +0,0 @@
|
|||||||
from cpl_core.configuration import ConfigurationABC
|
|
||||||
from cpl_core.environment import ApplicationEnvironmentABC
|
|
||||||
from cpl_core.mailing import EMailClientABC, EMailClientSettings
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
from flask import Response, jsonify, request
|
|
||||||
|
|
||||||
from bot_api.api import Api
|
|
||||||
from bot_api.filter.discord.server_select_criteria import ServerSelectCriteria
|
|
||||||
from bot_api.json_processor import JSONProcessor
|
|
||||||
from bot_api.logging.api_logger import ApiLogger
|
|
||||||
from bot_api.route.route import Route
|
|
||||||
from bot_api.service.discord_service import DiscordService
|
|
||||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
|
||||||
|
|
||||||
|
|
||||||
class ServerController:
|
|
||||||
BasePath = f'/api/discord/server'
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
config: ConfigurationABC,
|
|
||||||
env: ApplicationEnvironmentABC,
|
|
||||||
logger: ApiLogger,
|
|
||||||
t: TranslatePipe,
|
|
||||||
api: Api,
|
|
||||||
mail_settings: EMailClientSettings,
|
|
||||||
mailer: EMailClientABC,
|
|
||||||
discord_service: DiscordService
|
|
||||||
):
|
|
||||||
self._config = config
|
|
||||||
self._env = env
|
|
||||||
self._logger = logger
|
|
||||||
self._t = t
|
|
||||||
self._api = api
|
|
||||||
self._mail_settings = mail_settings
|
|
||||||
self._mailer = mailer
|
|
||||||
self._discord_service = discord_service
|
|
||||||
|
|
||||||
@Route.get(f'{BasePath}/get/servers')
|
|
||||||
@Route.authorize(role=AuthRoleEnum.admin)
|
|
||||||
async def get_all_servers(self) -> Response:
|
|
||||||
result = await self._discord_service.get_all_servers()
|
|
||||||
result = result.select(lambda x: x.to_dict()).to_list()
|
|
||||||
return jsonify(result)
|
|
||||||
|
|
||||||
@Route.get(f'{BasePath}/get/servers-by-user')
|
|
||||||
@Route.authorize
|
|
||||||
async def get_all_servers_by_user(self) -> Response:
|
|
||||||
result = await self._discord_service.get_all_servers_by_user()
|
|
||||||
result = result.select(lambda x: x.to_dict()).to_list()
|
|
||||||
return jsonify(result)
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/get/filtered')
|
|
||||||
@Route.authorize
|
|
||||||
async def get_filtered_servers(self) -> Response:
|
|
||||||
dto: ServerSelectCriteria = JSONProcessor.process(ServerSelectCriteria, request.get_json(force=True, silent=True))
|
|
||||||
result = await self._discord_service.get_filtered_servers_async(dto)
|
|
||||||
result.result = result.result.select(lambda x: x.to_dict()).to_list()
|
|
||||||
return jsonify(result.to_dict())
|
|
||||||
|
|
||||||
@Route.get(f'{BasePath}/get/<id>')
|
|
||||||
@Route.authorize
|
|
||||||
async def get_server_by_id(self, id: int) -> Response:
|
|
||||||
result = await self._discord_service.get_server_by_id_async(id).to_list()
|
|
||||||
return jsonify(result.to_dict())
|
|
@ -1,78 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from cpl_core.configuration import ConfigurationABC
|
|
||||||
from cpl_core.environment import ApplicationEnvironmentABC
|
|
||||||
from cpl_core.mailing import EMail, EMailClientABC, EMailClientSettings
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
from flask import jsonify
|
|
||||||
|
|
||||||
from bot_api.api import Api
|
|
||||||
from bot_api.configuration.authentication_settings import AuthenticationSettings
|
|
||||||
from bot_api.logging.api_logger import ApiLogger
|
|
||||||
from bot_api.model.settings_dto import SettingsDTO
|
|
||||||
from bot_api.model.version_dto import VersionDTO
|
|
||||||
from bot_api.route.route import Route
|
|
||||||
|
|
||||||
|
|
||||||
class GuiController:
|
|
||||||
BasePath = f'/api/gui'
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
config: ConfigurationABC,
|
|
||||||
env: ApplicationEnvironmentABC,
|
|
||||||
logger: ApiLogger,
|
|
||||||
t: TranslatePipe,
|
|
||||||
api: Api,
|
|
||||||
mail_settings: EMailClientSettings,
|
|
||||||
mailer: EMailClientABC,
|
|
||||||
auth_settings: AuthenticationSettings
|
|
||||||
):
|
|
||||||
self._config = config
|
|
||||||
self._env = env
|
|
||||||
self._logger = logger
|
|
||||||
self._t = t
|
|
||||||
self._api = api
|
|
||||||
self._mail_settings = mail_settings
|
|
||||||
self._mailer = mailer
|
|
||||||
self._auth_settings = auth_settings
|
|
||||||
|
|
||||||
@Route.get(f'{BasePath}/api-version')
|
|
||||||
async def api_version(self):
|
|
||||||
import bot_api
|
|
||||||
version = bot_api.version_info
|
|
||||||
return VersionDTO(version.major, version.minor, version.micro).to_dict()
|
|
||||||
|
|
||||||
@Route.get(f'{BasePath}/settings')
|
|
||||||
@Route.authorize
|
|
||||||
async def settings(self):
|
|
||||||
import bot_api
|
|
||||||
version = bot_api.version_info
|
|
||||||
|
|
||||||
return jsonify(SettingsDTO(
|
|
||||||
'',
|
|
||||||
VersionDTO(version.major, version.minor, version.micro),
|
|
||||||
os.path.abspath(os.path.join(self._env.working_directory, 'config')),
|
|
||||||
'/',
|
|
||||||
'/',
|
|
||||||
self._auth_settings.token_expire_time,
|
|
||||||
self._auth_settings.refresh_token_expire_time,
|
|
||||||
self._mail_settings.user_name,
|
|
||||||
self._mail_settings.port,
|
|
||||||
self._mail_settings.host,
|
|
||||||
self._mail_settings.user_name,
|
|
||||||
self._mail_settings.user_name,
|
|
||||||
).to_dict())
|
|
||||||
|
|
||||||
@Route.post(f'{BasePath}/send-test-mail/<email>')
|
|
||||||
@Route.authorize
|
|
||||||
async def send_test_mail(self, email: str):
|
|
||||||
mail = EMail()
|
|
||||||
mail.add_header('Mime-Version: 1.0')
|
|
||||||
mail.add_header('Content-Type: text/plain; charset=utf-8')
|
|
||||||
mail.add_header('Content-Transfer-Encoding: quoted-printable')
|
|
||||||
mail.add_receiver(email)
|
|
||||||
mail.subject = self._t.transform('api.api.test_mail.subject')
|
|
||||||
mail.body = self._t.transform('api.api.test_mail.message').format(self._env.host_name, self._env.environment_name)
|
|
||||||
self._mailer.send_mail(mail)
|
|
||||||
return '', 200
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'bot_api.event'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,13 +0,0 @@
|
|||||||
from cpl_discord.events import OnReadyABC
|
|
||||||
|
|
||||||
from bot_api.api_thread import ApiThread
|
|
||||||
|
|
||||||
|
|
||||||
class BotApiOnReadyEvent(OnReadyABC):
|
|
||||||
|
|
||||||
def __init__(self, api: ApiThread):
|
|
||||||
OnReadyABC.__init__(self)
|
|
||||||
self._api = api
|
|
||||||
|
|
||||||
async def on_ready(self):
|
|
||||||
self._api.start()
|
|
@ -1,24 +0,0 @@
|
|||||||
from enum import Enum
|
|
||||||
|
|
||||||
from werkzeug.exceptions import Unauthorized
|
|
||||||
|
|
||||||
|
|
||||||
class ServiceErrorCode(Enum):
|
|
||||||
|
|
||||||
Unknown = 0
|
|
||||||
|
|
||||||
InvalidDependencies = 1
|
|
||||||
InvalidData = 2
|
|
||||||
NotFound = 3
|
|
||||||
DataAlreadyExists = 4
|
|
||||||
UnableToAdd = 5
|
|
||||||
UnableToDelete = 6
|
|
||||||
|
|
||||||
InvalidUser = 7
|
|
||||||
|
|
||||||
ConnectionFailed = 8
|
|
||||||
Timeout = 9
|
|
||||||
MailError = 10
|
|
||||||
|
|
||||||
Unauthorized = 11
|
|
||||||
Forbidden = 12
|
|
@ -1,13 +0,0 @@
|
|||||||
from bot_api.exception.service_error_code_enum import ServiceErrorCode
|
|
||||||
|
|
||||||
|
|
||||||
class ServiceException(Exception):
|
|
||||||
|
|
||||||
def __init__(self, error_code: ServiceErrorCode, message: str, *args):
|
|
||||||
Exception.__init__(self, *args)
|
|
||||||
|
|
||||||
self.error_code = error_code
|
|
||||||
self.message = message
|
|
||||||
|
|
||||||
def get_detailed_message(self) -> str:
|
|
||||||
return f'ServiceException - ErrorCode: {self.error_code} - ErrorMessage: {self.message}'
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'bot_api.filter'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,23 +0,0 @@
|
|||||||
from bot_api.abc.select_criteria_abc import SelectCriteriaABC
|
|
||||||
|
|
||||||
|
|
||||||
class AuthUserSelectCriteria(SelectCriteriaABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
page_index: int,
|
|
||||||
page_size: int,
|
|
||||||
sort_direction: str,
|
|
||||||
sort_column: str,
|
|
||||||
|
|
||||||
first_name: str,
|
|
||||||
last_name: str,
|
|
||||||
email: str,
|
|
||||||
auth_role: int
|
|
||||||
):
|
|
||||||
SelectCriteriaABC.__init__(self, page_index, page_size, sort_direction, sort_column)
|
|
||||||
|
|
||||||
self.first_name = first_name
|
|
||||||
self.last_name = last_name
|
|
||||||
self.email = email
|
|
||||||
self.auth_role = auth_role
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'bot_api.filter.discord'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,17 +0,0 @@
|
|||||||
from bot_api.abc.select_criteria_abc import SelectCriteriaABC
|
|
||||||
|
|
||||||
|
|
||||||
class ServerSelectCriteria(SelectCriteriaABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
page_index: int,
|
|
||||||
page_size: int,
|
|
||||||
sort_direction: str,
|
|
||||||
sort_column: str,
|
|
||||||
|
|
||||||
name: str,
|
|
||||||
):
|
|
||||||
SelectCriteriaABC.__init__(self, page_index, page_size, sort_direction, sort_column)
|
|
||||||
|
|
||||||
self.name = name
|
|
@ -1,43 +0,0 @@
|
|||||||
import enum
|
|
||||||
from inspect import signature, Parameter
|
|
||||||
|
|
||||||
from cpl_core.utils import String
|
|
||||||
|
|
||||||
|
|
||||||
class JSONProcessor:
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def process(_t: type, values: dict) -> object:
|
|
||||||
args = []
|
|
||||||
|
|
||||||
sig = signature(_t.__init__)
|
|
||||||
for param in sig.parameters.items():
|
|
||||||
parameter = param[1]
|
|
||||||
if parameter.name == 'self' or parameter.annotation == Parameter.empty:
|
|
||||||
continue
|
|
||||||
|
|
||||||
name = String.convert_to_camel_case(parameter.name)
|
|
||||||
name = name.replace('Dto', 'DTO')
|
|
||||||
name_first_lower = String.first_to_lower(name)
|
|
||||||
if name in values or name_first_lower in values:
|
|
||||||
value = ''
|
|
||||||
if name in values:
|
|
||||||
value = values[name]
|
|
||||||
else:
|
|
||||||
value = values[name_first_lower]
|
|
||||||
|
|
||||||
if isinstance(value, dict):
|
|
||||||
value = JSONProcessor.process(parameter.annotation, value)
|
|
||||||
|
|
||||||
if issubclass(parameter.annotation, enum.Enum):
|
|
||||||
value = parameter.annotation(value)
|
|
||||||
|
|
||||||
args.append(value)
|
|
||||||
|
|
||||||
elif parameter.default != Parameter.empty:
|
|
||||||
args.append(parameter.default)
|
|
||||||
|
|
||||||
else:
|
|
||||||
args.append(None)
|
|
||||||
|
|
||||||
return _t(*args)
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'bot_api.logging'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,11 +0,0 @@
|
|||||||
from cpl_core.configuration import ConfigurationABC
|
|
||||||
from cpl_core.environment import ApplicationEnvironmentABC
|
|
||||||
from cpl_core.time import TimeFormatSettings
|
|
||||||
|
|
||||||
from bot_core.abc.custom_file_logger_abc import CustomFileLoggerABC
|
|
||||||
|
|
||||||
|
|
||||||
class ApiLogger(CustomFileLoggerABC):
|
|
||||||
|
|
||||||
def __init__(self, config: ConfigurationABC, time_format: TimeFormatSettings, env: ApplicationEnvironmentABC):
|
|
||||||
CustomFileLoggerABC.__init__(self, 'Api', config, time_format, env)
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'bot_api.model'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,99 +0,0 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
from bot_api.abc.dto_abc import DtoABC
|
|
||||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
|
||||||
|
|
||||||
|
|
||||||
class AuthUserDTO(DtoABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
id: int = None,
|
|
||||||
first_name: str = None,
|
|
||||||
last_name: str = None,
|
|
||||||
email: str = None,
|
|
||||||
password: str = None,
|
|
||||||
confirmation_id: Optional[str] = None,
|
|
||||||
auth_role: AuthRoleEnum = None,
|
|
||||||
):
|
|
||||||
DtoABC.__init__(self)
|
|
||||||
|
|
||||||
self._id = id
|
|
||||||
self._first_name = first_name
|
|
||||||
self._last_name = last_name
|
|
||||||
self._email = email
|
|
||||||
self._password = password
|
|
||||||
self._is_confirmed = confirmation_id is None
|
|
||||||
self._auth_role = auth_role
|
|
||||||
|
|
||||||
@property
|
|
||||||
def id(self) -> int:
|
|
||||||
return self._id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def first_name(self) -> str:
|
|
||||||
return self._first_name
|
|
||||||
|
|
||||||
@first_name.setter
|
|
||||||
def first_name(self, value: str):
|
|
||||||
self._first_name = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def last_name(self) -> str:
|
|
||||||
return self._last_name
|
|
||||||
|
|
||||||
@last_name.setter
|
|
||||||
def last_name(self, value: str):
|
|
||||||
self._last_name = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def email(self) -> str:
|
|
||||||
return self._email
|
|
||||||
|
|
||||||
@email.setter
|
|
||||||
def email(self, value: str):
|
|
||||||
self._email = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def password(self) -> str:
|
|
||||||
return self._password
|
|
||||||
|
|
||||||
@password.setter
|
|
||||||
def password(self, value: str):
|
|
||||||
self._password = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_confirmed(self) -> Optional[str]:
|
|
||||||
return self._is_confirmed
|
|
||||||
|
|
||||||
@is_confirmed.setter
|
|
||||||
def is_confirmed(self, value: Optional[str]):
|
|
||||||
self._is_confirmed = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def auth_role(self) -> AuthRoleEnum:
|
|
||||||
return self._auth_role
|
|
||||||
|
|
||||||
@auth_role.setter
|
|
||||||
def auth_role(self, value: AuthRoleEnum):
|
|
||||||
self._auth_role = value
|
|
||||||
|
|
||||||
def from_dict(self, values: dict):
|
|
||||||
self._id = values['id']
|
|
||||||
self._first_name = values['firstName']
|
|
||||||
self._last_name = values['lastName']
|
|
||||||
self._email = values['email']
|
|
||||||
self._password = values['password']
|
|
||||||
self._is_confirmed = values['isConfirmed']
|
|
||||||
self._auth_role = AuthRoleEnum(values['authRole'])
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
return {
|
|
||||||
'id': self._id,
|
|
||||||
'firstName': self._first_name,
|
|
||||||
'lastName': self._last_name,
|
|
||||||
'email': self._email,
|
|
||||||
'password': self._password,
|
|
||||||
'isConfirmed': self._is_confirmed,
|
|
||||||
'authRole': self._auth_role.value,
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
from bot_api.abc.dto_abc import DtoABC
|
|
||||||
from bot_data.filtered_result import FilteredResult
|
|
||||||
|
|
||||||
|
|
||||||
class AuthUserFilteredResultDTO(DtoABC, FilteredResult):
|
|
||||||
|
|
||||||
def __init__(self, result: List = None, total_count: int = 0):
|
|
||||||
DtoABC.__init__(self)
|
|
||||||
FilteredResult.__init__(self, result, total_count)
|
|
||||||
|
|
||||||
def from_dict(self, values: dict):
|
|
||||||
self._result = values['users']
|
|
||||||
self._total_count = values['totalCount']
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
return {
|
|
||||||
'users': self.result,
|
|
||||||
'totalCount': self.total_count
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'bot_api.model.discord'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,58 +0,0 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
from bot_api.abc.dto_abc import DtoABC
|
|
||||||
|
|
||||||
|
|
||||||
class ServerDTO(DtoABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
server_id: int,
|
|
||||||
discord_id: int,
|
|
||||||
name: str,
|
|
||||||
member_count: int,
|
|
||||||
icon_url: Optional[str]
|
|
||||||
|
|
||||||
):
|
|
||||||
DtoABC.__init__(self)
|
|
||||||
|
|
||||||
self._server_id = server_id
|
|
||||||
self._discord_id = discord_id
|
|
||||||
self._name = name
|
|
||||||
self._member_count = member_count
|
|
||||||
self._icon_url = icon_url
|
|
||||||
|
|
||||||
@property
|
|
||||||
def server_id(self) -> int:
|
|
||||||
return self._server_id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def discord_id(self) -> int:
|
|
||||||
return self._discord_id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self) -> str:
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def member_count(self) -> int:
|
|
||||||
return self._member_count
|
|
||||||
|
|
||||||
@property
|
|
||||||
def icon_url(self) -> Optional[str]:
|
|
||||||
return self._icon_url
|
|
||||||
|
|
||||||
def from_dict(self, values: dict):
|
|
||||||
self._server_id = int(values['serverId'])
|
|
||||||
self._discord_id = int(values['discordId'])
|
|
||||||
self._name = values['name']
|
|
||||||
self._icon_url = values['iconURL']
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
return {
|
|
||||||
'serverId': self._server_id,
|
|
||||||
'discordId': self._discord_id,
|
|
||||||
'name': self._name,
|
|
||||||
'memberCount': self._member_count,
|
|
||||||
'iconURL': self._icon_url,
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
from bot_api.abc.dto_abc import DtoABC
|
|
||||||
from bot_data.filtered_result import FilteredResult
|
|
||||||
|
|
||||||
|
|
||||||
class ServerFilteredResultDTO(DtoABC, FilteredResult):
|
|
||||||
|
|
||||||
def __init__(self, result: List = None, total_count: int = 0):
|
|
||||||
DtoABC.__init__(self)
|
|
||||||
FilteredResult.__init__(self, result, total_count)
|
|
||||||
|
|
||||||
def from_dict(self, values: dict):
|
|
||||||
self._result = values['servers']
|
|
||||||
self._total_count = values['totalCount']
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
return {
|
|
||||||
'servers': self.result,
|
|
||||||
'totalCount': self.total_count
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
import traceback
|
|
||||||
|
|
||||||
from cpl_core.console import Console
|
|
||||||
|
|
||||||
from bot_api.abc.dto_abc import DtoABC
|
|
||||||
|
|
||||||
|
|
||||||
class EMailStringDTO(DtoABC):
|
|
||||||
|
|
||||||
def __init__(self, email: str):
|
|
||||||
DtoABC.__init__(self)
|
|
||||||
|
|
||||||
self._email = email
|
|
||||||
|
|
||||||
def from_dict(self, values: dict):
|
|
||||||
self._email = values['email']
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
return {
|
|
||||||
'email': self._email
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
class ErrorDTO(DtoABC):
|
|
||||||
|
|
||||||
def __init__(self, error_code: Optional[ServiceErrorCode], message: str):
|
|
||||||
DtoABC.__init__(self)
|
|
||||||
|
|
||||||
self._error_code = ServiceErrorCode.Unknown if error_code is None else error_code
|
|
||||||
self._message = message
|
|
||||||
|
|
||||||
@property
|
|
||||||
def error_code(self) -> ServiceErrorCode:
|
|
||||||
return self._error_code
|
|
||||||
|
|
||||||
@property
|
|
||||||
def message(self) -> str:
|
|
||||||
return self._message
|
|
||||||
|
|
||||||
def from_dict(self, values: dict):
|
|
||||||
self._error_code = values['ErrorCode']
|
|
||||||
self._message = values['Message']
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
return {
|
|
||||||
'errorCode': int(self._error_code.value),
|
|
||||||
'message': self._message
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
from bot_api.abc.dto_abc import DtoABC
|
|
||||||
from bot_api.model.auth_user_dto import AuthUserDTO
|
|
||||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
|
||||||
|
|
||||||
|
|
||||||
class OAuthDTO(DtoABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
user: AuthUserDTO,
|
|
||||||
o_auth_id: Optional[str],
|
|
||||||
):
|
|
||||||
DtoABC.__init__(self)
|
|
||||||
|
|
||||||
self._user = user
|
|
||||||
self._oauth_id = o_auth_id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def user(self) -> AuthUserDTO:
|
|
||||||
return self._user
|
|
||||||
|
|
||||||
@user.setter
|
|
||||||
def user(self, value: AuthUserDTO):
|
|
||||||
self._user = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def oauth_id(self) -> Optional[str]:
|
|
||||||
return self._oauth_id
|
|
||||||
|
|
||||||
@oauth_id.setter
|
|
||||||
def oauth_id(self, value: Optional[str]):
|
|
||||||
self._oauth_id = value
|
|
||||||
|
|
||||||
def from_dict(self, values: dict):
|
|
||||||
self._user = AuthUserDTO().from_dict(values['user'])
|
|
||||||
self._oauth_id = values['oAuthId']
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
return {
|
|
||||||
'user': self._user.to_dict(),
|
|
||||||
'oAuthId': self._oauth_id
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
import traceback
|
|
||||||
|
|
||||||
from cpl_core.console import Console
|
|
||||||
|
|
||||||
from bot_api.abc.dto_abc import DtoABC
|
|
||||||
|
|
||||||
|
|
||||||
class ResetPasswordDTO(DtoABC):
|
|
||||||
|
|
||||||
def __init__(self, id: str, password: str):
|
|
||||||
DtoABC.__init__(self)
|
|
||||||
|
|
||||||
self._id = id
|
|
||||||
self._password = password
|
|
||||||
|
|
||||||
@property
|
|
||||||
def id(self) -> str:
|
|
||||||
return self._id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def password(self) -> str:
|
|
||||||
return self._password
|
|
||||||
|
|
||||||
def from_dict(self, values: dict):
|
|
||||||
self._id = values['id']
|
|
||||||
self._password = values['password']
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
return {
|
|
||||||
'id': self._id,
|
|
||||||
'password': self._password
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
from bot_api.abc.dto_abc import DtoABC
|
|
||||||
from bot_api.model.version_dto import VersionDTO
|
|
||||||
|
|
||||||
|
|
||||||
class SettingsDTO(DtoABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
web_version: str,
|
|
||||||
api_version: VersionDTO,
|
|
||||||
config_path: str,
|
|
||||||
web_base_url: str,
|
|
||||||
api_base_url: str,
|
|
||||||
token_expire_time: int,
|
|
||||||
refresh_token_expire_time: int,
|
|
||||||
mail_user: str,
|
|
||||||
mail_port: int,
|
|
||||||
mail_host: str,
|
|
||||||
mail_transceiver: str,
|
|
||||||
mail_transceiver_address: str,
|
|
||||||
):
|
|
||||||
DtoABC.__init__(self)
|
|
||||||
|
|
||||||
self._web_version = web_version
|
|
||||||
self._api_version = api_version
|
|
||||||
self._config_path = config_path
|
|
||||||
self._web_base_url = web_base_url
|
|
||||||
self._api_base_url = api_base_url
|
|
||||||
|
|
||||||
self._token_expire_time = token_expire_time
|
|
||||||
self._refresh_token_expire_time = refresh_token_expire_time
|
|
||||||
|
|
||||||
self._mail_user = mail_user
|
|
||||||
self._mail_port = mail_port
|
|
||||||
self._mail_host = mail_host
|
|
||||||
self._mail_transceiver = mail_transceiver
|
|
||||||
self._mail_transceiver_address = mail_transceiver_address
|
|
||||||
|
|
||||||
def from_dict(self, values: dict):
|
|
||||||
self._web_version = values['webVersion']
|
|
||||||
self._api_version.from_dict(values['apiVersion'])
|
|
||||||
self._config_path = values['configPath']
|
|
||||||
self._web_base_url = values['webBaseURL']
|
|
||||||
self._api_base_url = values['apiBaseURL']
|
|
||||||
self._token_expire_time = values['tokenExpireTime']
|
|
||||||
self._refresh_token_expire_time = values['refreshTokenExpireTime']
|
|
||||||
self._mail_user = values['mailUser']
|
|
||||||
self._mail_port = values['mailPort']
|
|
||||||
self._mail_host = values['mailHost']
|
|
||||||
self._mail_transceiver = values['mailTransceiver']
|
|
||||||
self._mail_transceiver_address = values['mailTransceiverAddress']
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
return {
|
|
||||||
'webVersion': self._web_version,
|
|
||||||
'apiVersion': self._api_version.str,
|
|
||||||
'configPath': self._config_path,
|
|
||||||
'webBaseURL': self._web_base_url,
|
|
||||||
'apiBaseURL': self._api_base_url,
|
|
||||||
'tokenExpireTime': self._token_expire_time,
|
|
||||||
'refreshTokenExpireTime': self._refresh_token_expire_time,
|
|
||||||
'mailUser': self._mail_user,
|
|
||||||
'mailPort': self._mail_port,
|
|
||||||
'mailHost': self._mail_host,
|
|
||||||
'mailTransceiver': self._mail_transceiver,
|
|
||||||
'mailTransceiverAddress': self._mail_transceiver_address,
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
import traceback
|
|
||||||
|
|
||||||
from cpl_core.console import Console
|
|
||||||
|
|
||||||
from bot_api.abc.dto_abc import DtoABC
|
|
||||||
|
|
||||||
|
|
||||||
class TokenDTO(DtoABC):
|
|
||||||
|
|
||||||
def __init__(self, token: str, refresh_token: str):
|
|
||||||
DtoABC.__init__(self)
|
|
||||||
|
|
||||||
self._token = token
|
|
||||||
self._refresh_token = refresh_token
|
|
||||||
|
|
||||||
@property
|
|
||||||
def token(self) -> str:
|
|
||||||
return self._token
|
|
||||||
|
|
||||||
@property
|
|
||||||
def refresh_token(self) -> str:
|
|
||||||
return self._refresh_token
|
|
||||||
|
|
||||||
def from_dict(self, values: dict):
|
|
||||||
self._token = values['token']
|
|
||||||
self._refresh_token = values['refreshToken']
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
return {
|
|
||||||
'token': self._token,
|
|
||||||
'refreshToken': self._refresh_token
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
import traceback
|
|
||||||
|
|
||||||
from cpl_core.console import Console
|
|
||||||
|
|
||||||
from bot_api.abc.dto_abc import DtoABC
|
|
||||||
from bot_api.model.auth_user_dto import AuthUserDTO
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateAuthUserDTO(DtoABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
auth_user_dto: AuthUserDTO,
|
|
||||||
new_auth_user_dto: AuthUserDTO,
|
|
||||||
change_password: bool = False
|
|
||||||
):
|
|
||||||
DtoABC.__init__(self)
|
|
||||||
|
|
||||||
self._auth_user = auth_user_dto
|
|
||||||
self._new_auth_user = new_auth_user_dto
|
|
||||||
self._change_password = change_password
|
|
||||||
|
|
||||||
@property
|
|
||||||
def auth_user(self) -> AuthUserDTO:
|
|
||||||
return self._auth_user
|
|
||||||
|
|
||||||
@property
|
|
||||||
def new_auth_user(self) -> AuthUserDTO:
|
|
||||||
return self._new_auth_user
|
|
||||||
|
|
||||||
@property
|
|
||||||
def change_password(self) -> bool:
|
|
||||||
return self._change_password
|
|
||||||
|
|
||||||
def from_dict(self, values: dict):
|
|
||||||
self._auth_user = AuthUserDTO().from_dict(values['authUser'])
|
|
||||||
self._new_auth_user = AuthUserDTO().from_dict(values['newAuthUser'])
|
|
||||||
self._change_password = False if 'changePassword' not in values else bool(values['changePassword'])
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
return {
|
|
||||||
'authUser': self._auth_user,
|
|
||||||
'newAuthUser': self._new_auth_user,
|
|
||||||
'changePassword': self._change_password
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
import traceback
|
|
||||||
|
|
||||||
from cpl_core.console import Console
|
|
||||||
|
|
||||||
from bot_api.abc.dto_abc import DtoABC
|
|
||||||
|
|
||||||
|
|
||||||
class VersionDTO(DtoABC):
|
|
||||||
|
|
||||||
def __init__(self, major: str = None, minor: str = None, micro: str = None):
|
|
||||||
DtoABC.__init__(self)
|
|
||||||
|
|
||||||
self._major = major
|
|
||||||
self._minor = minor
|
|
||||||
self._micro = micro
|
|
||||||
|
|
||||||
@property
|
|
||||||
def major(self) -> str:
|
|
||||||
return self._major
|
|
||||||
|
|
||||||
@property
|
|
||||||
def minor(self) -> str:
|
|
||||||
return self._minor
|
|
||||||
|
|
||||||
@property
|
|
||||||
def micro(self) -> str:
|
|
||||||
return self._micro
|
|
||||||
|
|
||||||
@property
|
|
||||||
def str(self) -> str:
|
|
||||||
return f'{self._major}.{self._minor}.{self._micro}'
|
|
||||||
|
|
||||||
def from_dict(self, values: dict):
|
|
||||||
self._major = values['major']
|
|
||||||
self._minor = values['minor']
|
|
||||||
self._micro = values['micro']
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
return {
|
|
||||||
'major': self._major,
|
|
||||||
'minor': self._minor,
|
|
||||||
'micro': self._micro,
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'bot_api.route'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,103 +0,0 @@
|
|||||||
import functools
|
|
||||||
from functools import wraps
|
|
||||||
from typing import Optional, Callable
|
|
||||||
|
|
||||||
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_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
|
|
||||||
|
|
||||||
|
|
||||||
class Route:
|
|
||||||
registered_routes = {}
|
|
||||||
|
|
||||||
_auth_users: Optional[AuthUserRepositoryABC] = None
|
|
||||||
_auth: Optional[AuthServiceABC] = None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def init_authorize(cls, auth_users: AuthUserRepositoryABC, auth: AuthServiceABC):
|
|
||||||
cls._auth_users = auth_users
|
|
||||||
cls._auth = auth
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def authorize(cls, f: Callable = None, role: AuthRoleEnum = None):
|
|
||||||
if f is None:
|
|
||||||
return functools.partial(cls.authorize, role=role)
|
|
||||||
|
|
||||||
@wraps(f)
|
|
||||||
async def decorator(*args, **kwargs):
|
|
||||||
token = None
|
|
||||||
if 'Authorization' in request.headers:
|
|
||||||
bearer = request.headers.get('Authorization')
|
|
||||||
token = bearer.split()[1]
|
|
||||||
|
|
||||||
if token is None:
|
|
||||||
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token not set')
|
|
||||||
error = ErrorDTO(ex.error_code, ex.message)
|
|
||||||
return jsonify(error.to_dict()), 401
|
|
||||||
|
|
||||||
if cls._auth_users is None or cls._auth is None:
|
|
||||||
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Authorize is not initialized')
|
|
||||||
error = ErrorDTO(ex.error_code, ex.message)
|
|
||||||
return jsonify(error.to_dict()), 401
|
|
||||||
|
|
||||||
if not cls._auth.verify_login(token):
|
|
||||||
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token expired')
|
|
||||||
error = ErrorDTO(ex.error_code, ex.message)
|
|
||||||
return jsonify(error.to_dict()), 401
|
|
||||||
|
|
||||||
token = cls._auth.decode_token(token)
|
|
||||||
if token is None or 'email' not in token:
|
|
||||||
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token invalid')
|
|
||||||
error = ErrorDTO(ex.error_code, ex.message)
|
|
||||||
return jsonify(error.to_dict()), 401
|
|
||||||
|
|
||||||
user = cls._auth_users.get_auth_user_by_email(token['email'])
|
|
||||||
if user is None:
|
|
||||||
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token invalid')
|
|
||||||
error = ErrorDTO(ex.error_code, ex.message)
|
|
||||||
return jsonify(error.to_dict()), 401
|
|
||||||
|
|
||||||
if role is not None and user.auth_role.value < role.value:
|
|
||||||
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Role {role} required')
|
|
||||||
error = ErrorDTO(ex.error_code, ex.message)
|
|
||||||
return jsonify(error.to_dict()), 403
|
|
||||||
|
|
||||||
return await f(*args, **kwargs)
|
|
||||||
|
|
||||||
return decorator
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def route(cls, path=None, **kwargs):
|
|
||||||
# simple decorator for class based views
|
|
||||||
def inner(fn):
|
|
||||||
cross_origin(fn)
|
|
||||||
cls.registered_routes[path] = (fn, kwargs)
|
|
||||||
return fn
|
|
||||||
|
|
||||||
return inner
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get(cls, path=None, **kwargs):
|
|
||||||
return cls.route(path, methods=['GET'], **kwargs)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def post(cls, path=None, **kwargs):
|
|
||||||
return cls.route(path, methods=['POST'], **kwargs)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def head(cls, path=None, **kwargs):
|
|
||||||
return cls.route(path, methods=['HEAD'], **kwargs)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def put(cls, path=None, **kwargs):
|
|
||||||
return cls.route(path, methods=['PUT'], **kwargs)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def delete(cls, path=None, **kwargs):
|
|
||||||
return cls.route(path, methods=['DELETE'], **kwargs)
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'bot_api.service'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,555 +0,0 @@
|
|||||||
import hashlib
|
|
||||||
import re
|
|
||||||
import textwrap
|
|
||||||
import uuid
|
|
||||||
from datetime import datetime, timedelta, timezone
|
|
||||||
from threading import Thread
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import jwt
|
|
||||||
from cpl_core.database.context import DatabaseContextABC
|
|
||||||
from cpl_core.environment import ApplicationEnvironmentABC
|
|
||||||
from cpl_core.mailing import EMail, EMailClientABC
|
|
||||||
from cpl_core.utils import CredentialManager
|
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
|
||||||
from cpl_query.extension import List
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
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_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
|
|
||||||
from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO
|
|
||||||
from bot_api.model.email_string_dto import EMailStringDTO
|
|
||||||
from bot_api.model.o_auth_dto import OAuthDTO
|
|
||||||
from bot_api.model.reset_password_dto import ResetPasswordDTO
|
|
||||||
from bot_api.model.token_dto import TokenDTO
|
|
||||||
from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO
|
|
||||||
from bot_api.transformer.auth_user_transformer import AuthUserTransformer as AUT
|
|
||||||
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
|
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
|
||||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
|
||||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
|
||||||
from bot_data.model.auth_user import AuthUser
|
|
||||||
from bot_data.model.auth_user_users_relation import AuthUserUsersRelation
|
|
||||||
|
|
||||||
_email_regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
|
|
||||||
|
|
||||||
|
|
||||||
class AuthService(AuthServiceABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
env: ApplicationEnvironmentABC,
|
|
||||||
logger: ApiLogger,
|
|
||||||
bot: DiscordBotServiceABC,
|
|
||||||
db: DatabaseContextABC,
|
|
||||||
auth_users: AuthUserRepositoryABC,
|
|
||||||
users: UserRepositoryABC,
|
|
||||||
servers: ServerRepositoryABC,
|
|
||||||
# mailer: MailThread,
|
|
||||||
mailer: EMailClientABC,
|
|
||||||
t: TranslatePipe,
|
|
||||||
auth_settings: AuthenticationSettings,
|
|
||||||
frontend_settings: FrontendSettings,
|
|
||||||
|
|
||||||
):
|
|
||||||
AuthServiceABC.__init__(self)
|
|
||||||
|
|
||||||
self._environment = env
|
|
||||||
self._logger = logger
|
|
||||||
self._bot = bot
|
|
||||||
self._db = db
|
|
||||||
self._auth_users = auth_users
|
|
||||||
self._users = users
|
|
||||||
self._servers = servers
|
|
||||||
self._mailer = mailer
|
|
||||||
self._t = t
|
|
||||||
self._auth_settings = auth_settings
|
|
||||||
self._frontend_settings = frontend_settings
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _hash_sha256(password: str, salt: str) -> str:
|
|
||||||
return hashlib.sha256(f'{password}{salt}'.encode('utf-8')).hexdigest()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _is_email_valid(email: str) -> bool:
|
|
||||||
if re.fullmatch(_email_regex, email) is not None:
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def generate_token(self, user: AuthUser) -> str:
|
|
||||||
token = jwt.encode(
|
|
||||||
payload={
|
|
||||||
'user_id': user.id,
|
|
||||||
'email': user.email,
|
|
||||||
'role': user.auth_role.value,
|
|
||||||
'exp': datetime.now(tz=timezone.utc) + timedelta(days=self._auth_settings.token_expire_time),
|
|
||||||
'iss': self._auth_settings.issuer,
|
|
||||||
'aud': self._auth_settings.audience
|
|
||||||
},
|
|
||||||
key=CredentialManager.decrypt(self._auth_settings.secret_key)
|
|
||||||
)
|
|
||||||
|
|
||||||
return token
|
|
||||||
|
|
||||||
def decode_token(self, token: str) -> dict:
|
|
||||||
return jwt.decode(
|
|
||||||
token,
|
|
||||||
key=CredentialManager.decrypt(self._auth_settings.secret_key),
|
|
||||||
issuer=self._auth_settings.issuer,
|
|
||||||
audience=self._auth_settings.audience,
|
|
||||||
algorithms=['HS256']
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_decoded_token_from_request(self) -> dict:
|
|
||||||
token = None
|
|
||||||
if 'Authorization' in request.headers:
|
|
||||||
bearer = request.headers.get('Authorization')
|
|
||||||
token = bearer.split()[1]
|
|
||||||
|
|
||||||
if token is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.Unauthorized, f'Token not set')
|
|
||||||
|
|
||||||
return jwt.decode(
|
|
||||||
token,
|
|
||||||
key=CredentialManager.decrypt(self._auth_settings.secret_key),
|
|
||||||
issuer=self._auth_settings.issuer,
|
|
||||||
audience=self._auth_settings.audience,
|
|
||||||
algorithms=['HS256']
|
|
||||||
)
|
|
||||||
|
|
||||||
def find_decoded_token_from_request(self) -> Optional[dict]:
|
|
||||||
token = None
|
|
||||||
if 'Authorization' in request.headers:
|
|
||||||
bearer = request.headers.get('Authorization')
|
|
||||||
token = bearer.split()[1]
|
|
||||||
|
|
||||||
return jwt.decode(
|
|
||||||
token,
|
|
||||||
key=CredentialManager.decrypt(self._auth_settings.secret_key),
|
|
||||||
issuer=self._auth_settings.issuer,
|
|
||||||
audience=self._auth_settings.audience,
|
|
||||||
algorithms=['HS256']
|
|
||||||
) if token is not None else None
|
|
||||||
|
|
||||||
def _create_and_save_refresh_token(self, user: AuthUser) -> str:
|
|
||||||
token = str(uuid.uuid4())
|
|
||||||
user.refresh_token = token
|
|
||||||
user.refresh_token_expire_time = datetime.now() + timedelta(days=self._auth_settings.refresh_token_expire_time)
|
|
||||||
self._auth_users.update_auth_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
return token
|
|
||||||
|
|
||||||
def _send_link_mail(self, email: str, subject: str, message: str):
|
|
||||||
url = self._frontend_settings.url
|
|
||||||
if not url.endswith('/'):
|
|
||||||
url = f'{url}/'
|
|
||||||
|
|
||||||
self._mailer.connect()
|
|
||||||
mail = EMail()
|
|
||||||
mail.add_header('Mime-Version: 1.0')
|
|
||||||
mail.add_header('Content-Type: text/plain; charset=utf-8')
|
|
||||||
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)}
|
|
||||||
""")
|
|
||||||
|
|
||||||
thr = Thread(target=self._mailer.send_mail, args=[mail])
|
|
||||||
thr.start()
|
|
||||||
|
|
||||||
def _send_confirmation_id_to_user(self, user: AuthUser):
|
|
||||||
url = self._frontend_settings.url
|
|
||||||
if not url.endswith('/'):
|
|
||||||
url = f'{url}/'
|
|
||||||
|
|
||||||
self._send_link_mail(
|
|
||||||
user.email,
|
|
||||||
self._t.transform('api.auth.confirmation.subject').format(user.first_name, user.last_name),
|
|
||||||
self._t.transform('api.auth.confirmation.message').format(url, user.confirmation_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
def _send_forgot_password_id_to_user(self, user: AuthUser):
|
|
||||||
url = self._frontend_settings.url
|
|
||||||
if not url.endswith('/'):
|
|
||||||
url = f'{url}/'
|
|
||||||
|
|
||||||
self._send_link_mail(
|
|
||||||
user.email,
|
|
||||||
self._t.transform('api.auth.forgot_password.subject').format(user.first_name, user.last_name),
|
|
||||||
self._t.transform('api.auth.forgot_password.message').format(url, user.forgot_password_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
async def get_all_auth_users_async(self) -> List[AuthUserDTO]:
|
|
||||||
result = self._auth_users.get_all_auth_users() \
|
|
||||||
.select(lambda x: AUT.to_dto(x))
|
|
||||||
return List(AuthUserDTO, result)
|
|
||||||
|
|
||||||
async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO:
|
|
||||||
users = self._auth_users.get_filtered_auth_users(criteria)
|
|
||||||
result = users.result.select(lambda x: AUT.to_dto(x))
|
|
||||||
|
|
||||||
return AuthUserFilteredResultDTO(
|
|
||||||
List(AuthUserDTO, result),
|
|
||||||
users.total_count
|
|
||||||
)
|
|
||||||
|
|
||||||
async def get_auth_user_by_email_async(self, email: str, with_password: bool = False) -> AuthUserDTO:
|
|
||||||
try:
|
|
||||||
# todo: check if logged in user is admin then send mail
|
|
||||||
user = self._auth_users.get_auth_user_by_email(email)
|
|
||||||
return AUT.to_dto(user, password=user.password if with_password else None)
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'AuthUser not found', e)
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, f'User not found {email}')
|
|
||||||
|
|
||||||
async def find_auth_user_by_email_async(self, email: str) -> Optional[AuthUser]:
|
|
||||||
user = self._auth_users.find_auth_user_by_email(email)
|
|
||||||
return AUT.to_dto(user) if user is not None else None
|
|
||||||
|
|
||||||
async def add_auth_user_async(self, user_dto: AuthUserDTO):
|
|
||||||
db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
|
|
||||||
if db_user is not None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists')
|
|
||||||
|
|
||||||
user = AUT.to_db(user_dto)
|
|
||||||
if self._auth_users.get_all_auth_users().count() == 0:
|
|
||||||
user.auth_role = AuthRoleEnum.admin
|
|
||||||
|
|
||||||
user.password_salt = uuid.uuid4()
|
|
||||||
user.password = self._hash_sha256(user_dto.password, user.password_salt)
|
|
||||||
if not self._is_email_valid(user.email):
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, 'Invalid E-Mail address')
|
|
||||||
|
|
||||||
try:
|
|
||||||
user.confirmation_id = uuid.uuid4()
|
|
||||||
self._auth_users.add_auth_user(user)
|
|
||||||
self._send_confirmation_id_to_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
self._logger.info(__name__, f'Added auth user with E-Mail: {user_dto.email}')
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Cannot add user with E-Mail {user_dto.email}', e)
|
|
||||||
raise ServiceException(ServiceErrorCode.UnableToAdd, "Invalid E-Mail")
|
|
||||||
|
|
||||||
async def add_auth_user_by_oauth_async(self, dto: OAuthDTO):
|
|
||||||
db_user = self._auth_users.find_auth_user_by_email(dto.user.email)
|
|
||||||
|
|
||||||
if db_user is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found')
|
|
||||||
|
|
||||||
if db_user.oauth_id != dto.oauth_id:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong OAuthId')
|
|
||||||
|
|
||||||
try:
|
|
||||||
db_user.first_name = dto.user.first_name
|
|
||||||
db_user.last_name = dto.user.last_name
|
|
||||||
db_user.password_salt = uuid.uuid4()
|
|
||||||
db_user.password = self._hash_sha256(dto.user.password, db_user.password_salt)
|
|
||||||
db_user.oauth_id = None
|
|
||||||
db_user.confirmation_id = uuid.uuid4()
|
|
||||||
self._send_confirmation_id_to_user(db_user)
|
|
||||||
self._auth_users.update_auth_user(db_user)
|
|
||||||
self._logger.info(__name__, f'Added auth user with E-Mail: {dto.user.email}')
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Cannot add user with E-Mail {dto.user.email}', e)
|
|
||||||
raise ServiceException(ServiceErrorCode.UnableToAdd, "Invalid E-Mail")
|
|
||||||
|
|
||||||
self._db.save_changes()
|
|
||||||
|
|
||||||
async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO, dc_id: int) -> OAuthDTO:
|
|
||||||
db_auth_user = self._auth_users.find_auth_user_by_email(user_dto.email)
|
|
||||||
|
|
||||||
# user exists
|
|
||||||
if db_auth_user is not None and db_auth_user.users.count() > 0:
|
|
||||||
# raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists')
|
|
||||||
self._logger.debug(__name__, f'Discord user already exists')
|
|
||||||
return OAuthDTO(AUT.to_dto(db_auth_user), None)
|
|
||||||
|
|
||||||
# user exists but discord user id not set
|
|
||||||
elif db_auth_user is not None and db_auth_user.users.count() == 0:
|
|
||||||
self._logger.debug(__name__, f'Auth user exists but not linked with discord')
|
|
||||||
# users = self._users.get_users_by_discord_id(user_dto.user_id)
|
|
||||||
# add auth_user to user refs
|
|
||||||
db_auth_user.oauth_id = None
|
|
||||||
|
|
||||||
else:
|
|
||||||
# user does not exists
|
|
||||||
self._logger.debug(__name__, f'Auth user does not exist')
|
|
||||||
try:
|
|
||||||
user_dto.user_id = self._users.get_users_by_discord_id(user_dto.user_id).single().user_id
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'User not found')
|
|
||||||
user_dto.user_id = None
|
|
||||||
|
|
||||||
await self.add_auth_user_async(user_dto)
|
|
||||||
db_auth_user = self._auth_users.get_auth_user_by_email(user_dto.email)
|
|
||||||
db_auth_user.oauth_id = uuid.uuid4()
|
|
||||||
|
|
||||||
for g in self._bot.guilds:
|
|
||||||
member = g.get_member(int(dc_id))
|
|
||||||
if member is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
server = self._servers.get_server_by_discord_id(g.id)
|
|
||||||
users = self._users.get_users_by_discord_id(dc_id)
|
|
||||||
for user in users:
|
|
||||||
if user.server.server_id != server.server_id:
|
|
||||||
continue
|
|
||||||
self._auth_users.add_auth_user_user_rel(AuthUserUsersRelation(db_auth_user, user))
|
|
||||||
|
|
||||||
self._auth_users.update_auth_user(db_auth_user)
|
|
||||||
self._db.save_changes()
|
|
||||||
return OAuthDTO(AUT.to_dto(db_auth_user), db_auth_user.oauth_id)
|
|
||||||
|
|
||||||
async def update_user_async(self, update_user_dto: UpdateAuthUserDTO):
|
|
||||||
if update_user_dto is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, f'User is empty')
|
|
||||||
|
|
||||||
if update_user_dto.auth_user is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, f'Existing user is empty')
|
|
||||||
|
|
||||||
if update_user_dto.new_auth_user is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, f'New user is empty')
|
|
||||||
|
|
||||||
if not self._is_email_valid(update_user_dto.auth_user.email) or not self._is_email_valid(update_user_dto.new_auth_user.email):
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, f'Invalid E-Mail')
|
|
||||||
|
|
||||||
user = self._auth_users.find_auth_user_by_email(update_user_dto.auth_user.email)
|
|
||||||
if user is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found')
|
|
||||||
|
|
||||||
if user.confirmation_id is not None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidUser, 'E-Mail not confirmed')
|
|
||||||
|
|
||||||
# update first name
|
|
||||||
if update_user_dto.new_auth_user.first_name is not None and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name:
|
|
||||||
user.first_name = update_user_dto.new_auth_user.first_name
|
|
||||||
|
|
||||||
# update last name
|
|
||||||
if update_user_dto.new_auth_user.last_name is not None and update_user_dto.new_auth_user.last_name != '' and \
|
|
||||||
update_user_dto.auth_user.last_name != update_user_dto.new_auth_user.last_name:
|
|
||||||
user.last_name = update_user_dto.new_auth_user.last_name
|
|
||||||
|
|
||||||
# update E-Mail
|
|
||||||
if update_user_dto.new_auth_user.email is not None and update_user_dto.new_auth_user.email != '' and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email:
|
|
||||||
user_by_new_e_mail = self._auth_users.find_auth_user_by_email(update_user_dto.new_auth_user.email)
|
|
||||||
if user_by_new_e_mail is not None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists')
|
|
||||||
user.email = update_user_dto.new_auth_user.email
|
|
||||||
|
|
||||||
update_user_dto.auth_user.password = self._hash_sha256(update_user_dto.auth_user.password, user.password_salt)
|
|
||||||
if update_user_dto.auth_user.password != user.password:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password')
|
|
||||||
|
|
||||||
# update password
|
|
||||||
if update_user_dto.new_auth_user.password is not None and self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) != user.password:
|
|
||||||
user.password_salt = uuid.uuid4()
|
|
||||||
user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt)
|
|
||||||
|
|
||||||
self._auth_users.update_auth_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
|
|
||||||
async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO):
|
|
||||||
if update_user_dto is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, f'User is empty')
|
|
||||||
|
|
||||||
if update_user_dto.auth_user is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, f'Existing user is empty')
|
|
||||||
|
|
||||||
if update_user_dto.new_auth_user is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, f'New user is empty')
|
|
||||||
|
|
||||||
if not self._is_email_valid(update_user_dto.auth_user.email) or not self._is_email_valid(update_user_dto.new_auth_user.email):
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, f'Invalid E-Mail')
|
|
||||||
|
|
||||||
user = self._auth_users.find_auth_user_by_email(update_user_dto.auth_user.email)
|
|
||||||
if user is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found')
|
|
||||||
|
|
||||||
if user.confirmation_id is not None and update_user_dto.new_auth_user.is_confirmed:
|
|
||||||
user.confirmation_id = None
|
|
||||||
elif user.confirmation_id is None and not update_user_dto.new_auth_user.is_confirmed:
|
|
||||||
user.confirmation_id = uuid.uuid4()
|
|
||||||
# else
|
|
||||||
# raise ServiceException(ServiceErrorCode.InvalidUser, 'E-Mail not confirmed')
|
|
||||||
|
|
||||||
# update first name
|
|
||||||
if update_user_dto.new_auth_user.first_name is not None and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name:
|
|
||||||
user.first_name = update_user_dto.new_auth_user.first_name
|
|
||||||
|
|
||||||
# update last name
|
|
||||||
if update_user_dto.new_auth_user.last_name is not None and update_user_dto.new_auth_user.last_name != '' and update_user_dto.auth_user.last_name != update_user_dto.new_auth_user.last_name:
|
|
||||||
user.last_name = update_user_dto.new_auth_user.last_name
|
|
||||||
|
|
||||||
# update E-Mail
|
|
||||||
if update_user_dto.new_auth_user.email is not None and update_user_dto.new_auth_user.email != '' and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email:
|
|
||||||
user_by_new_e_mail = self._auth_users.find_auth_user_by_email(update_user_dto.new_auth_user.email)
|
|
||||||
if user_by_new_e_mail is not None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists')
|
|
||||||
user.email = update_user_dto.new_auth_user.email
|
|
||||||
|
|
||||||
# update password
|
|
||||||
if update_user_dto.new_auth_user.password is not None and update_user_dto.change_password and user.password != self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt):
|
|
||||||
user.password_salt = uuid.uuid4()
|
|
||||||
user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt)
|
|
||||||
|
|
||||||
# update role
|
|
||||||
if user.auth_role == update_user_dto.auth_user.auth_role and user.auth_role != update_user_dto.new_auth_user.auth_role:
|
|
||||||
user.auth_role = update_user_dto.new_auth_user.auth_role
|
|
||||||
|
|
||||||
self._auth_users.update_auth_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
|
|
||||||
async def delete_auth_user_by_email_async(self, email: str):
|
|
||||||
try:
|
|
||||||
user = self._auth_users.get_auth_user_by_email(email)
|
|
||||||
self._auth_users.delete_auth_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Cannot delete user', e)
|
|
||||||
raise ServiceException(ServiceErrorCode.UnableToDelete, f'Cannot delete user by mail {email}')
|
|
||||||
|
|
||||||
async def delete_auth_user_async(self, user_dto: AuthUser):
|
|
||||||
try:
|
|
||||||
self._auth_users.delete_auth_user(AUT.to_db(user_dto))
|
|
||||||
self._db.save_changes()
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Cannot delete user', e)
|
|
||||||
raise ServiceException(ServiceErrorCode.UnableToDelete, f'Cannot delete user by mail {user_dto.email}')
|
|
||||||
|
|
||||||
def verify_login(self, token_str: str) -> bool:
|
|
||||||
try:
|
|
||||||
token = self.decode_token(token_str)
|
|
||||||
if token is None or 'email' not in token:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid')
|
|
||||||
|
|
||||||
user = self._auth_users.find_auth_user_by_email(token['email'])
|
|
||||||
if user is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired')
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Token invalid', e)
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def login_async(self, user_dto: AuthUser) -> TokenDTO:
|
|
||||||
if user_dto is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, 'User not set')
|
|
||||||
|
|
||||||
db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
|
|
||||||
if db_user is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidUser, f'User not found')
|
|
||||||
|
|
||||||
user_dto.password = self._hash_sha256(user_dto.password, db_user.password_salt)
|
|
||||||
if db_user.password != user_dto.password:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password')
|
|
||||||
|
|
||||||
token = self.generate_token(db_user)
|
|
||||||
refresh_token = self._create_and_save_refresh_token(db_user)
|
|
||||||
if db_user.forgot_password_id is not None:
|
|
||||||
db_user.forgot_password_id = None
|
|
||||||
|
|
||||||
self._db.save_changes()
|
|
||||||
return TokenDTO(token, refresh_token)
|
|
||||||
|
|
||||||
async def login_discord_async(self, user_dto: AuthUserDTO) -> TokenDTO:
|
|
||||||
if user_dto is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, 'User not set')
|
|
||||||
|
|
||||||
db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
|
|
||||||
if db_user is None:
|
|
||||||
await self.add_auth_user_async(user_dto)
|
|
||||||
# raise ServiceException(ServiceErrorCode.InvalidUser, f'User not found')
|
|
||||||
|
|
||||||
db_user = self._auth_users.get_auth_user_by_email(user_dto.email)
|
|
||||||
token = self.generate_token(db_user)
|
|
||||||
refresh_token = self._create_and_save_refresh_token(db_user)
|
|
||||||
if db_user.forgot_password_id is not None:
|
|
||||||
db_user.forgot_password_id = None
|
|
||||||
|
|
||||||
self._db.save_changes()
|
|
||||||
return TokenDTO(token, refresh_token)
|
|
||||||
|
|
||||||
async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO:
|
|
||||||
if token_dto is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, f'Token not set')
|
|
||||||
|
|
||||||
try:
|
|
||||||
token = self.decode_token(token_dto.token)
|
|
||||||
if token is None or 'email' not in token:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid')
|
|
||||||
|
|
||||||
user = self._auth_users.get_auth_user_by_email(token['email'])
|
|
||||||
if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now():
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired')
|
|
||||||
|
|
||||||
return TokenDTO(self.generate_token(user), self._create_and_save_refresh_token(user))
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Refreshing token failed', e)
|
|
||||||
return TokenDTO('', '')
|
|
||||||
|
|
||||||
async def revoke_async(self, token_dto: TokenDTO):
|
|
||||||
if token_dto is None or token_dto.token is None or token_dto.refresh_token is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, 'Token not set')
|
|
||||||
|
|
||||||
try:
|
|
||||||
token = self.decode_token(token_dto.token)
|
|
||||||
|
|
||||||
user = self._auth_users.get_auth_user_by_email(token['email'])
|
|
||||||
if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now():
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired')
|
|
||||||
|
|
||||||
user.refresh_token = None
|
|
||||||
self._auth_users.update_auth_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Refreshing token failed', e)
|
|
||||||
|
|
||||||
async def confirm_email_async(self, id: str) -> bool:
|
|
||||||
user = self._auth_users.find_auth_user_by_confirmation_id(id)
|
|
||||||
if user is None:
|
|
||||||
return False
|
|
||||||
|
|
||||||
user.confirmation_id = None
|
|
||||||
self._auth_users.update_auth_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def forgot_password_async(self, email: str):
|
|
||||||
user = self._auth_users.find_auth_user_by_email(email)
|
|
||||||
if user is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
user.forgot_password_id = uuid.uuid4()
|
|
||||||
self._auth_users.update_auth_user(user)
|
|
||||||
self._send_forgot_password_id_to_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
|
|
||||||
async def confirm_forgot_password_async(self, id: str) -> EMailStringDTO:
|
|
||||||
user = self._auth_users.find_auth_user_by_forgot_password_id(id)
|
|
||||||
return EMailStringDTO(user.email)
|
|
||||||
|
|
||||||
async def reset_password_async(self, rp_dto: ResetPasswordDTO):
|
|
||||||
user = self._auth_users.find_auth_user_by_forgot_password_id(rp_dto.id)
|
|
||||||
if user is None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidUser, f'User by forgot password id {rp_dto.id} not found')
|
|
||||||
|
|
||||||
if user.confirmation_id is not None:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidUser, f'E-Mail not confirmed')
|
|
||||||
|
|
||||||
if user.password is None or rp_dto.password == '':
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, f'Password not set')
|
|
||||||
|
|
||||||
user.password_salt = uuid.uuid4()
|
|
||||||
user.password = self._hash_sha256(rp_dto.password, user.password_salt)
|
|
||||||
user.forgot_password_id = None
|
|
||||||
self._auth_users.update_auth_user(user)
|
|
||||||
self._db.save_changes()
|
|
@ -1,105 +0,0 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
|
||||||
from cpl_query.extension import List
|
|
||||||
from flask import jsonify
|
|
||||||
|
|
||||||
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_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
|
|
||||||
from bot_api.model.error_dto import ErrorDTO
|
|
||||||
from bot_api.transformer.server_transformer import ServerTransformer
|
|
||||||
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
|
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
|
||||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
|
||||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
|
||||||
from bot_data.model.server import Server
|
|
||||||
|
|
||||||
|
|
||||||
class DiscordService:
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
bot: DiscordBotServiceABC,
|
|
||||||
servers: ServerRepositoryABC,
|
|
||||||
auth: AuthServiceABC,
|
|
||||||
auth_users: AuthUserRepositoryABC,
|
|
||||||
users: UserRepositoryABC,
|
|
||||||
):
|
|
||||||
self._bot = bot
|
|
||||||
self._servers = servers
|
|
||||||
self._auth = auth
|
|
||||||
self._auth_users = auth_users
|
|
||||||
self._users = users
|
|
||||||
|
|
||||||
def _to_dto(self, x: Server) -> Optional[ServerDTO]:
|
|
||||||
guild = self._bot.get_guild(x.discord_server_id)
|
|
||||||
if guild is None:
|
|
||||||
return ServerTransformer.to_dto(
|
|
||||||
x,
|
|
||||||
'',
|
|
||||||
0,
|
|
||||||
None
|
|
||||||
)
|
|
||||||
|
|
||||||
return ServerTransformer.to_dto(
|
|
||||||
x,
|
|
||||||
guild.name,
|
|
||||||
guild.member_count,
|
|
||||||
guild.icon
|
|
||||||
)
|
|
||||||
|
|
||||||
async def get_all_servers(self) -> List[ServerDTO]:
|
|
||||||
servers = List(ServerDTO, self._servers.get_servers())
|
|
||||||
return servers.select(self._to_dto).where(lambda x: x.name != '')
|
|
||||||
|
|
||||||
async def get_all_servers_by_user(self) -> List[ServerDTO]:
|
|
||||||
token = self._auth.get_decoded_token_from_request()
|
|
||||||
if token is None or 'email' not in token or 'role' not in token:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid')
|
|
||||||
|
|
||||||
role = AuthRoleEnum(token['role'])
|
|
||||||
servers = self._servers.get_servers()
|
|
||||||
if role != AuthRoleEnum.admin:
|
|
||||||
auth_user = self._auth_users.find_auth_user_by_email(token['email'])
|
|
||||||
if auth_user is not None:
|
|
||||||
user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.server_id)
|
|
||||||
servers = servers.where(lambda x: x.server_id in user_ids)
|
|
||||||
|
|
||||||
servers = List(ServerDTO, servers)
|
|
||||||
return servers.select(self._to_dto).where(lambda x: x.name != '')
|
|
||||||
|
|
||||||
async def get_filtered_servers_async(self, criteria: ServerSelectCriteria) -> ServerFilteredResultDTO:
|
|
||||||
token = self._auth.get_decoded_token_from_request()
|
|
||||||
if token is None or 'email' not in token or 'role' not in token:
|
|
||||||
raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid')
|
|
||||||
|
|
||||||
role = AuthRoleEnum(token['role'])
|
|
||||||
filtered_result = self._servers.get_filtered_servers(criteria)
|
|
||||||
# filter out servers, where the user not exists
|
|
||||||
if role != AuthRoleEnum.admin:
|
|
||||||
auth_user = self._auth_users.find_auth_user_by_email(token['email'])
|
|
||||||
if auth_user is not None:
|
|
||||||
user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.server_id)
|
|
||||||
filtered_result.result = filtered_result.result.where(lambda x: x.server_id in user_ids)
|
|
||||||
|
|
||||||
servers: List = filtered_result.result.select(self._to_dto).where(lambda x: x.name != '')
|
|
||||||
result = List(ServerDTO, servers)
|
|
||||||
|
|
||||||
if criteria.name is not None and criteria.name != '':
|
|
||||||
result = result.where(lambda x: criteria.name.lower() in x.name.lower() or x.name.lower() == criteria.name.lower())
|
|
||||||
|
|
||||||
return ServerFilteredResultDTO(
|
|
||||||
List(ServerDTO, result),
|
|
||||||
servers.count()
|
|
||||||
)
|
|
||||||
|
|
||||||
async def get_server_by_id_async(self, id: int) -> ServerDTO:
|
|
||||||
server = self._servers.get_server_by_id(id)
|
|
||||||
guild = self._bot.get_guild(server.discord_server_id)
|
|
||||||
|
|
||||||
server_dto = ServerTransformer.to_dto(server, guild.name, guild.member_count, guild.icon)
|
|
||||||
return server_dto
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'bot_api.transformer'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,38 +0,0 @@
|
|||||||
from datetime import datetime, timezone
|
|
||||||
|
|
||||||
from bot_api.abc.transformer_abc import TransformerABC
|
|
||||||
from bot_api.model.auth_user_dto import AuthUserDTO
|
|
||||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
|
||||||
from bot_data.model.auth_user import AuthUser
|
|
||||||
|
|
||||||
|
|
||||||
class AuthUserTransformer(TransformerABC):
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def to_db(dto: AuthUserDTO) -> AuthUser:
|
|
||||||
return AuthUser(
|
|
||||||
dto.first_name,
|
|
||||||
dto.last_name,
|
|
||||||
dto.email,
|
|
||||||
dto.password,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
datetime.now(),
|
|
||||||
AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role),
|
|
||||||
auth_user_id=0 if dto.id is None else dto.id
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def to_dto(db: AuthUser, password: str = None) -> AuthUserDTO:
|
|
||||||
return AuthUserDTO(
|
|
||||||
db.id,
|
|
||||||
db.first_name,
|
|
||||||
db.last_name,
|
|
||||||
db.email,
|
|
||||||
'' if password is None else password,
|
|
||||||
db.confirmation_id,
|
|
||||||
db.auth_role
|
|
||||||
)
|
|
@ -1,24 +0,0 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
import discord
|
|
||||||
|
|
||||||
from bot_api.abc.transformer_abc import TransformerABC
|
|
||||||
from bot_api.model.discord.server_dto import ServerDTO
|
|
||||||
from bot_data.model.server import Server
|
|
||||||
|
|
||||||
|
|
||||||
class ServerTransformer(TransformerABC):
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def to_db(dto: ServerDTO) -> Server:
|
|
||||||
return Server(dto.discord_id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def to_dto(db: Server, name: str, member_count: int, icon_url: Optional[discord.Asset]) -> ServerDTO:
|
|
||||||
return ServerDTO(
|
|
||||||
db.server_id,
|
|
||||||
db.discord_server_id,
|
|
||||||
name,
|
|
||||||
member_count,
|
|
||||||
icon_url.url if icon_url is not None else None,
|
|
||||||
)
|
|
@ -1,30 +0,0 @@
|
|||||||
from cpl_core.application import ApplicationExtensionABC
|
|
||||||
from cpl_core.configuration import ConfigurationABC
|
|
||||||
from cpl_core.dependency_injection import ServiceProviderABC
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
|
|
||||||
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC
|
|
||||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
|
||||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
|
||||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
|
||||||
from bot_core.helper.command_checks import CommandChecks
|
|
||||||
from bot_core.helper.event_checks import EventChecks
|
|
||||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
|
||||||
|
|
||||||
|
|
||||||
class CoreExtension(ApplicationExtensionABC):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
ApplicationExtensionABC.__init__(self)
|
|
||||||
|
|
||||||
async def run(self, config: ConfigurationABC, services: ServiceProviderABC):
|
|
||||||
feature_flags: FeatureFlagsSettings = config.get_configuration(FeatureFlagsSettings)
|
|
||||||
if not feature_flags.get_flag(FeatureFlagsEnum.core_module):
|
|
||||||
return
|
|
||||||
|
|
||||||
permissions: PermissionServiceABC = services.get_service(PermissionServiceABC)
|
|
||||||
client_utils: ClientUtilsServiceABC = services.get_service(ClientUtilsServiceABC)
|
|
||||||
message_service: MessageServiceABC = services.get_service(MessageServiceABC)
|
|
||||||
t: TranslatePipe = services.get_service(TranslatePipe)
|
|
||||||
CommandChecks.init(permissions, client_utils, message_service, t)
|
|
||||||
EventChecks.init(client_utils)
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'bot_core.exception'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,7 +0,0 @@
|
|||||||
from discord.ext.commands import CommandError
|
|
||||||
|
|
||||||
|
|
||||||
class CheckError(CommandError):
|
|
||||||
|
|
||||||
def __init__(self, message, *args):
|
|
||||||
CommandError.__init__(self, message, *args)
|
|
@ -1,76 +0,0 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
from discord.ext import commands
|
|
||||||
from discord.ext.commands import Context
|
|
||||||
|
|
||||||
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC
|
|
||||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
|
||||||
from bot_core.exception.check_error import CheckError
|
|
||||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
|
||||||
|
|
||||||
|
|
||||||
class CommandChecks:
|
|
||||||
_permissions: Optional[PermissionServiceABC] = None
|
|
||||||
_client_utils: Optional[ClientUtilsServiceABC] = None
|
|
||||||
_message_service: Optional[MessageServiceABC] = None
|
|
||||||
_t: Optional[TranslatePipe] = None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def init(
|
|
||||||
cls,
|
|
||||||
permissions: PermissionServiceABC,
|
|
||||||
client_utils: ClientUtilsServiceABC,
|
|
||||||
message_service: MessageServiceABC,
|
|
||||||
translate: TranslatePipe,
|
|
||||||
):
|
|
||||||
cls._permissions = permissions
|
|
||||||
cls._client_utils = client_utils
|
|
||||||
cls._message_service = message_service
|
|
||||||
cls._t = translate
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def check_is_ready(cls):
|
|
||||||
async def check_if_bot_is_ready_yet_and_respond(ctx: Context) -> bool:
|
|
||||||
result = await cls._client_utils.check_if_bot_is_ready_yet_and_respond(ctx)
|
|
||||||
if not result:
|
|
||||||
raise CheckError(f'Bot is not ready')
|
|
||||||
return result
|
|
||||||
|
|
||||||
return commands.check(check_if_bot_is_ready_yet_and_respond)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def check_is_member_admin(cls):
|
|
||||||
async def check_is_member_admin(ctx: Context):
|
|
||||||
has_permission = cls._permissions.is_member_admin(ctx.author)
|
|
||||||
if not has_permission:
|
|
||||||
await cls._message_service.send_ctx_msg(ctx, cls._t.transform('common.no_permission_message'))
|
|
||||||
raise CheckError(f'Member {ctx.author.name} is not admin')
|
|
||||||
|
|
||||||
return has_permission
|
|
||||||
|
|
||||||
return commands.check(check_is_member_admin)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def check_is_member_technician(cls):
|
|
||||||
async def check_is_member_technician(ctx: Context):
|
|
||||||
has_permission = cls._permissions.is_member_technician(ctx.author)
|
|
||||||
if not has_permission:
|
|
||||||
await cls._message_service.send_ctx_msg(ctx, cls._t.transform('common.no_permission_message'))
|
|
||||||
raise CheckError(f'Member {ctx.author.name} is not technician')
|
|
||||||
|
|
||||||
return has_permission
|
|
||||||
|
|
||||||
return commands.check(check_is_member_technician)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def check_is_member_moderator(cls):
|
|
||||||
async def check_is_member_moderator(ctx: Context):
|
|
||||||
has_permission = cls._permissions.is_member_moderator(ctx.author)
|
|
||||||
if not has_permission:
|
|
||||||
await cls._message_service.send_ctx_msg(ctx, cls._t.transform('common.no_permission_message'))
|
|
||||||
raise CheckError(f'Member {ctx.author.name} is not moderator')
|
|
||||||
|
|
||||||
return has_permission
|
|
||||||
|
|
||||||
return commands.check(check_is_member_moderator)
|
|
@ -1,31 +0,0 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
from discord.ext import commands
|
|
||||||
from discord.ext.commands import Context
|
|
||||||
|
|
||||||
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC
|
|
||||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
|
||||||
from bot_core.exception.check_error import CheckError
|
|
||||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
|
||||||
|
|
||||||
|
|
||||||
class EventChecks:
|
|
||||||
_client_utils: Optional[ClientUtilsServiceABC] = None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def init(
|
|
||||||
cls,
|
|
||||||
client_utils: ClientUtilsServiceABC,
|
|
||||||
):
|
|
||||||
cls._client_utils = client_utils
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def check_is_ready(cls):
|
|
||||||
async def check_if_bot_is_ready() -> bool:
|
|
||||||
result = await cls._client_utils.check_if_bot_is_ready()
|
|
||||||
if not result:
|
|
||||||
raise CheckError(f'Bot is not ready')
|
|
||||||
return result
|
|
||||||
|
|
||||||
return commands.check(check_if_bot_is_ready)
|
|
@ -1,51 +0,0 @@
|
|||||||
from abc import ABC, abstractmethod
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria
|
|
||||||
from bot_data.filtered_result import FilteredResult
|
|
||||||
from bot_data.model.auth_user import AuthUser
|
|
||||||
from bot_data.model.auth_user_users_relation import AuthUserUsersRelation
|
|
||||||
|
|
||||||
|
|
||||||
class AuthUserRepositoryABC(ABC):
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def __init__(self): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_all_auth_users(self) -> List[AuthUser]: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_filtered_auth_users(self, criteria: AuthUserSelectCriteria) -> FilteredResult: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_auth_user_by_email(self, email: str) -> AuthUser: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def find_auth_user_by_email(self, email: str) -> Optional[AuthUser]: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def find_auth_user_by_confirmation_id(self, id: str) -> Optional[AuthUser]: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def find_auth_user_by_forgot_password_id(self, id: str) -> Optional[AuthUser]: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def add_auth_user(self, user: AuthUser): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def update_auth_user(self, user: AuthUser): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def delete_auth_user(self, user: AuthUser): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def add_auth_user_user_rel(self, rel: AuthUserUsersRelation): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def update_auth_user_user_rel(self, rel: AuthUserUsersRelation): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def delete_auth_user_user_rel(self, rel: AuthUserUsersRelation): pass
|
|
@ -1,10 +0,0 @@
|
|||||||
from abc import ABC, abstractmethod
|
|
||||||
|
|
||||||
|
|
||||||
class DataSeederABC(ABC):
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def __init__(self): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def seed(self): pass
|
|
@ -1,36 +0,0 @@
|
|||||||
from abc import ABC, abstractmethod
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
from bot_data.model.level import Level
|
|
||||||
|
|
||||||
|
|
||||||
class LevelRepositoryABC(ABC):
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def __init__(self): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_levels(self) -> List[Level]: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_level_by_id(self, id: int) -> Level: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def find_level_by_id(self, id: int) -> Optional[Level]: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_levels_by_server_id(self, server_id: int) -> List[Level]: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def find_levels_by_server_id(self, server_id: int) -> Optional[List[Level]]: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def add_level(self, level: Level): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def update_level(self, level: Level): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def delete_level(self, level: Level): pass
|
|
@ -1,36 +0,0 @@
|
|||||||
from abc import ABC, abstractmethod
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
from bot_data.model.statistic import Statistic
|
|
||||||
|
|
||||||
|
|
||||||
class StatisticRepositoryABC(ABC):
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def __init__(self): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_statistics(self) -> List[Statistic]: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_statistics_by_server_id(self, server_id: int) -> List[Statistic]: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_statistic_by_id(self, id: int) -> Statistic: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_statistic_by_name(self, name: str, server_id: int) -> Statistic: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def find_statistic_by_name(self, name: str, server_id: int) -> Optional[Statistic]: pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def add_statistic(self, statistic: Statistic): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def update_statistic(self, statistic: Statistic): pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def delete_statistic(self, statistic: Statistic): pass
|
|
@ -1,24 +0,0 @@
|
|||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
|
|
||||||
class FilteredResult:
|
|
||||||
|
|
||||||
def __init__(self, result: List = None, total_count: int = 0):
|
|
||||||
self._result = [] if result is None else result
|
|
||||||
self._total_count = total_count
|
|
||||||
|
|
||||||
@property
|
|
||||||
def result(self) -> List:
|
|
||||||
return self._result
|
|
||||||
|
|
||||||
@result.setter
|
|
||||||
def result(self, value: List):
|
|
||||||
self._result = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def total_count(self) -> int:
|
|
||||||
return self._total_count
|
|
||||||
|
|
||||||
@total_count.setter
|
|
||||||
def total_count(self, value: int):
|
|
||||||
self._total_count = value
|
|
@ -1,58 +0,0 @@
|
|||||||
from bot_core.logging.database_logger import DatabaseLogger
|
|
||||||
from bot_data.abc.migration_abc import MigrationABC
|
|
||||||
from bot_data.db_context import DBContext
|
|
||||||
|
|
||||||
|
|
||||||
class ApiMigration(MigrationABC):
|
|
||||||
name = '0.3_ApiMigration'
|
|
||||||
|
|
||||||
def __init__(self, logger: DatabaseLogger, db: DBContext):
|
|
||||||
MigrationABC.__init__(self)
|
|
||||||
self._logger = logger
|
|
||||||
self._db = db
|
|
||||||
self._cursor = db.cursor
|
|
||||||
|
|
||||||
def upgrade(self):
|
|
||||||
self._logger.debug(__name__, 'Running upgrade')
|
|
||||||
|
|
||||||
self._cursor.execute(
|
|
||||||
str(f"""
|
|
||||||
CREATE TABLE IF NOT EXISTS `AuthUsers` (
|
|
||||||
`Id` BIGINT NOT NULL AUTO_INCREMENT,
|
|
||||||
`FirstName` VARCHAR(255),
|
|
||||||
`LastName` VARCHAR(255),
|
|
||||||
`EMail` VARCHAR(255),
|
|
||||||
`Password` VARCHAR(255),
|
|
||||||
`PasswordSalt` VARCHAR(255),
|
|
||||||
`RefreshToken` VARCHAR(255),
|
|
||||||
`ConfirmationId` VARCHAR(255) DEFAULT NULL,
|
|
||||||
`ForgotPasswordId` VARCHAR(255) DEFAULT NULL,
|
|
||||||
`OAuthId` VARCHAR(255) DEFAULT NULL,
|
|
||||||
`RefreshTokenExpiryTime` DATETIME(6) NOT NULL,
|
|
||||||
`AuthRole` INT NOT NULL DEFAULT 0,
|
|
||||||
`CreatedAt` DATETIME(6) NOT NULL,
|
|
||||||
`LastModifiedAt` DATETIME(6) NOT NULL,
|
|
||||||
PRIMARY KEY(`Id`)
|
|
||||||
);
|
|
||||||
""")
|
|
||||||
)
|
|
||||||
|
|
||||||
self._cursor.execute(
|
|
||||||
str(f"""
|
|
||||||
CREATE TABLE IF NOT EXISTS `AuthUserUsersRelations`(
|
|
||||||
`Id` BIGINT NOT NULL AUTO_INCREMENT,
|
|
||||||
`AuthUserId` BIGINT DEFAULT NULL,
|
|
||||||
`UserId` BIGINT DEFAULT NULL,
|
|
||||||
`CreatedAt` DATETIME(6) NOT NULL,
|
|
||||||
`LastModifiedAt` DATETIME(6) NOT NULL,
|
|
||||||
PRIMARY KEY(`Id`),
|
|
||||||
FOREIGN KEY (`AuthUserId`) REFERENCES `AuthUsers`(`Id`),
|
|
||||||
FOREIGN KEY (`UserId`) REFERENCES `Users`(`UserId`)
|
|
||||||
);
|
|
||||||
""")
|
|
||||||
)
|
|
||||||
|
|
||||||
def downgrade(self):
|
|
||||||
self._cursor.execute('DROP TABLE `AuthUsers`;')
|
|
||||||
self._cursor.execute('DROP TABLE `AuthUserUsersRelations`;')
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
|||||||
from bot_core.logging.database_logger import DatabaseLogger
|
|
||||||
from bot_data.abc.migration_abc import MigrationABC
|
|
||||||
from bot_data.db_context import DBContext
|
|
||||||
|
|
||||||
|
|
||||||
class AutoRoleFix1Migration(MigrationABC):
|
|
||||||
name = '0.3.0_AutoRoleMigration'
|
|
||||||
|
|
||||||
def __init__(self, logger: DatabaseLogger, db: DBContext):
|
|
||||||
MigrationABC.__init__(self)
|
|
||||||
self._logger = logger
|
|
||||||
self._db = db
|
|
||||||
self._cursor = db.cursor
|
|
||||||
|
|
||||||
def upgrade(self):
|
|
||||||
self._logger.debug(__name__, 'Running upgrade')
|
|
||||||
|
|
||||||
self._cursor.execute(
|
|
||||||
str(f"""
|
|
||||||
ALTER TABLE AutoRoles ADD DiscordChannelId BIGINT NOT NULL AFTER ServerId;
|
|
||||||
""")
|
|
||||||
)
|
|
||||||
|
|
||||||
def downgrade(self):
|
|
||||||
self._cursor.execute(
|
|
||||||
str(f"""
|
|
||||||
ALTER TABLE AutoRoles DROP COLUMN DiscordChannelId;
|
|
||||||
""")
|
|
||||||
)
|
|
@ -1,37 +0,0 @@
|
|||||||
from bot_core.logging.database_logger import DatabaseLogger
|
|
||||||
from bot_data.abc.migration_abc import MigrationABC
|
|
||||||
from bot_data.db_context import DBContext
|
|
||||||
|
|
||||||
|
|
||||||
class LevelMigration(MigrationABC):
|
|
||||||
name = '0.3_LevelMigration'
|
|
||||||
|
|
||||||
def __init__(self, logger: DatabaseLogger, db: DBContext):
|
|
||||||
MigrationABC.__init__(self)
|
|
||||||
self._logger = logger
|
|
||||||
self._db = db
|
|
||||||
self._cursor = db.cursor
|
|
||||||
|
|
||||||
def upgrade(self):
|
|
||||||
self._logger.debug(__name__, 'Running upgrade')
|
|
||||||
|
|
||||||
self._cursor.execute(
|
|
||||||
str(f"""
|
|
||||||
CREATE TABLE IF NOT EXISTS `Levels` (
|
|
||||||
`Id` BIGINT NOT NULL AUTO_INCREMENT,
|
|
||||||
`Name` VARCHAR(255) NOT NULL,
|
|
||||||
`Color` VARCHAR(8) NOT NULL,
|
|
||||||
`MinXp` BIGINT NOT NULL,
|
|
||||||
`PermissionInt` BIGINT NOT NULL,
|
|
||||||
`ServerId` BIGINT,
|
|
||||||
`CreatedAt` DATETIME(6),
|
|
||||||
`LastModifiedAt` DATETIME(6),
|
|
||||||
PRIMARY KEY(`Id`),
|
|
||||||
FOREIGN KEY (`ServerId`) REFERENCES `Servers`(`ServerId`)
|
|
||||||
);
|
|
||||||
""")
|
|
||||||
)
|
|
||||||
|
|
||||||
def downgrade(self):
|
|
||||||
self._cursor.execute('DROP TABLE `Levels`;')
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
|||||||
from bot_core.logging.database_logger import DatabaseLogger
|
|
||||||
from bot_data.abc.migration_abc import MigrationABC
|
|
||||||
from bot_data.db_context import DBContext
|
|
||||||
|
|
||||||
|
|
||||||
class StatsMigration(MigrationABC):
|
|
||||||
name = '0.3_StatsMigration'
|
|
||||||
|
|
||||||
def __init__(self, logger: DatabaseLogger, db: DBContext):
|
|
||||||
MigrationABC.__init__(self)
|
|
||||||
self._logger = logger
|
|
||||||
self._db = db
|
|
||||||
self._cursor = db.cursor
|
|
||||||
|
|
||||||
def upgrade(self):
|
|
||||||
self._logger.debug(__name__, 'Running upgrade')
|
|
||||||
|
|
||||||
self._cursor.execute(
|
|
||||||
str(f"""
|
|
||||||
CREATE TABLE IF NOT EXISTS `Statistics` (
|
|
||||||
`Id` BIGINT NOT NULL AUTO_INCREMENT,
|
|
||||||
`Name` VARCHAR(255) NOT NULL,
|
|
||||||
`Description` VARCHAR(255) NOT NULL,
|
|
||||||
`Code` LONGTEXT NOT NULL,
|
|
||||||
`ServerId` BIGINT,
|
|
||||||
`CreatedAt` DATETIME(6),
|
|
||||||
`LastModifiedAt` DATETIME(6),
|
|
||||||
PRIMARY KEY(`Id`),
|
|
||||||
FOREIGN KEY (`ServerId`) REFERENCES `Servers`(`ServerId`)
|
|
||||||
);
|
|
||||||
""")
|
|
||||||
)
|
|
||||||
|
|
||||||
def downgrade(self):
|
|
||||||
self._cursor.execute('DROP TABLE `Statistics`;')
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
|||||||
from enum import Enum
|
|
||||||
|
|
||||||
|
|
||||||
class AuthRoleEnum(Enum):
|
|
||||||
|
|
||||||
normal = 0
|
|
||||||
admin = 1
|
|
@ -1,254 +0,0 @@
|
|||||||
import uuid
|
|
||||||
from datetime import datetime
|
|
||||||
from typing import Optional
|
|
||||||
from cpl_core.database import TableABC
|
|
||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
|
||||||
from bot_data.model.server import Server
|
|
||||||
from bot_data.model.user import User
|
|
||||||
|
|
||||||
|
|
||||||
class AuthUser(TableABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
first_name: str,
|
|
||||||
last_name: str,
|
|
||||||
email: str,
|
|
||||||
password: str,
|
|
||||||
password_salt: Optional[str],
|
|
||||||
refresh_token: Optional[str],
|
|
||||||
confirmation_id: Optional[str],
|
|
||||||
forgot_password_id: Optional[str],
|
|
||||||
oauth_id: Optional[str],
|
|
||||||
refresh_token_expire_time: datetime,
|
|
||||||
auth_role: AuthRoleEnum,
|
|
||||||
created_at: datetime = None,
|
|
||||||
modified_at: datetime = None,
|
|
||||||
auth_user_id=0,
|
|
||||||
users: List[User] = None
|
|
||||||
):
|
|
||||||
self._auth_user_id = auth_user_id
|
|
||||||
self._first_name = first_name
|
|
||||||
self._last_name = last_name
|
|
||||||
self._email = email
|
|
||||||
self._password = password
|
|
||||||
self._password_salt = uuid.uuid4() if password_salt is None else password_salt
|
|
||||||
self._refresh_token = refresh_token
|
|
||||||
self._confirmation_id = confirmation_id
|
|
||||||
self._oauth_id = oauth_id
|
|
||||||
self._forgot_password_id = forgot_password_id
|
|
||||||
self._refresh_token_expire_time = refresh_token_expire_time
|
|
||||||
|
|
||||||
if users is None:
|
|
||||||
self._users = List(User)
|
|
||||||
|
|
||||||
self._auth_role_id = auth_role
|
|
||||||
|
|
||||||
TableABC.__init__(self)
|
|
||||||
self._created_at = created_at if created_at is not None else self._created_at
|
|
||||||
self._modified_at = modified_at if modified_at is not None else self._modified_at
|
|
||||||
|
|
||||||
@property
|
|
||||||
def id(self) -> int:
|
|
||||||
return self._auth_user_id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def first_name(self) -> str:
|
|
||||||
return self._first_name
|
|
||||||
|
|
||||||
@first_name.setter
|
|
||||||
def first_name(self, value: str):
|
|
||||||
self._first_name = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def last_name(self) -> str:
|
|
||||||
return self._last_name
|
|
||||||
|
|
||||||
@last_name.setter
|
|
||||||
def last_name(self, value: str):
|
|
||||||
self._last_name = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def email(self) -> str:
|
|
||||||
return self._email
|
|
||||||
|
|
||||||
@email.setter
|
|
||||||
def email(self, value: str):
|
|
||||||
self._email = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def password(self) -> str:
|
|
||||||
return self._password
|
|
||||||
|
|
||||||
@password.setter
|
|
||||||
def password(self, value: str):
|
|
||||||
self._password = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def password_salt(self) -> str:
|
|
||||||
return self._password_salt
|
|
||||||
|
|
||||||
@password_salt.setter
|
|
||||||
def password_salt(self, value: str):
|
|
||||||
self._password_salt = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def refresh_token(self) -> Optional[str]:
|
|
||||||
return self._refresh_token
|
|
||||||
|
|
||||||
@refresh_token.setter
|
|
||||||
def refresh_token(self, value: Optional[str]):
|
|
||||||
self._refresh_token = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def confirmation_id(self) -> Optional[str]:
|
|
||||||
return self._confirmation_id
|
|
||||||
|
|
||||||
@confirmation_id.setter
|
|
||||||
def confirmation_id(self, value: Optional[str]):
|
|
||||||
self._confirmation_id = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def forgot_password_id(self) -> Optional[str]:
|
|
||||||
return self._forgot_password_id
|
|
||||||
|
|
||||||
@forgot_password_id.setter
|
|
||||||
def forgot_password_id(self, value: Optional[str]):
|
|
||||||
self._forgot_password_id = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def oauth_id(self) -> Optional[str]:
|
|
||||||
return self._oauth_id
|
|
||||||
|
|
||||||
@oauth_id.setter
|
|
||||||
def oauth_id(self, value: Optional[str]):
|
|
||||||
self._oauth_id = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def refresh_token_expire_time(self) -> datetime:
|
|
||||||
return self._refresh_token_expire_time
|
|
||||||
|
|
||||||
@refresh_token_expire_time.setter
|
|
||||||
def refresh_token_expire_time(self, value: datetime):
|
|
||||||
self._refresh_token_expire_time = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def auth_role(self) -> AuthRoleEnum:
|
|
||||||
return self._auth_role_id
|
|
||||||
|
|
||||||
@auth_role.setter
|
|
||||||
def auth_role(self, value: AuthRoleEnum):
|
|
||||||
self._auth_role_id = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def users(self) -> List[User]:
|
|
||||||
return self._users
|
|
||||||
|
|
||||||
@users.setter
|
|
||||||
def users(self, value: List[User]):
|
|
||||||
self._users = value
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_all_string() -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `AuthUsers`;
|
|
||||||
""")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_by_id_string(id: int) -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `AuthUsers`
|
|
||||||
WHERE `Id` = {id};
|
|
||||||
""")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_by_email_string(email: str) -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `AuthUsers`
|
|
||||||
WHERE `EMail` = '{email}';
|
|
||||||
""")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_by_confirmation_id_string(id: str) -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `AuthUsers`
|
|
||||||
WHERE `ConfirmationId` = '{id}';
|
|
||||||
""")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_by_forgot_password_id_string(id: str) -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `AuthUsers`
|
|
||||||
WHERE `ForgotPasswordId` = '{id}';
|
|
||||||
""")
|
|
||||||
|
|
||||||
def get_select_user_id_from_relations(self) -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT `UserId`
|
|
||||||
FROM `AuthUserUsersRelations`
|
|
||||||
WHERE `AuthUserId` = {self._auth_user_id};
|
|
||||||
""")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def insert_string(self) -> str:
|
|
||||||
return str(f"""
|
|
||||||
INSERT INTO `AuthUsers` (
|
|
||||||
`Id`,
|
|
||||||
`FirstName`,
|
|
||||||
`LastName`,
|
|
||||||
`EMail`,
|
|
||||||
`Password`,
|
|
||||||
`PasswordSalt`,
|
|
||||||
`RefreshToken`,
|
|
||||||
`ConfirmationId`,
|
|
||||||
`ForgotPasswordId`,
|
|
||||||
`OAuthId`,
|
|
||||||
`RefreshTokenExpiryTime`,
|
|
||||||
`AuthRole`,
|
|
||||||
`CreatedAt`,
|
|
||||||
`LastModifiedAt`
|
|
||||||
) VALUES (
|
|
||||||
{self._auth_user_id},
|
|
||||||
'{self._first_name}',
|
|
||||||
'{self._last_name}',
|
|
||||||
'{self._email}',
|
|
||||||
'{self._password}',
|
|
||||||
'{self._password_salt}',
|
|
||||||
'{"NULL" if self._refresh_token is None else self._refresh_token}',
|
|
||||||
'{"NULL" if self._confirmation_id is None else self._confirmation_id}',
|
|
||||||
'{"NULL" if self._forgot_password_id is None else self._forgot_password_id}',
|
|
||||||
'{"NULL" if self._oauth_id is None else self._oauth_id}',
|
|
||||||
'{self._refresh_token_expire_time.isoformat()}',
|
|
||||||
{self._auth_role_id.value},
|
|
||||||
'{self._created_at}',
|
|
||||||
'{self._modified_at}'
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def udpate_string(self) -> str:
|
|
||||||
return str(f"""
|
|
||||||
UPDATE `AuthUsers`
|
|
||||||
SET `FirstName` = '{self._first_name}',
|
|
||||||
`LastName` = '{self._last_name}',
|
|
||||||
`EMail` = '{self._email}',
|
|
||||||
`Password` = '{self._password}',
|
|
||||||
`PasswordSalt` = '{self._password_salt}',
|
|
||||||
`RefreshToken` = '{"NULL" if self._refresh_token is None else self._refresh_token}',
|
|
||||||
`ConfirmationId` = '{"NULL" if self._confirmation_id is None else self._confirmation_id}',
|
|
||||||
`ForgotPasswordId` = '{"NULL" if self._forgot_password_id is None else self._forgot_password_id}',
|
|
||||||
`OAuthId` = '{"NULL" if self._oauth_id is None else self._oauth_id}',
|
|
||||||
`RefreshTokenExpiryTime` = '{self._refresh_token_expire_time.isoformat()}',
|
|
||||||
`AuthRole` = {self._auth_role_id.value},
|
|
||||||
`LastModifiedAt` = '{self._modified_at}'
|
|
||||||
WHERE `AuthUsers`.`Id` = {self._auth_user_id};
|
|
||||||
""")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def delete_string(self) -> str:
|
|
||||||
return str(f"""
|
|
||||||
DELETE FROM `AuthUsers`
|
|
||||||
WHERE `Id` = {self._auth_user_id};
|
|
||||||
""")
|
|
@ -1,85 +0,0 @@
|
|||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from cpl_core.database import TableABC
|
|
||||||
|
|
||||||
from bot_data.model.auth_user import AuthUser
|
|
||||||
from bot_data.model.user import User
|
|
||||||
|
|
||||||
|
|
||||||
class AuthUserUsersRelation(TableABC):
|
|
||||||
|
|
||||||
def __init__(self, auth_user: AuthUser, user: User, created_at: datetime = None, modified_at: datetime = None):
|
|
||||||
self._auth_user = auth_user
|
|
||||||
self._user = user
|
|
||||||
|
|
||||||
TableABC.__init__(self)
|
|
||||||
self._created_at = created_at if created_at is not None else self._created_at
|
|
||||||
self._modified_at = modified_at if modified_at is not None else self._modified_at
|
|
||||||
|
|
||||||
@property
|
|
||||||
def auth_user(self) -> AuthUser:
|
|
||||||
return self._auth_user
|
|
||||||
|
|
||||||
@auth_user.setter
|
|
||||||
def auth_user(self, value: AuthUser):
|
|
||||||
self._auth_user = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def user(self) -> User:
|
|
||||||
return self._user
|
|
||||||
|
|
||||||
@user.setter
|
|
||||||
def user(self, value: User):
|
|
||||||
self._user = value
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_all_string() -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `AuthUserUsersRelations`;
|
|
||||||
""")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_by_auth_user_id_string(id: int) -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `AuthUserUsersRelations`
|
|
||||||
WHERE `AuthUserId` = {id};
|
|
||||||
""")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_by_user_id_string(id: int) -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `AuthUserUsersRelations`
|
|
||||||
WHERE `UserId` = {id};
|
|
||||||
""")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def insert_string(self) -> str:
|
|
||||||
return str(f"""
|
|
||||||
INSERT INTO `AuthUserUsersRelations` (
|
|
||||||
`AuthUserId`, `UserId`, `CreatedAt`, `LastModifiedAt`
|
|
||||||
) VALUES (
|
|
||||||
{self._auth_user.id},
|
|
||||||
{self._user.user_id},
|
|
||||||
'{self._created_at}',
|
|
||||||
'{self._modified_at}'
|
|
||||||
);
|
|
||||||
""")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def udpate_string(self) -> str:
|
|
||||||
return str(f"""
|
|
||||||
UPDATE `AuthUserUsersRelations`
|
|
||||||
SET `AuthUserId` = '{self._auth_user.id}',,
|
|
||||||
`UserId` = '{self._user.user_id}'
|
|
||||||
`LastModifiedAt` = '{self._modified_at}'
|
|
||||||
WHERE `AuthUserId` = {self._auth_user.id}
|
|
||||||
AND `UserId` = {self._user.user_id};
|
|
||||||
""")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def delete_string(self) -> str:
|
|
||||||
return str(f"""
|
|
||||||
DELETE FROM `AuthUserUsersRelations`
|
|
||||||
WHERE `AuthUserId` = {self._auth_user.id}
|
|
||||||
AND `UserId` = {self._user.user_id};
|
|
||||||
""")
|
|
@ -1,119 +0,0 @@
|
|||||||
from datetime import datetime
|
|
||||||
from typing import Optional
|
|
||||||
from cpl_core.database import TableABC
|
|
||||||
|
|
||||||
from bot_data.model.server import Server
|
|
||||||
|
|
||||||
|
|
||||||
class Level(TableABC):
|
|
||||||
|
|
||||||
def __init__(self, name: str, color: str, min_xp: int, permissions: int, server: Optional[Server], created_at: datetime = None, modified_at: datetime = None, id=0):
|
|
||||||
self._id = id
|
|
||||||
self._name = name
|
|
||||||
self._color = color
|
|
||||||
self._min_xp = min_xp
|
|
||||||
self._permissions = permissions
|
|
||||||
self._server = server
|
|
||||||
|
|
||||||
TableABC.__init__(self)
|
|
||||||
self._created_at = created_at if created_at is not None else self._created_at
|
|
||||||
self._modified_at = modified_at if modified_at is not None else self._modified_at
|
|
||||||
|
|
||||||
@property
|
|
||||||
def id(self) -> int:
|
|
||||||
return self._id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self) -> str:
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@name.setter
|
|
||||||
def name(self, value: str):
|
|
||||||
self._name = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def color(self) -> str:
|
|
||||||
return self._color
|
|
||||||
|
|
||||||
@color.setter
|
|
||||||
def color(self, value: str):
|
|
||||||
self._color = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def min_xp(self) -> int:
|
|
||||||
return self._min_xp
|
|
||||||
|
|
||||||
@min_xp.setter
|
|
||||||
def min_xp(self, value: int):
|
|
||||||
self._min_xp = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def permissions(self) -> int:
|
|
||||||
return self._permissions
|
|
||||||
|
|
||||||
@permissions.setter
|
|
||||||
def permissions(self, value: int):
|
|
||||||
self._permissions = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def server(self) -> Server:
|
|
||||||
return self._server
|
|
||||||
|
|
||||||
@server.setter
|
|
||||||
def server(self, value: Server):
|
|
||||||
self._server = value
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_all_string() -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `Levels`;
|
|
||||||
""")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_by_id_string(id: int) -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `Levels`
|
|
||||||
WHERE `Id` = {id};
|
|
||||||
""")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_by_server_id_string(s_id: int) -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `Levels`
|
|
||||||
WHERE `ServerId` = {s_id};
|
|
||||||
""")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def insert_string(self) -> str:
|
|
||||||
return str(f"""
|
|
||||||
INSERT INTO `Levels` (
|
|
||||||
`Name`, `Color`, `MinXp`, `PermissionInt`, `ServerId`, `CreatedAt`, `LastModifiedAt`
|
|
||||||
) VALUES (
|
|
||||||
'{self._name}',
|
|
||||||
'{self._color}',
|
|
||||||
{self._min_xp},
|
|
||||||
{self._permissions},
|
|
||||||
{self._server.server_id},
|
|
||||||
'{self._created_at}',
|
|
||||||
'{self._modified_at}'
|
|
||||||
);
|
|
||||||
""")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def udpate_string(self) -> str:
|
|
||||||
return str(f"""
|
|
||||||
UPDATE `Levels`
|
|
||||||
SET `Name` = '{self._name}',
|
|
||||||
`Color` = '{self._color}',
|
|
||||||
`MinXp` = {self._min_xp},
|
|
||||||
`PermissionInt` = {self._permissions},
|
|
||||||
`LastModifiedAt` = '{self._modified_at}'
|
|
||||||
WHERE `Id` = {self._id};
|
|
||||||
""")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def delete_string(self) -> str:
|
|
||||||
return str(f"""
|
|
||||||
DELETE FROM `Levels`
|
|
||||||
WHERE `Id` = {self._id};
|
|
||||||
""")
|
|
@ -1,109 +0,0 @@
|
|||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from cpl_core.database import TableABC
|
|
||||||
from cpl_core.utils import CredentialManager
|
|
||||||
|
|
||||||
from bot_data.model.server import Server
|
|
||||||
|
|
||||||
|
|
||||||
class Statistic(TableABC):
|
|
||||||
|
|
||||||
def __init__(self, name: str, description: str, code: str, server: Server, created_at: datetime=None, modified_at: datetime=None, id=0):
|
|
||||||
self._id = id
|
|
||||||
self._name = name
|
|
||||||
self._description = description
|
|
||||||
self._code = CredentialManager.encrypt(code)
|
|
||||||
self._server = server
|
|
||||||
|
|
||||||
TableABC.__init__(self)
|
|
||||||
self._created_at = created_at if created_at is not None else self._created_at
|
|
||||||
self._modified_at = modified_at if modified_at is not None else self._modified_at
|
|
||||||
|
|
||||||
@property
|
|
||||||
def id(self) -> int:
|
|
||||||
return self._id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self) -> str:
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def description(self) -> str:
|
|
||||||
return self._description
|
|
||||||
|
|
||||||
@description.setter
|
|
||||||
def description(self, value: str):
|
|
||||||
self._description = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def code(self) -> str:
|
|
||||||
return CredentialManager.decrypt(self._code)
|
|
||||||
|
|
||||||
@code.setter
|
|
||||||
def code(self, value: str):
|
|
||||||
self._code = CredentialManager.encrypt(value)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def server(self) -> Server:
|
|
||||||
return self._server
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_all_string() -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `Statistics`;
|
|
||||||
""")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_by_id_string(id: int) -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `Statistics`
|
|
||||||
WHERE `Id` = {id};
|
|
||||||
""")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_by_name_string(name: str, s_id: int) -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `Statistics`
|
|
||||||
WHERE `ServerId` = {s_id}
|
|
||||||
AND `Name` = '{name}';
|
|
||||||
""")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_select_by_server_string(s_id: int) -> str:
|
|
||||||
return str(f"""
|
|
||||||
SELECT * FROM `Statistics`
|
|
||||||
WHERE `ServerId` = {s_id};
|
|
||||||
""")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def insert_string(self) -> str:
|
|
||||||
return str(f"""
|
|
||||||
INSERT INTO `Statistics` (
|
|
||||||
`Name`, `Description`, `Code`, `ServerId`, `CreatedAt`, `LastModifiedAt`
|
|
||||||
) VALUES (
|
|
||||||
'{self._name}',
|
|
||||||
'{self._description}',
|
|
||||||
'{self._code}',
|
|
||||||
{self._server.server_id},
|
|
||||||
'{self._created_at}',
|
|
||||||
'{self._modified_at}'
|
|
||||||
);
|
|
||||||
""")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def udpate_string(self) -> str:
|
|
||||||
return str(f"""
|
|
||||||
UPDATE `Statistics`
|
|
||||||
SET `Name` = '{self._name}',
|
|
||||||
`Description` = '{self._description}',
|
|
||||||
`Code` = '{self._code}',
|
|
||||||
`LastModifiedAt` = '{self._modified_at}'
|
|
||||||
WHERE `Id` = {self._id};
|
|
||||||
""")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def delete_string(self) -> str:
|
|
||||||
return str(f"""
|
|
||||||
DELETE FROM `Statistics`
|
|
||||||
WHERE `Id` = {self._id};
|
|
||||||
""")
|
|
@ -1,160 +0,0 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
from cpl_core.database.context import DatabaseContextABC
|
|
||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria
|
|
||||||
from bot_core.logging.database_logger import DatabaseLogger
|
|
||||||
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
|
|
||||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
|
||||||
from bot_data.filtered_result import FilteredResult
|
|
||||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
|
||||||
from bot_data.model.auth_user import AuthUser
|
|
||||||
from bot_data.model.auth_user_users_relation import AuthUserUsersRelation
|
|
||||||
from bot_data.model.user import User
|
|
||||||
|
|
||||||
|
|
||||||
class AuthUserRepositoryService(AuthUserRepositoryABC):
|
|
||||||
|
|
||||||
def __init__(self, logger: DatabaseLogger, db_context: DatabaseContextABC, users: UserRepositoryABC):
|
|
||||||
self._logger = logger
|
|
||||||
self._context = db_context
|
|
||||||
self._users = users
|
|
||||||
|
|
||||||
AuthUserRepositoryABC.__init__(self)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_value_from_result(value: any) -> Optional[any]:
|
|
||||||
if isinstance(value, str) and 'NULL' in value:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return value
|
|
||||||
|
|
||||||
def _user_from_result(self, au_result: tuple) -> AuthUser:
|
|
||||||
auth_user = AuthUser(
|
|
||||||
self._get_value_from_result(au_result[1]),
|
|
||||||
self._get_value_from_result(au_result[2]),
|
|
||||||
self._get_value_from_result(au_result[3]),
|
|
||||||
self._get_value_from_result(au_result[4]),
|
|
||||||
self._get_value_from_result(au_result[5]),
|
|
||||||
self._get_value_from_result(au_result[6]),
|
|
||||||
self._get_value_from_result(au_result[7]),
|
|
||||||
self._get_value_from_result(au_result[8]),
|
|
||||||
self._get_value_from_result(au_result[9]),
|
|
||||||
self._get_value_from_result(au_result[10]),
|
|
||||||
AuthRoleEnum(self._get_value_from_result(au_result[11])),
|
|
||||||
auth_user_id=self._get_value_from_result(au_result[0])
|
|
||||||
)
|
|
||||||
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {auth_user.get_select_user_id_from_relations()}')
|
|
||||||
results = self._context.select(auth_user.get_select_user_id_from_relations())
|
|
||||||
for result in results:
|
|
||||||
user_id = self._get_value_from_result(result[0])
|
|
||||||
if user_id is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
user = self._users.get_user_by_id(user_id)
|
|
||||||
auth_user.users.append(user)
|
|
||||||
|
|
||||||
return auth_user
|
|
||||||
|
|
||||||
def get_all_auth_users(self) -> List[AuthUser]:
|
|
||||||
users = List(AuthUser)
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_all_string()}')
|
|
||||||
results = self._context.select(AuthUser.get_select_all_string())
|
|
||||||
for result in results:
|
|
||||||
self._logger.trace(__name__, f'Get auth user with id {result[0]}')
|
|
||||||
users.append(self._user_from_result(result))
|
|
||||||
|
|
||||||
return users
|
|
||||||
|
|
||||||
def get_filtered_auth_users(self, criteria: AuthUserSelectCriteria) -> FilteredResult:
|
|
||||||
users = self.get_all_auth_users()
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_all_string()}')
|
|
||||||
query = users
|
|
||||||
|
|
||||||
if criteria.first_name is not None and criteria.first_name != '':
|
|
||||||
query = query.where(lambda x: criteria.first_name in x.first_name or x.first_name == criteria.first_name)
|
|
||||||
|
|
||||||
if criteria.last_name is not None and criteria.last_name != '':
|
|
||||||
query = query.where(lambda x: criteria.last_name in x.last_name or x.last_name == criteria.last_name)
|
|
||||||
|
|
||||||
if criteria.email is not None and criteria.email != '':
|
|
||||||
query = query.where(lambda x: criteria.email in x.email or x.email == criteria.email)
|
|
||||||
|
|
||||||
if criteria.auth_role is not None:
|
|
||||||
query = query.where(lambda x: x.auth_role == AuthRoleEnum(criteria.auth_role))
|
|
||||||
|
|
||||||
# sort
|
|
||||||
if criteria.sort_column is not None and criteria.sort_column != '' and criteria.sort_direction is not None and criteria.sort_direction:
|
|
||||||
crit_sort_direction = criteria.sort_direction.lower()
|
|
||||||
if crit_sort_direction == "desc" or crit_sort_direction == "descending":
|
|
||||||
query = query.order_by_descending(lambda x: getattr(x, criteria.sort_column))
|
|
||||||
else:
|
|
||||||
query = query.order_by(lambda x: getattr(x, criteria.sort_column))
|
|
||||||
|
|
||||||
result = FilteredResult()
|
|
||||||
result.total_count = query.count()
|
|
||||||
skip = criteria.page_size * criteria.page_index
|
|
||||||
result.result = query.skip(skip).take(criteria.page_size)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def get_auth_user_by_email(self, email: str) -> AuthUser:
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_email_string(email)}')
|
|
||||||
result = self._context.select(AuthUser.get_select_by_email_string(email))[0]
|
|
||||||
return self._user_from_result(result)
|
|
||||||
|
|
||||||
def find_auth_user_by_email(self, email: str) -> Optional[AuthUser]:
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_email_string(email)}')
|
|
||||||
result = self._context.select(AuthUser.get_select_by_email_string(email))
|
|
||||||
if result is None or len(result) == 0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
result = result[0]
|
|
||||||
|
|
||||||
return self._user_from_result(result)
|
|
||||||
|
|
||||||
def find_auth_user_by_confirmation_id(self, id: str) -> Optional[AuthUser]:
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_confirmation_id_string(id)}')
|
|
||||||
result = self._context.select(AuthUser.get_select_by_confirmation_id_string(id))
|
|
||||||
if result is None or len(result) == 0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
result = result[0]
|
|
||||||
|
|
||||||
return self._user_from_result(result)
|
|
||||||
|
|
||||||
def find_auth_user_by_forgot_password_id(self, id: str) -> Optional[AuthUser]:
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_forgot_password_id_string(id)}')
|
|
||||||
result = self._context.select(AuthUser.get_select_by_forgot_password_id_string(id))
|
|
||||||
if result is None or len(result) == 0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
result = result[0]
|
|
||||||
|
|
||||||
return self._user_from_result(result)
|
|
||||||
|
|
||||||
def add_auth_user(self, user: AuthUser):
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {user.insert_string}')
|
|
||||||
self._context.cursor.execute(user.insert_string)
|
|
||||||
|
|
||||||
def update_auth_user(self, user: AuthUser):
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {user.udpate_string}')
|
|
||||||
self._context.cursor.execute(user.udpate_string)
|
|
||||||
|
|
||||||
def delete_auth_user(self, user: AuthUser):
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {user.delete_string}')
|
|
||||||
self._context.cursor.execute(user.delete_string)
|
|
||||||
|
|
||||||
def add_auth_user_user_rel(self, rel: AuthUserUsersRelation):
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {rel.insert_string}')
|
|
||||||
self._context.cursor.execute(rel.insert_string)
|
|
||||||
|
|
||||||
def update_auth_user_user_rel(self, rel: AuthUserUsersRelation):
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {rel.udpate_string}')
|
|
||||||
self._context.cursor.execute(rel.udpate_string)
|
|
||||||
|
|
||||||
def delete_auth_user_user_rel(self, rel: AuthUserUsersRelation):
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {rel.delete_string}')
|
|
||||||
self._context.cursor.execute(rel.delete_string)
|
|
@ -1,97 +0,0 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
from cpl_core.database.context import DatabaseContextABC
|
|
||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
from bot_core.logging.database_logger import DatabaseLogger
|
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
|
||||||
from bot_data.abc.level_repository_abc import LevelRepositoryABC
|
|
||||||
from bot_data.model.level import Level
|
|
||||||
|
|
||||||
|
|
||||||
class LevelRepositoryService(LevelRepositoryABC):
|
|
||||||
|
|
||||||
def __init__(self, logger: DatabaseLogger, db_context: DatabaseContextABC, servers: ServerRepositoryABC):
|
|
||||||
self._logger = logger
|
|
||||||
self._context = db_context
|
|
||||||
|
|
||||||
self._servers = servers
|
|
||||||
|
|
||||||
LevelRepositoryABC.__init__(self)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_value_from_result(value: any) -> Optional[any]:
|
|
||||||
if isinstance(value, str) and 'NULL' in value:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return value
|
|
||||||
|
|
||||||
def _level_from_result(self, sql_result: tuple) -> Level:
|
|
||||||
return Level(
|
|
||||||
self._get_value_from_result(sql_result[1]), # name
|
|
||||||
self._get_value_from_result(sql_result[2]), # color
|
|
||||||
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
|
|
||||||
id=self._get_value_from_result(sql_result[0]) # id
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_levels(self) -> List[Level]:
|
|
||||||
levels = List(Level)
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {Level.get_select_all_string()}')
|
|
||||||
results = self._context.select(Level.get_select_all_string())
|
|
||||||
for result in results:
|
|
||||||
self._logger.trace(__name__, f'Get level with id {result[0]}')
|
|
||||||
levels.append(self._level_from_result(result))
|
|
||||||
|
|
||||||
return levels
|
|
||||||
|
|
||||||
def get_level_by_id(self, id: int) -> Level:
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {Level.get_select_by_id_string(id)}')
|
|
||||||
result = self._context.select(Level.get_select_by_id_string(id))[0]
|
|
||||||
|
|
||||||
return self._level_from_result(result)
|
|
||||||
|
|
||||||
def find_level_by_id(self, id: int) -> Optional[Level]:
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {Level.get_select_by_id_string(id)}')
|
|
||||||
result = self._context.select(Level.get_select_by_id_string(id))
|
|
||||||
if result is None or len(result) == 0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return self._level_from_result(result[0])
|
|
||||||
|
|
||||||
def get_levels_by_server_id(self, server_id: int) -> List[Level]:
|
|
||||||
levels = List(Level)
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {Level.get_select_by_server_id_string(server_id)}')
|
|
||||||
results = self._context.select(Level.get_select_by_server_id_string(server_id))
|
|
||||||
|
|
||||||
for result in results:
|
|
||||||
self._logger.trace(__name__, f'Get level with id {result[0]}')
|
|
||||||
levels.append(self._level_from_result(result))
|
|
||||||
|
|
||||||
return levels
|
|
||||||
|
|
||||||
def find_levels_by_server_id(self, server_id: int) -> Optional[List[Level]]:
|
|
||||||
levels = List(Level)
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {Level.get_select_by_server_id_string(server_id)}')
|
|
||||||
results = self._context.select(Level.get_select_by_server_id_string(server_id))
|
|
||||||
if results is None or len(results) == 0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
for result in results:
|
|
||||||
self._logger.trace(__name__, f'Get level with id {result[0]}')
|
|
||||||
levels.append(self._level_from_result(result))
|
|
||||||
|
|
||||||
return levels
|
|
||||||
|
|
||||||
def add_level(self, level: Level):
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {level.insert_string}')
|
|
||||||
self._context.cursor.execute(level.insert_string)
|
|
||||||
|
|
||||||
def update_level(self, level: Level):
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {level.udpate_string}')
|
|
||||||
self._context.cursor.execute(level.udpate_string)
|
|
||||||
|
|
||||||
def delete_level(self, level: Level):
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {level.delete_string}')
|
|
||||||
self._context.cursor.execute(level.delete_string)
|
|
@ -1,25 +0,0 @@
|
|||||||
from cpl_core.database.context import DatabaseContextABC
|
|
||||||
from cpl_core.dependency_injection import ServiceProviderABC
|
|
||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
from bot_core.logging.database_logger import DatabaseLogger
|
|
||||||
from bot_data.abc.data_seeder_abc import DataSeederABC
|
|
||||||
|
|
||||||
|
|
||||||
class SeederService:
|
|
||||||
|
|
||||||
def __init__(self, logger: DatabaseLogger, services: ServiceProviderABC, db: DatabaseContextABC):
|
|
||||||
self._logger = logger
|
|
||||||
self._services = services
|
|
||||||
|
|
||||||
self._db = db
|
|
||||||
|
|
||||||
self._seeder = List(type, DataSeederABC.__subclasses__())
|
|
||||||
|
|
||||||
async def seed(self):
|
|
||||||
self._logger.info(__name__, f"Seed data")
|
|
||||||
for seeder in self._seeder:
|
|
||||||
seeder_as_service: DataSeederABC = self._services.get_service(seeder)
|
|
||||||
self._logger.debug(__name__, f"Starting seeder {seeder.__name__}")
|
|
||||||
await seeder_as_service.seed()
|
|
||||||
self._db.save_changes()
|
|
@ -1,93 +0,0 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
from cpl_core.database.context import DatabaseContextABC
|
|
||||||
from cpl_core.utils import CredentialManager
|
|
||||||
from cpl_query.extension import List
|
|
||||||
|
|
||||||
from bot_core.logging.database_logger import DatabaseLogger
|
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
|
||||||
from bot_data.abc.statistic_repository_abc import StatisticRepositoryABC
|
|
||||||
from bot_data.model.statistic import Statistic
|
|
||||||
|
|
||||||
|
|
||||||
class StatisticRepositoryService(StatisticRepositoryABC):
|
|
||||||
|
|
||||||
def __init__(self, logger: DatabaseLogger, db_context: DatabaseContextABC, statistics: ServerRepositoryABC):
|
|
||||||
self._logger = logger
|
|
||||||
self._context = db_context
|
|
||||||
|
|
||||||
self._statistics = statistics
|
|
||||||
|
|
||||||
StatisticRepositoryABC.__init__(self)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_value_from_result(value: any) -> Optional[any]:
|
|
||||||
if isinstance(value, str) and 'NULL' in value:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return value
|
|
||||||
|
|
||||||
def _statistic_from_result(self, sql_result: tuple) -> Statistic:
|
|
||||||
code = self._get_value_from_result(sql_result[3])
|
|
||||||
if code is not None:
|
|
||||||
code = CredentialManager.decrypt(code)
|
|
||||||
|
|
||||||
statistic = Statistic(
|
|
||||||
self._get_value_from_result(sql_result[1]),
|
|
||||||
self._get_value_from_result(sql_result[2]),
|
|
||||||
code,
|
|
||||||
self._statistics.get_server_by_id(sql_result[4]),
|
|
||||||
id=self._get_value_from_result(sql_result[0])
|
|
||||||
)
|
|
||||||
|
|
||||||
return statistic
|
|
||||||
|
|
||||||
def get_statistics(self) -> List[Statistic]:
|
|
||||||
statistics = List(Statistic)
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {Statistic.get_select_all_string()}')
|
|
||||||
results = self._context.select(Statistic.get_select_all_string())
|
|
||||||
for result in results:
|
|
||||||
statistics.append(self._statistic_from_result(result))
|
|
||||||
|
|
||||||
return statistics
|
|
||||||
|
|
||||||
def get_statistics_by_server_id(self, server_id: int) -> List[Statistic]:
|
|
||||||
statistics = List(Statistic)
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {Statistic.get_select_by_server_string(server_id)}')
|
|
||||||
results = self._context.select(Statistic.get_select_by_server_string(server_id))
|
|
||||||
for result in results:
|
|
||||||
statistics.append(self._statistic_from_result(result))
|
|
||||||
|
|
||||||
return statistics
|
|
||||||
|
|
||||||
def get_statistic_by_id(self, id: int) -> Statistic:
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {Statistic.get_select_by_id_string(id)}')
|
|
||||||
result = self._context.select(Statistic.get_select_by_id_string(id))[0]
|
|
||||||
return self._statistic_from_result(result)
|
|
||||||
|
|
||||||
def get_statistic_by_name(self, name: str, server_id: int) -> Statistic:
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {Statistic.get_select_by_name_string(name, server_id)}')
|
|
||||||
result = self._context.select(Statistic.get_select_by_name_string(name, server_id))[0]
|
|
||||||
return self._statistic_from_result(result)
|
|
||||||
|
|
||||||
def find_statistic_by_name(self, name: str, server_id: int) -> Optional[Statistic]:
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {Statistic.get_select_by_name_string(name, server_id)}')
|
|
||||||
result = self._context.select(Statistic.get_select_by_name_string(name, server_id))
|
|
||||||
if result is None or len(result) == 0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
result = result[0]
|
|
||||||
|
|
||||||
return self._statistic_from_result(result)
|
|
||||||
|
|
||||||
def add_statistic(self, statistic: Statistic):
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {statistic.insert_string}')
|
|
||||||
self._context.cursor.execute(statistic.insert_string)
|
|
||||||
|
|
||||||
def update_statistic(self, statistic: Statistic):
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {statistic.udpate_string}')
|
|
||||||
self._context.cursor.execute(statistic.udpate_string)
|
|
||||||
|
|
||||||
def delete_statistic(self, statistic: Statistic):
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {statistic.delete_string}')
|
|
||||||
self._context.cursor.execute(statistic.delete_string)
|
|
@ -1,54 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
|
|
||||||
import discord
|
|
||||||
from cpl_discord.command import DiscordCommandABC
|
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
from discord.ext import commands
|
|
||||||
from discord.ext.commands import Context
|
|
||||||
|
|
||||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
|
||||||
from bot_core.helper.command_checks import CommandChecks
|
|
||||||
from bot_core.logging.command_logger import CommandLogger
|
|
||||||
from bot_core.service.client_utils_service import ClientUtilsService
|
|
||||||
|
|
||||||
|
|
||||||
class MassMoveCommand(DiscordCommandABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
logger: CommandLogger,
|
|
||||||
message_service: MessageServiceABC,
|
|
||||||
bot: DiscordBotServiceABC,
|
|
||||||
translate: TranslatePipe,
|
|
||||||
client_utils: ClientUtilsService
|
|
||||||
):
|
|
||||||
DiscordCommandABC.__init__(self)
|
|
||||||
self._logger = logger
|
|
||||||
self._message_service = message_service
|
|
||||||
self._bot = bot
|
|
||||||
self._t = translate
|
|
||||||
self._client_utils = client_utils
|
|
||||||
|
|
||||||
@commands.hybrid_command(name='mass-move')
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
@CommandChecks.check_is_member_moderator()
|
|
||||||
async def mass_move(self, ctx: Context, channel_to: discord.VoiceChannel,
|
|
||||||
channel_from: discord.VoiceChannel = None):
|
|
||||||
self._logger.debug(__name__, f'Received command mass-move {ctx}')
|
|
||||||
|
|
||||||
if channel_from is None and ctx.author.voice is None:
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.base.mass_move.channel_from_error'))
|
|
||||||
return
|
|
||||||
|
|
||||||
if channel_from is None:
|
|
||||||
channel_from = ctx.author.voice.channel
|
|
||||||
|
|
||||||
moves = [member.move_to(channel_to) for member in channel_from.members]
|
|
||||||
move_count = len(moves)
|
|
||||||
await asyncio.gather(*moves)
|
|
||||||
self._client_utils.moved_users(ctx.guild.id, move_count)
|
|
||||||
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.base.mass_move.moved').format(channel_from.mention, channel_to.mention))
|
|
||||||
|
|
||||||
self._logger.trace(__name__, f'Finished mass-move command')
|
|
@ -1,68 +0,0 @@
|
|||||||
import discord
|
|
||||||
from cpl_discord.command import DiscordCommandABC
|
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
from discord.ext import commands
|
|
||||||
from discord.ext.commands import Context
|
|
||||||
|
|
||||||
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC
|
|
||||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
|
||||||
from bot_core.helper.command_checks import CommandChecks
|
|
||||||
from bot_core.logging.command_logger import CommandLogger
|
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
|
||||||
from modules.base.abc.base_helper_abc import BaseHelperABC
|
|
||||||
from modules.base.configuration.base_server_settings import BaseServerSettings
|
|
||||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
|
||||||
|
|
||||||
|
|
||||||
class PingCommand(DiscordCommandABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
logger: CommandLogger,
|
|
||||||
message_service: MessageServiceABC,
|
|
||||||
bot: DiscordBotServiceABC,
|
|
||||||
client_utils: ClientUtilsServiceABC,
|
|
||||||
translate: TranslatePipe,
|
|
||||||
permissions: PermissionServiceABC,
|
|
||||||
base_helper: BaseHelperABC,
|
|
||||||
servers: ServerRepositoryABC,
|
|
||||||
):
|
|
||||||
DiscordCommandABC.__init__(self)
|
|
||||||
|
|
||||||
self._logger = logger
|
|
||||||
self._message_service = message_service
|
|
||||||
self._bot = bot
|
|
||||||
self._client_utils = client_utils
|
|
||||||
self._t = translate
|
|
||||||
self._permissions = permissions
|
|
||||||
self._base_helper = base_helper
|
|
||||||
self._servers = servers
|
|
||||||
|
|
||||||
self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_ping(url: str) -> float:
|
|
||||||
from icmplib import ping
|
|
||||||
ping_result = ping(url, count=4, interval=0.2, privileged=False)
|
|
||||||
return ping_result.avg_rtt
|
|
||||||
|
|
||||||
@commands.hybrid_command()
|
|
||||||
@commands.guild_only()
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
async def ping(self, ctx: Context):
|
|
||||||
self._logger.debug(__name__, f'Received command ping {ctx}')
|
|
||||||
if self._permissions.is_member_technician(ctx.author):
|
|
||||||
embed = discord.Embed(
|
|
||||||
title=self._t.transform('modules.base.info.title'),
|
|
||||||
description=self._t.transform('modules.base.info.description'),
|
|
||||||
color=int('ef9d0d', 16)
|
|
||||||
)
|
|
||||||
server = self._servers.get_server_by_discord_id(ctx.guild.id)
|
|
||||||
settings: BaseServerSettings = self._base_helper.get_config(server.discord_server_id)
|
|
||||||
for server in settings.ping_urls:
|
|
||||||
embed.add_field(name=server, value=f'{self._get_ping(server)} ms', inline=False)
|
|
||||||
await self._message_service.send_ctx_msg(ctx, embed)
|
|
||||||
else:
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.base.pong'))
|
|
||||||
self._logger.trace(__name__, f'Finished ping command')
|
|
@ -1,48 +0,0 @@
|
|||||||
import discord
|
|
||||||
from cpl_discord.command import DiscordCommandABC
|
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
from discord.ext import commands
|
|
||||||
from discord.ext.commands import Context
|
|
||||||
|
|
||||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
|
||||||
from bot_core.helper.command_checks import CommandChecks
|
|
||||||
from bot_core.logging.command_logger import CommandLogger
|
|
||||||
|
|
||||||
|
|
||||||
class PresenceCommand(DiscordCommandABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
logger: CommandLogger,
|
|
||||||
message_service: MessageServiceABC,
|
|
||||||
bot: DiscordBotServiceABC,
|
|
||||||
translate: TranslatePipe,
|
|
||||||
):
|
|
||||||
DiscordCommandABC.__init__(self)
|
|
||||||
|
|
||||||
self._logger = logger
|
|
||||||
self._message_service = message_service
|
|
||||||
self._bot = bot
|
|
||||||
self._t = translate
|
|
||||||
|
|
||||||
@commands.hybrid_command()
|
|
||||||
@commands.guild_only()
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
@CommandChecks.check_is_member_moderator()
|
|
||||||
async def presence(self, ctx: Context, text: str = ''):
|
|
||||||
self._logger.debug(__name__, f'Received command presence {ctx}')
|
|
||||||
|
|
||||||
if text == '':
|
|
||||||
await self._bot.change_presence(activity=None)
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.base.presence.removed'))
|
|
||||||
return
|
|
||||||
|
|
||||||
if len(text) > 128:
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.base.presence.max_char_count_exceeded'))
|
|
||||||
return
|
|
||||||
|
|
||||||
await self._bot.change_presence(activity=discord.Game(name=text))
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.base.presence.changed'))
|
|
||||||
|
|
||||||
self._logger.trace(__name__, f'Finished presence command')
|
|
@ -1,258 +0,0 @@
|
|||||||
from typing import Optional, List
|
|
||||||
|
|
||||||
import discord
|
|
||||||
from cpl_core.configuration import ConfigurationABC
|
|
||||||
from cpl_core.database.context import DatabaseContextABC
|
|
||||||
from cpl_discord.command import DiscordCommandABC
|
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
from discord import app_commands
|
|
||||||
from discord.ext import commands
|
|
||||||
from discord.ext.commands import Context
|
|
||||||
from mysql.connector.errors import DatabaseError
|
|
||||||
|
|
||||||
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC
|
|
||||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
|
||||||
from bot_core.helper.command_checks import CommandChecks
|
|
||||||
from bot_core.logging.command_logger import CommandLogger
|
|
||||||
from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
|
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
|
||||||
from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
|
|
||||||
from bot_data.abc.user_joined_voice_channel_abc import UserJoinedVoiceChannelRepositoryABC
|
|
||||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
|
||||||
from modules.level.service.level_service import LevelService
|
|
||||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
|
||||||
|
|
||||||
|
|
||||||
class UserGroup(DiscordCommandABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
config: ConfigurationABC,
|
|
||||||
logger: CommandLogger,
|
|
||||||
message_service: MessageServiceABC,
|
|
||||||
bot: DiscordBotServiceABC,
|
|
||||||
client_utils: ClientUtilsServiceABC,
|
|
||||||
permissions: PermissionServiceABC,
|
|
||||||
servers: ServerRepositoryABC,
|
|
||||||
db: DatabaseContextABC,
|
|
||||||
users: UserRepositoryABC,
|
|
||||||
user_joined_servers: UserJoinedServerRepositoryABC,
|
|
||||||
user_joined_voice_channel: UserJoinedVoiceChannelRepositoryABC,
|
|
||||||
translate: TranslatePipe,
|
|
||||||
date: DateTimeOffsetPipe,
|
|
||||||
level: LevelService
|
|
||||||
):
|
|
||||||
DiscordCommandABC.__init__(self)
|
|
||||||
|
|
||||||
self._config = config
|
|
||||||
self._logger = logger
|
|
||||||
self._message_service = message_service
|
|
||||||
self._bot = bot
|
|
||||||
self._client_utils = client_utils
|
|
||||||
self._permissions = permissions
|
|
||||||
self._servers = servers
|
|
||||||
self._db = db
|
|
||||||
self._users = users
|
|
||||||
self._user_joined_servers = user_joined_servers
|
|
||||||
self._user_joined_voice_channel = user_joined_voice_channel
|
|
||||||
self._t = translate
|
|
||||||
self._date = date
|
|
||||||
self._level = level
|
|
||||||
|
|
||||||
self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}')
|
|
||||||
|
|
||||||
self._atr_dict = {
|
|
||||||
"xp": self._t.transform('modules.base.user.atr.xp'),
|
|
||||||
'ontime': self._t.transform('modules.base.user.atr.ontime')
|
|
||||||
}
|
|
||||||
|
|
||||||
self._atr_list = [(key, self._atr_dict[key]) for key in self._atr_dict]
|
|
||||||
|
|
||||||
@commands.hybrid_group()
|
|
||||||
@commands.guild_only()
|
|
||||||
async def user(self, ctx: Context):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@user.command()
|
|
||||||
@commands.guild_only()
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
async def info(self, ctx: Context, member: Optional[discord.Member] = None, *, wait: int = None):
|
|
||||||
self._logger.debug(__name__, f'Received command user-info {ctx}:{member},{wait}')
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
if member is None or not isinstance(member, discord.Member):
|
|
||||||
member = ctx.author
|
|
||||||
|
|
||||||
server = self._servers.find_server_by_discord_id(ctx.guild.id)
|
|
||||||
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id)
|
|
||||||
joins = self._user_joined_servers.get_user_joined_servers_by_user_id(user.user_id)
|
|
||||||
|
|
||||||
embed = discord.Embed(
|
|
||||||
title=member.name,
|
|
||||||
description=member.name,
|
|
||||||
color=int('ef9d0d', 16)
|
|
||||||
)
|
|
||||||
|
|
||||||
ontime = self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.user_id)\
|
|
||||||
.where(lambda x: x.leaved_on is not None and x.joined_on is not None)\
|
|
||||||
.sum(lambda join: round((join.leaved_on - join.joined_on).total_seconds() / 3600, 2))
|
|
||||||
|
|
||||||
embed.add_field(name=self._t.transform('modules.base.user.atr.id'), value=member.id)
|
|
||||||
embed.add_field(name=self._t.transform('modules.base.user.atr.name'), value=member.name)
|
|
||||||
embed.add_field(name=self._t.transform('modules.base.user.atr.discord_join'),
|
|
||||||
value=self._date.transform(member.created_at), inline=False)
|
|
||||||
embed.add_field(name=self._t.transform('modules.base.user.atr.last_join'),
|
|
||||||
value=self._date.transform(member.joined_at), inline=False)
|
|
||||||
embed.add_field(name=self._t.transform('modules.base.user.atr.xp'), value=str(user.xp))
|
|
||||||
embed.add_field(name=self._t.transform('modules.base.user.atr.ontime'), value=str(ontime))
|
|
||||||
|
|
||||||
roles = ''
|
|
||||||
for role in member.roles:
|
|
||||||
roles += f'{role.name}\n'
|
|
||||||
embed.add_field(name=self._t.transform('modules.base.user.atr.roles'), value=roles, inline=False)
|
|
||||||
|
|
||||||
if is_mod or member == ctx.author:
|
|
||||||
joins_string = ''
|
|
||||||
for join in joins:
|
|
||||||
joins_string += f'{self._date.transform(join.joined_on)}\n'
|
|
||||||
embed.add_field(name=self._t.transform('modules.base.user.atr.joins'), value=joins_string)
|
|
||||||
|
|
||||||
if is_mod or member == ctx.author:
|
|
||||||
lefts_string = ''
|
|
||||||
for join in joins:
|
|
||||||
if join.leaved_on is None:
|
|
||||||
if lefts_string == '':
|
|
||||||
lefts_string = '/'
|
|
||||||
continue
|
|
||||||
lefts_string += f'{self._date.transform(join.leaved_on)}\n'
|
|
||||||
|
|
||||||
embed.add_field(name=self._t.transform('modules.base.user.atr.lefts'), value=lefts_string)
|
|
||||||
|
|
||||||
if is_mod or member == ctx.author:
|
|
||||||
embed.add_field(name=self._t.transform('modules.base.user.atr.warnings'),
|
|
||||||
value=self._t.transform('common.not_implemented_yet'), inline=False)
|
|
||||||
|
|
||||||
# send to interaction because of sensitive data
|
|
||||||
await self._message_service.send_interaction_msg(ctx.interaction, embed, wait_before_delete=wait)
|
|
||||||
self._logger.trace(__name__, f'Finished user-info command')
|
|
||||||
|
|
||||||
@user.command()
|
|
||||||
@commands.guild_only()
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
async def get(self, ctx: Context, atr: str, member: discord.Member = None):
|
|
||||||
self._logger.debug(__name__, f'Received command user-get {atr} {ctx}:{member}')
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
if member is None or not isinstance(member, discord.Member):
|
|
||||||
member = ctx.author
|
|
||||||
|
|
||||||
server = self._servers.find_server_by_discord_id(ctx.guild.id)
|
|
||||||
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id)
|
|
||||||
|
|
||||||
if atr == 'xp':
|
|
||||||
value = str(user.xp)
|
|
||||||
|
|
||||||
elif atr == 'ontime':
|
|
||||||
value = str(round(
|
|
||||||
self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.user_id)
|
|
||||||
.sum(lambda join: (join.leaved_on - join.joined_on).total_seconds() / 3600),
|
|
||||||
2
|
|
||||||
))
|
|
||||||
|
|
||||||
else:
|
|
||||||
await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.error.atr_not_found').format(atr))
|
|
||||||
return
|
|
||||||
|
|
||||||
await self._message_service.send_interaction_msg(
|
|
||||||
ctx.interaction,
|
|
||||||
self._t.transform(f'modules.base.user.get.{atr.lower()}').format(member.mention, value)
|
|
||||||
)
|
|
||||||
|
|
||||||
@get.autocomplete('atr')
|
|
||||||
async def get_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]:
|
|
||||||
return [app_commands.Choice(name=value, value=key) for key, value in self._atr_list]
|
|
||||||
|
|
||||||
@user.command()
|
|
||||||
@commands.guild_only()
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
@CommandChecks.check_is_member_moderator()
|
|
||||||
async def set(self, ctx: Context, atr: str, value: str, member: discord.Member = None):
|
|
||||||
self._logger.debug(__name__, f'Received command user-set {atr} {ctx}:{member}')
|
|
||||||
|
|
||||||
if member is None or not isinstance(member, discord.Member):
|
|
||||||
member = ctx.author
|
|
||||||
|
|
||||||
server = self._servers.find_server_by_discord_id(ctx.guild.id)
|
|
||||||
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id)
|
|
||||||
|
|
||||||
if atr == 'xp':
|
|
||||||
if not value.isnumeric():
|
|
||||||
await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.value_type_not_numeric'))
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
user.xp = int(value)
|
|
||||||
except TypeError as te:
|
|
||||||
self._logger.error(__name__, f'String value couldn\'t be converted to int', te)
|
|
||||||
await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.type_error'))
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self._users.update_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
await self._level.check_level(member)
|
|
||||||
|
|
||||||
else:
|
|
||||||
await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.error.atr_not_found').format(atr))
|
|
||||||
return
|
|
||||||
|
|
||||||
await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform(f'modules.base.user.set.{atr.lower()}').format(member.mention, value))
|
|
||||||
|
|
||||||
@set.autocomplete('atr')
|
|
||||||
async def set_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]:
|
|
||||||
atr_list = [('xp', self._atr_dict['xp'])]
|
|
||||||
return [app_commands.Choice(name=value, value=key) for key, value in atr_list]
|
|
||||||
|
|
||||||
@user.command()
|
|
||||||
@commands.guild_only()
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
@CommandChecks.check_is_member_moderator()
|
|
||||||
async def remove(self, ctx: Context, atr: str, member: discord.Member = None):
|
|
||||||
self._logger.debug(__name__, f'Received command user-remove {atr} {ctx}:{member}')
|
|
||||||
|
|
||||||
if member is None or not isinstance(member, discord.Member):
|
|
||||||
member = ctx.author
|
|
||||||
|
|
||||||
server = self._servers.find_server_by_discord_id(ctx.guild.id)
|
|
||||||
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id)
|
|
||||||
|
|
||||||
if atr == 'xp':
|
|
||||||
user.xp = 0
|
|
||||||
self._users.update_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
await self._level.check_level(member)
|
|
||||||
|
|
||||||
elif atr == 'ontime':
|
|
||||||
self._user_joined_voice_channel.delete_user_joined_voice_channel_by_user_id(user.user_id)
|
|
||||||
self._db.save_changes()
|
|
||||||
|
|
||||||
else:
|
|
||||||
await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.error.atr_not_found').format(atr))
|
|
||||||
return
|
|
||||||
|
|
||||||
await self._message_service.send_interaction_msg(
|
|
||||||
ctx.interaction,
|
|
||||||
self._t.transform(f'modules.base.user.remove.{atr.lower()}').format(atr, member.mention)
|
|
||||||
)
|
|
||||||
|
|
||||||
@remove.autocomplete('atr')
|
|
||||||
async def remove_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]:
|
|
||||||
return [app_commands.Choice(name=value, value=key) for key, value in self._atr_list]
|
|
@ -1,36 +0,0 @@
|
|||||||
from cpl_core.logging import LoggerABC
|
|
||||||
from cpl_discord.events.on_raw_reaction_add_abc import OnRawReactionAddABC
|
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
|
||||||
from discord import RawReactionActionEvent
|
|
||||||
|
|
||||||
from bot_core.helper.event_checks import EventChecks
|
|
||||||
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
|
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
|
||||||
from modules.base.helper.base_reaction_handler import BaseReactionHandler
|
|
||||||
|
|
||||||
|
|
||||||
class BaseOnRawReactionAddEvent(OnRawReactionAddABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
logger: LoggerABC,
|
|
||||||
bot: DiscordBotServiceABC,
|
|
||||||
servers: ServerRepositoryABC,
|
|
||||||
auto_roles: AutoRoleRepositoryABC,
|
|
||||||
reaction_handler: BaseReactionHandler
|
|
||||||
):
|
|
||||||
OnRawReactionAddABC.__init__(self)
|
|
||||||
|
|
||||||
self._logger = logger
|
|
||||||
self._bot = bot
|
|
||||||
self._servers = servers
|
|
||||||
self._auto_roles = auto_roles
|
|
||||||
self._reaction_handler = reaction_handler
|
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
|
||||||
async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
|
|
||||||
self._logger.debug(__name__, f'Module {type(self)} started')
|
|
||||||
|
|
||||||
await self._reaction_handler.handle(payload, 'add')
|
|
||||||
|
|
||||||
self._logger.debug(__name__, f'Module {type(self)} stopped')
|
|
@ -1,36 +0,0 @@
|
|||||||
from cpl_core.logging import LoggerABC
|
|
||||||
from cpl_discord.events.on_raw_reaction_remove_abc import OnRawReactionRemoveABC
|
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
|
||||||
from discord import RawReactionActionEvent
|
|
||||||
|
|
||||||
from bot_core.helper.event_checks import EventChecks
|
|
||||||
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
|
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
|
||||||
from modules.base.helper.base_reaction_handler import BaseReactionHandler
|
|
||||||
|
|
||||||
|
|
||||||
class BaseOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
logger: LoggerABC,
|
|
||||||
bot: DiscordBotServiceABC,
|
|
||||||
servers: ServerRepositoryABC,
|
|
||||||
auto_roles: AutoRoleRepositoryABC,
|
|
||||||
reaction_handler: BaseReactionHandler,
|
|
||||||
):
|
|
||||||
OnRawReactionRemoveABC.__init__(self)
|
|
||||||
|
|
||||||
self._logger = logger
|
|
||||||
self._bot = bot
|
|
||||||
self._servers = servers
|
|
||||||
self._auto_roles = auto_roles
|
|
||||||
self._reaction_handler = reaction_handler
|
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
|
||||||
async def on_raw_reaction_remove(self, payload: RawReactionActionEvent):
|
|
||||||
self._logger.debug(__name__, f'Module {type(self)} started')
|
|
||||||
|
|
||||||
await self._reaction_handler.handle(payload, 'remove')
|
|
||||||
|
|
||||||
self._logger.debug(__name__, f'Module {type(self)} stopped')
|
|
@ -1,53 +0,0 @@
|
|||||||
import discord
|
|
||||||
from cpl_core.configuration import ConfigurationABC
|
|
||||||
from cpl_core.logging import LoggerABC
|
|
||||||
from cpl_discord.events import OnVoiceStateUpdateABC
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
|
|
||||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
|
||||||
from bot_core.helper.event_checks import EventChecks
|
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
|
||||||
from modules.base.abc.base_helper_abc import BaseHelperABC
|
|
||||||
from modules.base.configuration.base_server_settings import BaseServerSettings
|
|
||||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
|
||||||
|
|
||||||
|
|
||||||
class BaseOnVoiceStateUpdateEventHelpChannel(OnVoiceStateUpdateABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
config: ConfigurationABC,
|
|
||||||
logger: LoggerABC,
|
|
||||||
base_helper: BaseHelperABC,
|
|
||||||
servers: ServerRepositoryABC,
|
|
||||||
permissions: PermissionServiceABC,
|
|
||||||
message_service: MessageServiceABC,
|
|
||||||
t: TranslatePipe,
|
|
||||||
):
|
|
||||||
OnVoiceStateUpdateABC.__init__(self)
|
|
||||||
self._config = config
|
|
||||||
self._logger = logger
|
|
||||||
self._base_helper = base_helper
|
|
||||||
self._servers = servers
|
|
||||||
self._permissions = permissions
|
|
||||||
self._message_service = message_service
|
|
||||||
self._t = t
|
|
||||||
|
|
||||||
self._logger.info(__name__, f'Module {type(self)} loaded')
|
|
||||||
|
|
||||||
@EventChecks.check_is_ready()
|
|
||||||
async def on_voice_state_update(self, member: discord.Member, before: discord.VoiceState, after: discord.VoiceState):
|
|
||||||
self._logger.debug(__name__, f'Module {type(self)} started')
|
|
||||||
server = self._servers.get_server_by_discord_id(member.guild.id)
|
|
||||||
settings: BaseServerSettings = self._base_helper.get_config(server.discord_server_id)
|
|
||||||
if after.channel is None or after.channel.id != settings.help_voice_channel_id:
|
|
||||||
return
|
|
||||||
|
|
||||||
mods = [*self._permissions.get_admins(member.guild.id), *self._permissions.get_moderators(member.guild.id)]
|
|
||||||
for a in mods:
|
|
||||||
await self._message_service.send_dm_message(
|
|
||||||
self._t.transform('modules.base.member_joined_help_voice_channel').format(member.mention),
|
|
||||||
a,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._logger.debug(__name__, f'Module {type(self)} stopped')
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'modules.base.helper'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,55 +0,0 @@
|
|||||||
from cpl_core.database.context import DatabaseContextABC
|
|
||||||
from cpl_core.logging import LoggerABC
|
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
|
||||||
from discord import RawReactionActionEvent
|
|
||||||
|
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
|
||||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
|
||||||
from modules.base.abc.base_helper_abc import BaseHelperABC
|
|
||||||
from modules.base.configuration.base_server_settings import BaseServerSettings
|
|
||||||
|
|
||||||
|
|
||||||
class BaseReactionHandler:
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
logger: LoggerABC,
|
|
||||||
bot: DiscordBotServiceABC,
|
|
||||||
servers: ServerRepositoryABC,
|
|
||||||
users: UserRepositoryABC,
|
|
||||||
base_helper: BaseHelperABC,
|
|
||||||
db: DatabaseContextABC,
|
|
||||||
):
|
|
||||||
self._logger = logger
|
|
||||||
self._bot = bot
|
|
||||||
self._servers = servers
|
|
||||||
self._users = users
|
|
||||||
self._base_helper = base_helper
|
|
||||||
self._db = db
|
|
||||||
|
|
||||||
async def handle(self, payload: RawReactionActionEvent, r_type=None) -> None:
|
|
||||||
self._logger.trace(__name__, f'Handle reaction {payload} {r_type}')
|
|
||||||
|
|
||||||
guild = self._bot.get_guild(payload.guild_id)
|
|
||||||
member = guild.get_member(payload.user_id)
|
|
||||||
if member is None:
|
|
||||||
self._logger.warn(__name__, f'User {payload.user_id} in {guild.name} not found - skipping')
|
|
||||||
return
|
|
||||||
|
|
||||||
if member.bot:
|
|
||||||
return
|
|
||||||
|
|
||||||
server = self._servers.get_server_by_discord_id(guild.id)
|
|
||||||
user = self._users.get_user_by_discord_id_and_server_id(member.id, server.server_id)
|
|
||||||
settings: BaseServerSettings = self._base_helper.get_config(guild.id)
|
|
||||||
|
|
||||||
if r_type == 'add':
|
|
||||||
user.xp += settings.xp_per_reaction
|
|
||||||
self._users.update_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
elif r_type == 'remove':
|
|
||||||
user.xp -= settings.xp_per_reaction
|
|
||||||
self._users.update_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
else:
|
|
||||||
self._logger.warn(__name__, f'Invalid reaction type {r_type}')
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'modules.base.thread'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'modules.level.command'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
@ -1,396 +0,0 @@
|
|||||||
from typing import List as TList
|
|
||||||
|
|
||||||
import discord
|
|
||||||
from cpl_core.database.context import DatabaseContextABC
|
|
||||||
from cpl_discord.command import DiscordCommandABC
|
|
||||||
from cpl_discord.container import Guild, Role
|
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
|
||||||
from cpl_translation import TranslatePipe
|
|
||||||
from discord import app_commands
|
|
||||||
from discord.ext import commands
|
|
||||||
from discord.ext.commands import Context
|
|
||||||
|
|
||||||
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC
|
|
||||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
|
||||||
from bot_core.helper.command_checks import CommandChecks
|
|
||||||
from bot_core.logging.command_logger import CommandLogger
|
|
||||||
from bot_data.abc.level_repository_abc import LevelRepositoryABC
|
|
||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
|
||||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
|
||||||
from bot_data.model.level import Level
|
|
||||||
from modules.level.level_seeder import LevelSeeder
|
|
||||||
from modules.level.service.level_service import LevelService
|
|
||||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
|
||||||
|
|
||||||
|
|
||||||
class LevelGroup(DiscordCommandABC):
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
logger: CommandLogger,
|
|
||||||
message_service: MessageServiceABC,
|
|
||||||
bot: DiscordBotServiceABC,
|
|
||||||
client_utils: ClientUtilsServiceABC,
|
|
||||||
permission_service: PermissionServiceABC,
|
|
||||||
translate: TranslatePipe,
|
|
||||||
db: DatabaseContextABC,
|
|
||||||
levels: LevelRepositoryABC,
|
|
||||||
servers: ServerRepositoryABC,
|
|
||||||
users: UserRepositoryABC,
|
|
||||||
level_service: LevelService,
|
|
||||||
level_seeder: LevelSeeder,
|
|
||||||
):
|
|
||||||
DiscordCommandABC.__init__(self)
|
|
||||||
|
|
||||||
self._logger = logger
|
|
||||||
self._message_service = message_service
|
|
||||||
self._bot = bot
|
|
||||||
self._client_utils = client_utils
|
|
||||||
self._permissions = permission_service
|
|
||||||
self._t = translate
|
|
||||||
self._db = db
|
|
||||||
self._levels = levels
|
|
||||||
self._servers = servers
|
|
||||||
self._users = users
|
|
||||||
|
|
||||||
self._level_service = level_service
|
|
||||||
self._level_seeder = level_seeder
|
|
||||||
|
|
||||||
self._colors = [
|
|
||||||
('blue', discord.Colour.blue().to_rgb()),
|
|
||||||
('dark_blue', discord.Colour.dark_blue().to_rgb()),
|
|
||||||
('dark_gold', discord.Colour.dark_gold().to_rgb()),
|
|
||||||
('dark_gray', discord.Colour.dark_gray().to_rgb()),
|
|
||||||
('dark_green', discord.Colour.dark_green().to_rgb()),
|
|
||||||
('dark_grey', discord.Colour.dark_grey().to_rgb()),
|
|
||||||
('dark_magenta', discord.Colour.dark_magenta().to_rgb()),
|
|
||||||
('dark_orange', discord.Colour.dark_orange().to_rgb()),
|
|
||||||
('dark_purple', discord.Colour.dark_purple().to_rgb()),
|
|
||||||
('dark_red', discord.Colour.dark_red().to_rgb()),
|
|
||||||
('dark_teal', discord.Colour.dark_teal().to_rgb()),
|
|
||||||
('default', discord.Colour.default().to_rgb()),
|
|
||||||
('gold', discord.Colour.gold().to_rgb()),
|
|
||||||
('green', discord.Colour.green().to_rgb()),
|
|
||||||
('greyple', discord.Colour.greyple().to_rgb()),
|
|
||||||
('light_grey', discord.Colour.light_grey().to_rgb()),
|
|
||||||
('magenta', discord.Colour.magenta().to_rgb()),
|
|
||||||
('orange', discord.Colour.orange().to_rgb()),
|
|
||||||
('purple', discord.Colour.purple().to_rgb()),
|
|
||||||
('red', discord.Colour.red().to_rgb()),
|
|
||||||
('teal', discord.Colour.teal().to_rgb()),
|
|
||||||
('yellow', discord.Colour.yellow().to_rgb())
|
|
||||||
]
|
|
||||||
|
|
||||||
self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}')
|
|
||||||
|
|
||||||
async def _seed_levels(self, channel: discord.TextChannel):
|
|
||||||
# send message to ctx.channel because send_ctx_msg resolves ctx
|
|
||||||
try:
|
|
||||||
await self._message_service.send_channel_message(channel, self._t.transform('modules.level.seeding_started'))
|
|
||||||
await self._level_seeder.seed()
|
|
||||||
await self._message_service.send_channel_message(channel, self._t.transform('modules.level.seeding_finished'))
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Level seeding failed', e)
|
|
||||||
await self._message_service.send_channel_message(channel, self._t.transform('modules.level.seeding_failed'))
|
|
||||||
|
|
||||||
async def _level_auto_complete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]:
|
|
||||||
server = self._servers.get_server_by_discord_id(interaction.guild.id)
|
|
||||||
levels = self._levels.get_levels_by_server_id(server.server_id).select(lambda l: l.name)
|
|
||||||
return [app_commands.Choice(name=level, value=level) for level in self._client_utils.get_auto_complete_list(levels, current)]
|
|
||||||
|
|
||||||
@commands.hybrid_group()
|
|
||||||
@commands.guild_only()
|
|
||||||
async def level(self, ctx: Context):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@level.command(alias='levels')
|
|
||||||
@commands.guild_only()
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
@CommandChecks.check_is_member_moderator()
|
|
||||||
async def list(self, ctx: Context, wait: int = None):
|
|
||||||
self._logger.debug(__name__, f'Received command level list {ctx}')
|
|
||||||
|
|
||||||
if ctx.guild is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
server = self._servers.get_server_by_discord_id(ctx.guild.id)
|
|
||||||
levels = self._levels.get_levels_by_server_id(server.server_id)
|
|
||||||
if levels.count() < 1:
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.error.nothing_found'))
|
|
||||||
self._logger.trace(__name__, f'Finished command level list')
|
|
||||||
return
|
|
||||||
|
|
||||||
level_name = ''
|
|
||||||
xp = ''
|
|
||||||
permissions = ''
|
|
||||||
for level in levels:
|
|
||||||
level_name += f'\n{level.name}'
|
|
||||||
xp += f'\n{level.min_xp}'
|
|
||||||
permissions += f'\n{level.permissions}'
|
|
||||||
|
|
||||||
embed = discord.Embed(
|
|
||||||
title=self._t.transform('modules.level.list.title'),
|
|
||||||
description=self._t.transform('modules.level.list.description'),
|
|
||||||
color=int('ef9d0d', 16)
|
|
||||||
)
|
|
||||||
embed.add_field(name=self._t.transform('modules.level.list.name'), value=level_name, inline=True)
|
|
||||||
embed.add_field(name=self._t.transform('modules.level.list.min_xp'), value=xp, inline=True)
|
|
||||||
embed.add_field(name=self._t.transform('modules.level.list.permission_int'), value=permissions, inline=True)
|
|
||||||
await self._message_service.send_ctx_msg(ctx, embed, wait_before_delete=wait)
|
|
||||||
self._logger.trace(__name__, f'Finished command level list')
|
|
||||||
|
|
||||||
@level.command()
|
|
||||||
@commands.guild_only()
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
@CommandChecks.check_is_member_admin()
|
|
||||||
async def create(self, ctx: Context, name: str, color: str, min_xp: int, permissions: int):
|
|
||||||
self._logger.debug(__name__, f'Received command level create {ctx}')
|
|
||||||
|
|
||||||
try:
|
|
||||||
color = hex(discord.Colour.from_str(color).value)
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Error parsing color {color}', e)
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
permissions = discord.Permissions(permissions).value
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Error parsing permissions {permissions}', e)
|
|
||||||
return
|
|
||||||
|
|
||||||
if ctx.guild is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
server = self._servers.get_server_by_discord_id(ctx.guild.id)
|
|
||||||
level = Level(name, color, min_xp, permissions, server)
|
|
||||||
levels = self._levels.get_levels_by_server_id(server.server_id)
|
|
||||||
|
|
||||||
if levels.where(lambda l: l.name == level.name).first_or_default() is not None:
|
|
||||||
self._logger.debug(__name__, f'Level with name {level.name} already exists')
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.error.level_with_name_already_exists').format(level.name))
|
|
||||||
elif levels.where(lambda l: l.min_xp == level.min_xp).first_or_default() is not None:
|
|
||||||
self._logger.debug(__name__, f'Level with min_xp {level.min_xp} already exists {level.name}')
|
|
||||||
found_level = levels.where(lambda l: l.min_xp == level.min_xp).first_or_default()
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.error.level_with_xp_already_exists').format(found_level.name, found_level.min_xp))
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
self._levels.add_level(level)
|
|
||||||
self._db.save_changes()
|
|
||||||
self._logger.info(__name__, f'Saved level {name} with color {color}, min_xp {min_xp} and permissions {permissions}')
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Could not save level {name} with color {color}, min_xp {min_xp} and permissions {permissions}', e)
|
|
||||||
else:
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.create.created').format(name, permissions))
|
|
||||||
await self._seed_levels(ctx.channel)
|
|
||||||
|
|
||||||
self._logger.trace(__name__, f'Finished command level create')
|
|
||||||
|
|
||||||
@create.autocomplete('color')
|
|
||||||
async def create_color_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]:
|
|
||||||
# value in rg format see:
|
|
||||||
# https://discordpy.readthedocs.io/en/latest/api.html#discord.Colour.to_rgb
|
|
||||||
return [app_commands.Choice(name=self._t.transform(f'common.colors.{color}'), value=f'rgb({code[0]}, {code[1]}, {code[2]})') for color, code in self._colors]
|
|
||||||
|
|
||||||
@level.command()
|
|
||||||
@commands.guild_only()
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
@CommandChecks.check_is_member_admin()
|
|
||||||
async def edit(self, ctx: Context, level: str, name: str = None, color: str = None, min_xp: int = None, permissions: int = None):
|
|
||||||
self._logger.debug(__name__, f'Received command level edit {ctx}')
|
|
||||||
|
|
||||||
server = self._servers.get_server_by_discord_id(ctx.guild.id)
|
|
||||||
level_from_db = self._levels.get_levels_by_server_id(server.server_id).where(lambda l: l.name == level).single_or_default()
|
|
||||||
if level_from_db is None:
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.edit.not_found').format(level))
|
|
||||||
return
|
|
||||||
|
|
||||||
guild: Guild = self._bot.guilds.where(lambda g: g == ctx.guild).single()
|
|
||||||
role: Role = guild.roles.where(lambda r: r.name == level_from_db.name).single()
|
|
||||||
|
|
||||||
if name is not None:
|
|
||||||
level_from_db.name = name
|
|
||||||
|
|
||||||
if color is not None:
|
|
||||||
try:
|
|
||||||
level_from_db.color = hex(discord.Colour.from_str(color).value)
|
|
||||||
except Exception as e:
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.edit.color_invalid').format(color))
|
|
||||||
self._logger.error(__name__, f'Error parsing color {color}', e)
|
|
||||||
return
|
|
||||||
|
|
||||||
if min_xp is not None:
|
|
||||||
level_from_db.min_xp = min_xp
|
|
||||||
|
|
||||||
if permissions is not None:
|
|
||||||
try:
|
|
||||||
level_from_db.permissions = discord.Permissions(permissions).value
|
|
||||||
except Exception as e:
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.edit.permission_invalid').format(permissions))
|
|
||||||
self._logger.error(__name__, f'Error parsing permissions {permissions}', e)
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
self._levels.update_level(level_from_db)
|
|
||||||
self._db.save_changes()
|
|
||||||
await role.edit(name=level_from_db.name, permissions=discord.Permissions(level_from_db.permissions), colour=discord.Colour(int(level_from_db.color, 16)))
|
|
||||||
self._logger.info(__name__,
|
|
||||||
f'Saved level {level_from_db.name} with color {level_from_db.color}, min_xp {level_from_db.min_xp} and permissions {level_from_db.permissions}')
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Could not save level {level} with color {color}, min_xp {min_xp} and permissions {permissions}', e)
|
|
||||||
else:
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.edit.edited').format(level))
|
|
||||||
await self._seed_levels(ctx.channel)
|
|
||||||
|
|
||||||
self._logger.trace(__name__, f'Finished command level edit')
|
|
||||||
|
|
||||||
@edit.autocomplete('level')
|
|
||||||
async def edit_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]:
|
|
||||||
return await self._level_auto_complete(interaction, current)
|
|
||||||
|
|
||||||
@edit.autocomplete('color')
|
|
||||||
async def edit_color_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]:
|
|
||||||
# value in rg format see:
|
|
||||||
# https://discordpy.readthedocs.io/en/latest/api.html#discord.Colour.to_rgb
|
|
||||||
return [app_commands.Choice(name=self._t.transform(f'common.colors.{color}'), value=f'rgb({code[0]}, {code[1]}, {code[2]})') for color, code in self._colors]
|
|
||||||
|
|
||||||
@level.command()
|
|
||||||
@commands.guild_only()
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
@CommandChecks.check_is_member_admin()
|
|
||||||
async def remove(self, ctx: Context, level: str):
|
|
||||||
self._logger.debug(__name__, f'Received command level remove {ctx}')
|
|
||||||
|
|
||||||
server = self._servers.get_server_by_discord_id(ctx.guild.id)
|
|
||||||
level_from_db = self._levels.get_levels_by_server_id(server.server_id).where(lambda l: l.name == level).first_or_default()
|
|
||||||
if level_from_db is None:
|
|
||||||
self._logger.debug(__name__, f'level {level} not found')
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.remove.error.not_found').format(level))
|
|
||||||
self._logger.trace(__name__, f'Finished command level remove')
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
self._levels.delete_level(level_from_db)
|
|
||||||
self._db.save_changes()
|
|
||||||
guild: Guild = self._bot.guilds.where(lambda g: g == ctx.guild).single()
|
|
||||||
role: Role = guild.roles.where(lambda r: r.name == level).single_or_default()
|
|
||||||
if role is not None:
|
|
||||||
await role.delete()
|
|
||||||
self._logger.info(__name__, f'Removed level {level}')
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Could not remove level {level}', e)
|
|
||||||
else:
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.remove.success').format(level))
|
|
||||||
await self._seed_levels(ctx.channel)
|
|
||||||
|
|
||||||
self._logger.trace(__name__, f'Finished command level remove')
|
|
||||||
|
|
||||||
@remove.autocomplete('level')
|
|
||||||
async def remove_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]:
|
|
||||||
return await self._level_auto_complete(interaction, current)
|
|
||||||
|
|
||||||
@level.command()
|
|
||||||
@commands.guild_only()
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
@CommandChecks.check_is_member_moderator()
|
|
||||||
async def down(self, ctx: Context, member: discord.Member):
|
|
||||||
self._logger.debug(__name__, f'Received command level down {ctx} {member}')
|
|
||||||
|
|
||||||
if member.bot:
|
|
||||||
return
|
|
||||||
|
|
||||||
server = self._servers.get_server_by_discord_id(ctx.guild.id)
|
|
||||||
user = self._users.get_user_by_discord_id_and_server_id(member.id, server.server_id)
|
|
||||||
level = self._level_service.get_level(user)
|
|
||||||
levels = self._levels.get_levels_by_server_id(server.server_id).order_by(lambda l: l.min_xp)
|
|
||||||
|
|
||||||
if level == levels.first():
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.down.already_first').format(member.mention))
|
|
||||||
self._logger.trace(__name__, f'Finished command level down')
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
new_level = levels.where(lambda l: l.min_xp < level.min_xp).last()
|
|
||||||
user.xp = new_level.min_xp
|
|
||||||
self._users.update_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.down.success').format(member.mention, new_level.name))
|
|
||||||
await self._level_service.set_level(user)
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Cannot level down {member.name} with level {level.name}', e)
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.down.failed').format(member.mention))
|
|
||||||
|
|
||||||
self._logger.trace(__name__, f'Finished command level down')
|
|
||||||
|
|
||||||
@level.command()
|
|
||||||
@commands.guild_only()
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
@CommandChecks.check_is_member_moderator()
|
|
||||||
async def up(self, ctx: Context, member: discord.Member):
|
|
||||||
self._logger.debug(__name__, f'Received command level up {ctx} {member}')
|
|
||||||
|
|
||||||
if member.bot:
|
|
||||||
return
|
|
||||||
|
|
||||||
server = self._servers.get_server_by_discord_id(ctx.guild.id)
|
|
||||||
user = self._users.get_user_by_discord_id_and_server_id(member.id, server.server_id)
|
|
||||||
level = self._level_service.get_level(user)
|
|
||||||
levels = self._levels.get_levels_by_server_id(server.server_id).order_by(lambda l: l.min_xp)
|
|
||||||
|
|
||||||
if level.name == levels.last().name:
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.up.already_last').format(member.mention))
|
|
||||||
self._logger.trace(__name__, f'Finished command level up')
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
new_level = levels.where(lambda l: l.min_xp > level.min_xp).first()
|
|
||||||
user.xp = new_level.min_xp
|
|
||||||
self._users.update_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.up.success').format(member.mention, new_level.name))
|
|
||||||
await self._level_service.set_level(user)
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Cannot level up {member.name} with level {level.name}', e)
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.up.failed').format(member.mention))
|
|
||||||
|
|
||||||
self._logger.trace(__name__, f'Finished command level up')
|
|
||||||
|
|
||||||
@level.command()
|
|
||||||
@commands.guild_only()
|
|
||||||
@CommandChecks.check_is_ready()
|
|
||||||
@CommandChecks.check_is_member_moderator()
|
|
||||||
async def set(self, ctx: Context, member: discord.Member, level: str):
|
|
||||||
self._logger.debug(__name__, f'Received command level up {ctx} {member}')
|
|
||||||
|
|
||||||
if member.bot:
|
|
||||||
return
|
|
||||||
|
|
||||||
server = self._servers.get_server_by_discord_id(ctx.guild.id)
|
|
||||||
user = self._users.get_user_by_discord_id_and_server_id(member.id, server.server_id)
|
|
||||||
current_level = self._level_service.get_level(user)
|
|
||||||
new_level = self._levels.get_levels_by_server_id(server.server_id).where(lambda l: l.name == level).single_or_default()
|
|
||||||
|
|
||||||
if new_level is None:
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.set.not_found').format(level))
|
|
||||||
self._logger.trace(__name__, f'Finished command level set')
|
|
||||||
return
|
|
||||||
|
|
||||||
if current_level.name == level:
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.set.already_level').format(member.mention, level))
|
|
||||||
self._logger.trace(__name__, f'Finished command level set')
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
user.xp = new_level.min_xp
|
|
||||||
self._users.update_user(user)
|
|
||||||
self._db.save_changes()
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.set.success').format(member.mention, new_level.name))
|
|
||||||
await self._level_service.set_level(user)
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error(__name__, f'Cannot set level {level} for {member.name}', e)
|
|
||||||
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.level.set.failed').format(member.mention))
|
|
||||||
|
|
||||||
self._logger.trace(__name__, f'Finished command level set')
|
|
||||||
|
|
||||||
@set.autocomplete('level')
|
|
||||||
async def set_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]:
|
|
||||||
return await self._level_auto_complete(interaction, current)
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
bot Keksdose bot
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Discord bot for the Keksdose discord Server
|
|
||||||
|
|
||||||
:copyright: (c) 2022 sh-edraft.de
|
|
||||||
:license: MIT, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__title__ = 'modules.level.configuration'
|
|
||||||
__author__ = 'Sven Heidemann'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
|
|
||||||
__version__ = '0.3.0'
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
# imports
|
|
||||||
|
|
||||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
|
||||||
version_info = VersionInfo(major='0', minor='3', micro='0')
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user