Compare commits
	
		
			9 Commits
		
	
	
		
			#139
			...
			bcf71a26f0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| bcf71a26f0 | |||
| b25b75e382 | |||
| f21b4f9881 | |||
| 8705904882 | |||
| 7026b3abac | |||
| 31464df3f6 | |||
| eb9f5b83d5 | |||
| fdd8357729 | |||
| 7c744f0e65 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -143,5 +143,4 @@ PythonImportHelper-v2-Completion.json
 | 
				
			|||||||
deploy/
 | 
					deploy/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# idea
 | 
					# idea
 | 
				
			||||||
.idea/
 | 
					.idea/
 | 
				
			||||||
selenium-data/
 | 
					 | 
				
			||||||
@@ -1,14 +1,2 @@
 | 
				
			|||||||
# kd_discord_bot
 | 
					# kd_discord_bot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Test Bot
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
To test the bot run unittests or call ```cpl test```.
 | 
					 | 
				
			||||||
Configure test instance by creating the file ./test/ui_tests/.env and set following environment variables:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```sh
 | 
					 | 
				
			||||||
KDB_TEST_DB_PASSWORD=
 | 
					 | 
				
			||||||
KDB_TEST_NAME=
 | 
					 | 
				
			||||||
KDB_TEST_TOKEN=
 | 
					 | 
				
			||||||
KDB_TEST_DISCORD_MAIL=
 | 
					 | 
				
			||||||
KDB_TEST_DISCORD_PASSWORD=
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
@@ -14,27 +14,29 @@
 | 
				
			|||||||
      "permission": "src/modules/permission/permission.json",
 | 
					      "permission": "src/modules/permission/permission.json",
 | 
				
			||||||
      "stats": "src/modules/stats/stats.json",
 | 
					      "stats": "src/modules/stats/stats.json",
 | 
				
			||||||
      "technician": "src/modules/technician/technician.json",
 | 
					      "technician": "src/modules/technician/technician.json",
 | 
				
			||||||
      "ui-tests": "test/ui_tests/ui-tests.json",
 | 
					 | 
				
			||||||
      "ui-tests-shared": "test/ui_tests_shared/ui-tests-shared.json",
 | 
					 | 
				
			||||||
      "ui-tests-tests": "test/ui_tests_tests/ui-tests-tests.json",
 | 
					 | 
				
			||||||
      "get-version": "tools/get_version/get-version.json",
 | 
					      "get-version": "tools/get_version/get-version.json",
 | 
				
			||||||
      "post-build": "tools/post_build/post-build.json",
 | 
					      "post-build": "tools/post_build/post-build.json",
 | 
				
			||||||
      "set-version": "tools/set_version/set-version.json"
 | 
					      "set-version": "tools/set_version/set-version.json"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "Scripts": {
 | 
					    "Scripts": {
 | 
				
			||||||
      "test": "export $(cat test/ui_tests/.env); export PYTHONPATH=$PWD/src:$PYTHONPATH; cpl run ui-tests",
 | 
					 | 
				
			||||||
      "sv": "cpl set-version $ARGS",
 | 
					      "sv": "cpl set-version $ARGS",
 | 
				
			||||||
      "set-version": "cpl run set-version $ARGS; echo '';",
 | 
					      "set-version": "cpl run set-version $ARGS; echo '';",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "gv": "cpl get-version",
 | 
					      "gv": "cpl get-version",
 | 
				
			||||||
      "get-version": "export VERSION=$(cpl run get-version); echo $VERSION;",
 | 
					      "get-version": "export VERSION=$(cpl run get-version); echo $VERSION;",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "pre-build": "cpl set-version $ARGS",
 | 
					      "pre-build": "cpl set-version $ARGS",
 | 
				
			||||||
      "post-build": "cpl run post-build",
 | 
					      "post-build": "cpl run post-build",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "pre-prod": "cpl build",
 | 
					      "pre-prod": "cpl build",
 | 
				
			||||||
      "prod": "export KDB_ENVIRONMENT=production; export KDB_NAME=KDB-Prod; cpl start;",
 | 
					      "prod": "export KDB_ENVIRONMENT=production; export KDB_NAME=KDB-Prod; cpl start;",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "pre-stage": "cpl build",
 | 
					      "pre-stage": "cpl build",
 | 
				
			||||||
      "stage": "export KDB_ENVIRONMENT=staging; export KDB_NAME=KDB-Stage; cpl start;",
 | 
					      "stage": "export KDB_ENVIRONMENT=staging; export KDB_NAME=KDB-Stage; cpl start;",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "pre-dev": "cpl build",
 | 
					      "pre-dev": "cpl build",
 | 
				
			||||||
      "dev": "export KDB_ENVIRONMENT=development; export KDB_NAME=KDB-Dev; cpl start;",
 | 
					      "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) .;",
 | 
					      "docker-build": "cpl build $ARGS; docker build -t kdb-bot/kdb-bot:$(cpl gv) .;",
 | 
				
			||||||
      "dc-up": "docker-compose up -d",
 | 
					      "dc-up": "docker-compose up -d",
 | 
				
			||||||
      "dc-down": "docker-compose down",
 | 
					      "dc-down": "docker-compose down",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,22 +16,22 @@
 | 
				
			|||||||
    "LicenseName": "MIT",
 | 
					    "LicenseName": "MIT",
 | 
				
			||||||
    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
					    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core==2022.10.0.post9",
 | 
					      "cpl-core==2022.12.0",
 | 
				
			||||||
      "cpl-translation==2022.10.0.post2",
 | 
					      "cpl-translation==2022.10.0.post2",
 | 
				
			||||||
      "cpl-query==2022.10.0.post2",
 | 
					      "cpl-query==2022.12.2",
 | 
				
			||||||
      "cpl-discord==2022.10.0.post6",
 | 
					      "cpl-discord==2022.12.0",
 | 
				
			||||||
      "Flask==2.2.2",
 | 
					      "Flask==2.2.2",
 | 
				
			||||||
      "Flask-Classful==0.14.2",
 | 
					      "Flask-Classful==0.14.2",
 | 
				
			||||||
      "Flask-Cors==3.0.10",
 | 
					      "Flask-Cors==3.0.10",
 | 
				
			||||||
      "PyJWT==2.6.0",
 | 
					      "PyJWT==2.6.0",
 | 
				
			||||||
      "waitress==2.1.2",
 | 
					      "waitress==2.1.2",
 | 
				
			||||||
      "Flask-SocketIO==5.3.1",
 | 
					      "Flask-SocketIO==5.3.2",
 | 
				
			||||||
      "eventlet==0.33.1",
 | 
					      "eventlet==0.33.2",
 | 
				
			||||||
      "requests-oauthlib==1.3.1",
 | 
					      "requests-oauthlib==1.3.1",
 | 
				
			||||||
      "icmplib==3.0.3"
 | 
					      "icmplib==3.0.3"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli==2022.10.0"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -160,20 +160,27 @@
 | 
				
			|||||||
        "removed": "Presence wurde entfernt.",
 | 
					        "removed": "Presence wurde entfernt.",
 | 
				
			||||||
        "max_char_count_exceeded": "Der Text darf nicht mehr als 128 Zeichen lang sein!"
 | 
					        "max_char_count_exceeded": "Der Text darf nicht mehr als 128 Zeichen lang sein!"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "user_info": {
 | 
					      "user": {
 | 
				
			||||||
        "fields": {
 | 
					        "info": {
 | 
				
			||||||
          "id": "Id",
 | 
					          "fields": {
 | 
				
			||||||
          "name": "Name",
 | 
					            "id": "Id",
 | 
				
			||||||
          "discord_join": "Discord beigetreten am",
 | 
					            "name": "Name",
 | 
				
			||||||
          "last_join": "Server beigetreten am",
 | 
					            "discord_join": "Discord beigetreten am",
 | 
				
			||||||
          "xp": "XP",
 | 
					            "last_join": "Server beigetreten am",
 | 
				
			||||||
          "ontime": "Ontime",
 | 
					            "xp": "XP",
 | 
				
			||||||
          "roles": "Rollen",
 | 
					            "ontime": "Ontime",
 | 
				
			||||||
          "joins": "Beitritte",
 | 
					            "roles": "Rollen",
 | 
				
			||||||
          "lefts": "Abgänge",
 | 
					            "joins": "Beitritte",
 | 
				
			||||||
          "warnings": "Verwarnungen"
 | 
					            "lefts": "Abgänge",
 | 
				
			||||||
 | 
					            "warnings": "Verwarnungen"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "footer": ""
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "footer": ""
 | 
					        "get": {
 | 
				
			||||||
 | 
					          "atr_not_found": "Das Attribut {} konnte nicht gefunden werden :(",
 | 
				
			||||||
 | 
					          "xp": "{} hat {} xp",
 | 
				
			||||||
 | 
					          "ontime": "{} war insgesamt {} Stunden aktiv in einem Sprachkanal"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "boot_log": {
 | 
					    "boot_log": {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "",
 | 
					    "LicenseName": "",
 | 
				
			||||||
    "LicenseDescription": "",
 | 
					    "LicenseDescription": "",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core==2022.10.0.post7"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli==2022.10.0"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,14 +46,14 @@ class AuthController:
 | 
				
			|||||||
    @Route.authorize(role=AuthRoleEnum.admin)
 | 
					    @Route.authorize(role=AuthRoleEnum.admin)
 | 
				
			||||||
    async def get_all_users(self) -> Response:
 | 
					    async def get_all_users(self) -> Response:
 | 
				
			||||||
        result = await self._auth_service.get_all_auth_users_async()
 | 
					        result = await self._auth_service.get_all_auth_users_async()
 | 
				
			||||||
        return jsonify(result.select(lambda x: x.to_dict()))
 | 
					        return jsonify(result.select(lambda x: x.to_dict()).to_list())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Route.post(f'{BasePath}/users/get/filtered')
 | 
					    @Route.post(f'{BasePath}/users/get/filtered')
 | 
				
			||||||
    @Route.authorize(role=AuthRoleEnum.admin)
 | 
					    @Route.authorize(role=AuthRoleEnum.admin)
 | 
				
			||||||
    async def get_filtered_users(self) -> Response:
 | 
					    async def get_filtered_users(self) -> Response:
 | 
				
			||||||
        dto: AuthUserSelectCriteria = JSONProcessor.process(AuthUserSelectCriteria, request.get_json(force=True, silent=True))
 | 
					        dto: AuthUserSelectCriteria = JSONProcessor.process(AuthUserSelectCriteria, request.get_json(force=True, silent=True))
 | 
				
			||||||
        result = await self._auth_service.get_filtered_auth_users_async(dto)
 | 
					        result = await self._auth_service.get_filtered_auth_users_async(dto)
 | 
				
			||||||
        result.result = result.result.select(lambda x: x.to_dict())
 | 
					        result.result = result.result.select(lambda x: x.to_dict()).to_list()
 | 
				
			||||||
        return jsonify(result.to_dict())
 | 
					        return jsonify(result.to_dict())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Route.get(f'{BasePath}/users/get/<email>')
 | 
					    @Route.get(f'{BasePath}/users/get/<email>')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,14 +40,14 @@ class ServerController:
 | 
				
			|||||||
    @Route.authorize(role=AuthRoleEnum.admin)
 | 
					    @Route.authorize(role=AuthRoleEnum.admin)
 | 
				
			||||||
    async def get_all_servers(self) -> Response:
 | 
					    async def get_all_servers(self) -> Response:
 | 
				
			||||||
        result = await self._discord_service.get_all_servers()
 | 
					        result = await self._discord_service.get_all_servers()
 | 
				
			||||||
        result = result.select(lambda x: x.to_dict())
 | 
					        result = result.select(lambda x: x.to_dict()).to_list()
 | 
				
			||||||
        return jsonify(result)
 | 
					        return jsonify(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Route.get(f'{BasePath}/get/servers-by-user')
 | 
					    @Route.get(f'{BasePath}/get/servers-by-user')
 | 
				
			||||||
    @Route.authorize
 | 
					    @Route.authorize
 | 
				
			||||||
    async def get_all_servers_by_user(self) -> Response:
 | 
					    async def get_all_servers_by_user(self) -> Response:
 | 
				
			||||||
        result = await self._discord_service.get_all_servers_by_user()
 | 
					        result = await self._discord_service.get_all_servers_by_user()
 | 
				
			||||||
        result = result.select(lambda x: x.to_dict())
 | 
					        result = result.select(lambda x: x.to_dict()).to_list()
 | 
				
			||||||
        return jsonify(result)
 | 
					        return jsonify(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Route.post(f'{BasePath}/get/filtered')
 | 
					    @Route.post(f'{BasePath}/get/filtered')
 | 
				
			||||||
@@ -55,11 +55,11 @@ class ServerController:
 | 
				
			|||||||
    async def get_filtered_servers(self) -> Response:
 | 
					    async def get_filtered_servers(self) -> Response:
 | 
				
			||||||
        dto: ServerSelectCriteria = JSONProcessor.process(ServerSelectCriteria, request.get_json(force=True, silent=True))
 | 
					        dto: ServerSelectCriteria = JSONProcessor.process(ServerSelectCriteria, request.get_json(force=True, silent=True))
 | 
				
			||||||
        result = await self._discord_service.get_filtered_servers_async(dto)
 | 
					        result = await self._discord_service.get_filtered_servers_async(dto)
 | 
				
			||||||
        result.result = result.result.select(lambda x: x.to_dict())
 | 
					        result.result = result.result.select(lambda x: x.to_dict()).to_list()
 | 
				
			||||||
        return jsonify(result.to_dict())
 | 
					        return jsonify(result.to_dict())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Route.get(f'{BasePath}/get/<id>')
 | 
					    @Route.get(f'{BasePath}/get/<id>')
 | 
				
			||||||
    @Route.authorize
 | 
					    @Route.authorize
 | 
				
			||||||
    async def get_server_by_id(self, id: int) -> Response:
 | 
					    async def get_server_by_id(self, id: int) -> Response:
 | 
				
			||||||
        result = await self._discord_service.get_server_by_id_async(id)
 | 
					        result = await self._discord_service.get_server_by_id_async(id).to_list()
 | 
				
			||||||
        return jsonify(result.to_dict())
 | 
					        return jsonify(result.to_dict())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "MIT",
 | 
					    "LicenseName": "MIT",
 | 
				
			||||||
    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
					    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core>=0.3.dev70"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli==2022.10.0"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "MIT",
 | 
					    "LicenseName": "MIT",
 | 
				
			||||||
    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
					    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core>=0.3.dev70"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli==2022.10.0"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "",
 | 
					    "LicenseName": "",
 | 
				
			||||||
    "LicenseDescription": "",
 | 
					    "LicenseDescription": "",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core>=2022.10.0.post5"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli==2022.10.0"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "",
 | 
					    "LicenseName": "",
 | 
				
			||||||
    "LicenseDescription": "",
 | 
					    "LicenseDescription": "",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core>=2022.10.0.post2"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli==2022.10.0"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,11 @@
 | 
				
			|||||||
from typing import Optional
 | 
					from typing import Optional, List
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import discord
 | 
					import discord
 | 
				
			||||||
from cpl_core.configuration import ConfigurationABC
 | 
					from cpl_core.configuration import ConfigurationABC
 | 
				
			||||||
from cpl_discord.command import DiscordCommandABC
 | 
					from cpl_discord.command import DiscordCommandABC
 | 
				
			||||||
from cpl_discord.service import DiscordBotServiceABC
 | 
					from cpl_discord.service import DiscordBotServiceABC
 | 
				
			||||||
from cpl_translation import TranslatePipe
 | 
					from cpl_translation import TranslatePipe
 | 
				
			||||||
 | 
					from discord import app_commands
 | 
				
			||||||
from discord.ext import commands
 | 
					from discord.ext import commands
 | 
				
			||||||
from discord.ext.commands import Context
 | 
					from discord.ext.commands import Context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -83,26 +84,28 @@ class UserGroup(DiscordCommandABC):
 | 
				
			|||||||
            color=int('ef9d0d', 16)
 | 
					            color=int('ef9d0d', 16)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ujvs = self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.user_id)
 | 
					        ontime = self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.user_id).sum(
 | 
				
			||||||
        ontime = ujvs.sum(lambda join: round((join.leaved_on - join.joined_on).total_seconds() / 3600, 2))
 | 
					            lambda join: round((join.leaved_on - join.joined_on).total_seconds() / 3600, 2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.user_info.fields.id'), value=member.id)
 | 
					        embed.add_field(name=self._t.transform('modules.base.user.info.fields.id'), value=member.id)
 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.user_info.fields.name'), value=member.name)
 | 
					        embed.add_field(name=self._t.transform('modules.base.user.info.fields.name'), value=member.name)
 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.user_info.fields.discord_join'), value=self._date.transform(member.created_at), inline=False)
 | 
					        embed.add_field(name=self._t.transform('modules.base.user.info.fields.discord_join'),
 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.user_info.fields.last_join'), value=self._date.transform(member.joined_at), inline=False)
 | 
					                        value=self._date.transform(member.created_at), inline=False)
 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.user_info.fields.xp'), value=str(user.xp))
 | 
					        embed.add_field(name=self._t.transform('modules.base.user.info.fields.last_join'),
 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.user_info.fields.ontime'), value=str(ontime))
 | 
					                        value=self._date.transform(member.joined_at), inline=False)
 | 
				
			||||||
 | 
					        embed.add_field(name=self._t.transform('modules.base.user.info.fields.xp'), value=str(user.xp))
 | 
				
			||||||
 | 
					        embed.add_field(name=self._t.transform('modules.base.user.info.fields.ontime'), value=str(ontime))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        roles = ''
 | 
					        roles = ''
 | 
				
			||||||
        for role in member.roles:
 | 
					        for role in member.roles:
 | 
				
			||||||
            roles += f'{role.name}\n'
 | 
					            roles += f'{role.name}\n'
 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.user_info.fields.roles'), value=roles, inline=False)
 | 
					        embed.add_field(name=self._t.transform('modules.base.user.info.fields.roles'), value=roles, inline=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if is_mod or member == ctx.author:
 | 
					        if is_mod or member == ctx.author:
 | 
				
			||||||
            joins_string = ''
 | 
					            joins_string = ''
 | 
				
			||||||
            for join in joins:
 | 
					            for join in joins:
 | 
				
			||||||
                joins_string += f'{self._date.transform(join.joined_on)}\n'
 | 
					                joins_string += f'{self._date.transform(join.joined_on)}\n'
 | 
				
			||||||
            embed.add_field(name=self._t.transform('modules.base.user_info.fields.joins'), value=joins_string)
 | 
					            embed.add_field(name=self._t.transform('modules.base.user.info.fields.joins'), value=joins_string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if is_mod or member == ctx.author:
 | 
					        if is_mod or member == ctx.author:
 | 
				
			||||||
            lefts_string = ''
 | 
					            lefts_string = ''
 | 
				
			||||||
@@ -113,11 +116,54 @@ class UserGroup(DiscordCommandABC):
 | 
				
			|||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
                lefts_string += f'{self._date.transform(join.leaved_on)}\n'
 | 
					                lefts_string += f'{self._date.transform(join.leaved_on)}\n'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            embed.add_field(name=self._t.transform('modules.base.user_info.fields.lefts'), value=lefts_string)
 | 
					            embed.add_field(name=self._t.transform('modules.base.user.info.fields.lefts'), value=lefts_string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if is_mod or member == ctx.author:
 | 
					        if is_mod or member == ctx.author:
 | 
				
			||||||
            embed.add_field(name=self._t.transform('modules.base.user_info.fields.warnings'), value=self._t.transform('common.not_implemented_yet'), inline=False)
 | 
					            embed.add_field(name=self._t.transform('modules.base.user.info.fields.warnings'),
 | 
				
			||||||
 | 
					                            value=self._t.transform('common.not_implemented_yet'), inline=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # send to interaction because of sensitive data
 | 
					        # send to interaction because of sensitive data
 | 
				
			||||||
        await self._message_service.send_interaction_msg(ctx.interaction, embed, wait_before_delete=wait)
 | 
					        await self._message_service.send_interaction_msg(ctx.interaction, embed, wait_before_delete=wait)
 | 
				
			||||||
        self._logger.trace(__name__, f'Finished user-info command')
 | 
					        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-info {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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        match atr:
 | 
				
			||||||
 | 
					            case 'xp':
 | 
				
			||||||
 | 
					                value = str(user.xp)
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            case '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
 | 
				
			||||||
 | 
					                ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case other:
 | 
				
			||||||
 | 
					                await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.get.atr_not_found').format(atr))
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await self._message_service.send_interaction_msg(
 | 
				
			||||||
 | 
					            ctx.interaction,
 | 
				
			||||||
 | 
					            self._t.transform(f'modules.base.user.get.{atr}').format(member.mention, value)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @get.autocomplete('atr')
 | 
				
			||||||
 | 
					    async def get_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]:
 | 
				
			||||||
 | 
					        atr_list = ['xp', 'ontime']
 | 
				
			||||||
 | 
					        return [app_commands.Choice(name=atr, value=atr) for atr in atr_list]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "",
 | 
					    "LicenseName": "",
 | 
				
			||||||
    "LicenseDescription": "",
 | 
					    "LicenseDescription": "",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core>=2022.10.0.post2"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli==2022.10.0"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "MIT",
 | 
					    "LicenseName": "MIT",
 | 
				
			||||||
    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
					    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core>=2022.10.0.post2"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli==2022.10.0"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "",
 | 
					    "LicenseName": "",
 | 
				
			||||||
    "LicenseDescription": "",
 | 
					    "LicenseDescription": "",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core>=2022.10.0.post7"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli>=2022.10.1"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -88,7 +88,7 @@ class LevelSeeder(DataSeederABC):
 | 
				
			|||||||
                if levels.where(lambda l: l.name == role.name).count() == 0:
 | 
					                if levels.where(lambda l: l.name == role.name).count() == 0:
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                new_position = position_above_levels - (levels.index(levels.where(lambda l: l.name == role.name).single()) + 1)
 | 
					                new_position = position_above_levels - (levels.index_of(levels.where(lambda l: l.name == role.name).single()) + 1)
 | 
				
			||||||
                if new_position <= 0:
 | 
					                if new_position <= 0:
 | 
				
			||||||
                    new_position = 1
 | 
					                    new_position = 1
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "",
 | 
					    "LicenseName": "",
 | 
				
			||||||
    "LicenseDescription": "",
 | 
					    "LicenseDescription": "",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core>=2022.10.0.post2"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli==2022.10.0"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "",
 | 
					    "LicenseName": "",
 | 
				
			||||||
    "LicenseDescription": "",
 | 
					    "LicenseDescription": "",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core>=2022.10.0.post7"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli>=2022.10.1"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "",
 | 
					    "LicenseName": "",
 | 
				
			||||||
    "LicenseDescription": "",
 | 
					    "LicenseDescription": "",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core>=2022.10.0.post7"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli>=2022.10.0"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.6",
 | 
					    "PythonVersion": ">=3.10.6",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
# imports:
 | 
					 | 
				
			||||||
@@ -1,16 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "DatabaseSettings": {
 | 
					 | 
				
			||||||
    "Host": "localhost",
 | 
					 | 
				
			||||||
    "User": "kd_kdb",
 | 
					 | 
				
			||||||
    "Password": "",
 | 
					 | 
				
			||||||
    "Database": "keksdose_bot_dev",
 | 
					 | 
				
			||||||
    "Charset": "utf8mb4",
 | 
					 | 
				
			||||||
    "UseUnicode": "true",
 | 
					 | 
				
			||||||
    "Buffered": "true",
 | 
					 | 
				
			||||||
    "AuthPlugin": "mysql_native_password"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "DiscordBot": {
 | 
					 | 
				
			||||||
    "Token": "",
 | 
					 | 
				
			||||||
    "Prefix": "!kab-e "
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,54 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "TimeFormatSettings": {
 | 
					 | 
				
			||||||
    "DateFormat": "%Y-%m-%d",
 | 
					 | 
				
			||||||
    "TimeFormat": "%H:%M:%S",
 | 
					 | 
				
			||||||
    "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
 | 
					 | 
				
			||||||
    "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "LoggingSettings": {
 | 
					 | 
				
			||||||
    "Path": "logs/$date_now/",
 | 
					 | 
				
			||||||
    "Filename": "bot.log",
 | 
					 | 
				
			||||||
    "ConsoleLogLevel": "ERROR",
 | 
					 | 
				
			||||||
    "FileLogLevel": "WARN"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "BotLoggingSettings": {
 | 
					 | 
				
			||||||
    "Api": {
 | 
					 | 
				
			||||||
      "Path": "logs/$date_now/",
 | 
					 | 
				
			||||||
      "Filename": "api.log",
 | 
					 | 
				
			||||||
      "ConsoleLogLevel": "INFO",
 | 
					 | 
				
			||||||
      "FileLogLevel": "DEBUG"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "Command": {
 | 
					 | 
				
			||||||
      "Path": "logs/$date_now/",
 | 
					 | 
				
			||||||
      "Filename": "commands.log",
 | 
					 | 
				
			||||||
      "ConsoleLogLevel": "INFO",
 | 
					 | 
				
			||||||
      "FileLogLevel": "DEBUG"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "Database": {
 | 
					 | 
				
			||||||
      "Path": "logs/$date_now/",
 | 
					 | 
				
			||||||
      "Filename": "database.log",
 | 
					 | 
				
			||||||
      "ConsoleLogLevel": "INFO",
 | 
					 | 
				
			||||||
      "FileLogLevel": "DEBUG"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "Message": {
 | 
					 | 
				
			||||||
      "Path": "logs/$date_now/",
 | 
					 | 
				
			||||||
      "Filename": "message.log",
 | 
					 | 
				
			||||||
      "ConsoleLogLevel": "INFO",
 | 
					 | 
				
			||||||
      "FileLogLevel": "DEBUG"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "Translation": {
 | 
					 | 
				
			||||||
    "DefaultLanguage": "de",
 | 
					 | 
				
			||||||
    "Languages": [
 | 
					 | 
				
			||||||
      "de"
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "TestSettings": {
 | 
					 | 
				
			||||||
    "LoginUrl": "https://discord.com/login",
 | 
					 | 
				
			||||||
    "MePageUrl": "https://discord.com/channels/@me",
 | 
					 | 
				
			||||||
    "CmdURL": "https://discord.com/channels/910199451145076828/911578636899987526",
 | 
					 | 
				
			||||||
    "GuildId": 910199451145076828,
 | 
					 | 
				
			||||||
    "BotId": 998159802393964594,
 | 
					 | 
				
			||||||
    "TestUserId": 401941112010571777
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,34 +0,0 @@
 | 
				
			|||||||
import asyncio
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from cpl_core.application import ApplicationABC
 | 
					 | 
				
			||||||
from cpl_core.application import ApplicationBuilder
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from startup_test_extension import StartupTestExtension
 | 
					 | 
				
			||||||
from ui_tests.startup import Startup
 | 
					 | 
				
			||||||
from ui_tests_shared.declarations import Declarations
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
try:
 | 
					 | 
				
			||||||
    from test_application import TestApplication
 | 
					 | 
				
			||||||
except ImportError:
 | 
					 | 
				
			||||||
    from .test_application import TestApplication
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def get_app() -> ApplicationABC:
 | 
					 | 
				
			||||||
    app_builder = ApplicationBuilder(TestApplication) \
 | 
					 | 
				
			||||||
        .use_extension(StartupTestExtension) \
 | 
					 | 
				
			||||||
        .use_startup(Startup)
 | 
					 | 
				
			||||||
    app = app_builder.build()
 | 
					 | 
				
			||||||
    Declarations.app = app
 | 
					 | 
				
			||||||
    return app
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async def main():
 | 
					 | 
				
			||||||
    app = get_app()
 | 
					 | 
				
			||||||
    await app.run_async()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == '__main__':
 | 
					 | 
				
			||||||
    import nest_asyncio
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    nest_asyncio.apply()
 | 
					 | 
				
			||||||
    asyncio.run(main())
 | 
					 | 
				
			||||||
@@ -1,118 +0,0 @@
 | 
				
			|||||||
import os
 | 
					 | 
				
			||||||
from typing import Optional
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from cpl_core.application import StartupABC
 | 
					 | 
				
			||||||
from cpl_core.configuration import ConfigurationABC
 | 
					 | 
				
			||||||
from cpl_core.database import DatabaseSettings
 | 
					 | 
				
			||||||
from cpl_core.dependency_injection import ServiceCollectionABC
 | 
					 | 
				
			||||||
from cpl_core.dependency_injection import ServiceProviderABC
 | 
					 | 
				
			||||||
from cpl_core.environment import ApplicationEnvironment
 | 
					 | 
				
			||||||
from cpl_discord import get_discord_collection
 | 
					 | 
				
			||||||
from cpl_discord.discord_event_types_enum import DiscordEventTypesEnum
 | 
					 | 
				
			||||||
from dotenv import load_dotenv
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from bot.startup_settings_extension import StartupSettingsExtension
 | 
					 | 
				
			||||||
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC
 | 
					 | 
				
			||||||
from bot_core.abc.custom_file_logger_abc import CustomFileLoggerABC
 | 
					 | 
				
			||||||
from bot_core.abc.message_service_abc import MessageServiceABC
 | 
					 | 
				
			||||||
from bot_core.configuration.bot_logging_settings import BotLoggingSettings
 | 
					 | 
				
			||||||
from bot_core.logging.command_logger import CommandLogger
 | 
					 | 
				
			||||||
from bot_core.logging.database_logger import DatabaseLogger
 | 
					 | 
				
			||||||
from bot_core.logging.message_logger import MessageLogger
 | 
					 | 
				
			||||||
from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
 | 
					 | 
				
			||||||
from bot_core.service.client_utils_service import ClientUtilsService
 | 
					 | 
				
			||||||
from bot_core.service.message_service import MessageService
 | 
					 | 
				
			||||||
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
 | 
					 | 
				
			||||||
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
 | 
					 | 
				
			||||||
from bot_data.abc.client_repository_abc import ClientRepositoryABC
 | 
					 | 
				
			||||||
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
 | 
					 | 
				
			||||||
from bot_data.abc.level_repository_abc import LevelRepositoryABC
 | 
					 | 
				
			||||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
 | 
					 | 
				
			||||||
from bot_data.abc.statistic_repository_abc import StatisticRepositoryABC
 | 
					 | 
				
			||||||
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 bot_data.db_context import DBContext
 | 
					 | 
				
			||||||
from bot_data.service.auth_user_repository_service import AuthUserRepositoryService
 | 
					 | 
				
			||||||
from bot_data.service.auto_role_repository_service import AutoRoleRepositoryService
 | 
					 | 
				
			||||||
from bot_data.service.client_repository_service import ClientRepositoryService
 | 
					 | 
				
			||||||
from bot_data.service.known_user_repository_service import KnownUserRepositoryService
 | 
					 | 
				
			||||||
from bot_data.service.level_repository_service import LevelRepositoryService
 | 
					 | 
				
			||||||
from bot_data.service.seeder_service import SeederService
 | 
					 | 
				
			||||||
from bot_data.service.server_repository_service import ServerRepositoryService
 | 
					 | 
				
			||||||
from bot_data.service.statistic_repository_service import StatisticRepositoryService
 | 
					 | 
				
			||||||
from bot_data.service.user_joined_server_repository_service import UserJoinedServerRepositoryService
 | 
					 | 
				
			||||||
from bot_data.service.user_joined_voice_channel_service import UserJoinedVoiceChannelRepositoryService
 | 
					 | 
				
			||||||
from bot_data.service.user_repository_service import UserRepositoryService
 | 
					 | 
				
			||||||
from ui_tests.test_on_ready_event import TestOnReadyEvent
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Startup(StartupABC):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self):
 | 
					 | 
				
			||||||
        StartupABC.__init__(self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self._config: Optional[ConfigurationABC] = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def configure_configuration(self, configuration: ConfigurationABC, environment: ApplicationEnvironment) -> ConfigurationABC:
 | 
					 | 
				
			||||||
        load_dotenv()
 | 
					 | 
				
			||||||
        configuration.add_environment_variables('KDB_TEST_')
 | 
					 | 
				
			||||||
        configuration.add_environment_variables('DISCORD_')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cwd = os.path.dirname(os.path.realpath(__file__))
 | 
					 | 
				
			||||||
        configuration.add_json_file(f'{cwd}/config/appsettings.json', optional=False)
 | 
					 | 
				
			||||||
        configuration.add_json_file(f'{cwd}/config/appsettings.{environment.host_name}.json', optional=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        StartupSettingsExtension._configure_settings_with_sub_settings(configuration, BotLoggingSettings, lambda x: x.files, lambda x: x.key)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self._config = configuration
 | 
					 | 
				
			||||||
        return configuration
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def configure_services(self, services: ServiceCollectionABC, environment: ApplicationEnvironment) -> ServiceProviderABC:
 | 
					 | 
				
			||||||
        services.add_logging()
 | 
					 | 
				
			||||||
        services.add_singleton(CustomFileLoggerABC, CommandLogger)
 | 
					 | 
				
			||||||
        services.add_singleton(CustomFileLoggerABC, DatabaseLogger)
 | 
					 | 
				
			||||||
        services.add_singleton(CustomFileLoggerABC, MessageLogger)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        services.add_translation()
 | 
					 | 
				
			||||||
        db_settings: DatabaseSettings = self._config.get_configuration(DatabaseSettings)
 | 
					 | 
				
			||||||
        db_settings_with_pw = DatabaseSettings()
 | 
					 | 
				
			||||||
        pw = self._config.get_configuration('DB_PASSWORD')
 | 
					 | 
				
			||||||
        db_settings_with_pw.from_dict({
 | 
					 | 
				
			||||||
            "Host": db_settings.host,
 | 
					 | 
				
			||||||
            "User": db_settings.user,
 | 
					 | 
				
			||||||
            "Password": '' if pw is None else pw,
 | 
					 | 
				
			||||||
            "Database": db_settings.database,
 | 
					 | 
				
			||||||
            "Charset": db_settings.charset,
 | 
					 | 
				
			||||||
            "UseUnicode": db_settings.use_unicode,
 | 
					 | 
				
			||||||
            "Buffered": db_settings.buffered,
 | 
					 | 
				
			||||||
            "AuthPlugin": db_settings.auth_plugin
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        services.add_db_context(DBContext, db_settings_with_pw)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        services.add_discord()
 | 
					 | 
				
			||||||
        dc = get_discord_collection(services)
 | 
					 | 
				
			||||||
        dc.add_event(DiscordEventTypesEnum.on_ready.value, TestOnReadyEvent)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # bot_core stuff
 | 
					 | 
				
			||||||
        services.add_transient(MessageServiceABC, MessageService)
 | 
					 | 
				
			||||||
        services.add_transient(ClientUtilsServiceABC, ClientUtilsService)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # pipes
 | 
					 | 
				
			||||||
        services.add_transient(DateTimeOffsetPipe)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # data stuff
 | 
					 | 
				
			||||||
        services.add_transient(AuthUserRepositoryABC, AuthUserRepositoryService)
 | 
					 | 
				
			||||||
        services.add_transient(ServerRepositoryABC, ServerRepositoryService)
 | 
					 | 
				
			||||||
        services.add_transient(UserRepositoryABC, UserRepositoryService)
 | 
					 | 
				
			||||||
        services.add_transient(ClientRepositoryABC, ClientRepositoryService)
 | 
					 | 
				
			||||||
        services.add_transient(KnownUserRepositoryABC, KnownUserRepositoryService)
 | 
					 | 
				
			||||||
        services.add_transient(UserJoinedServerRepositoryABC, UserJoinedServerRepositoryService)
 | 
					 | 
				
			||||||
        services.add_transient(UserJoinedVoiceChannelRepositoryABC, UserJoinedVoiceChannelRepositoryService)
 | 
					 | 
				
			||||||
        services.add_transient(AutoRoleRepositoryABC, AutoRoleRepositoryService)
 | 
					 | 
				
			||||||
        services.add_transient(LevelRepositoryABC, LevelRepositoryService)
 | 
					 | 
				
			||||||
        services.add_transient(StatisticRepositoryABC, StatisticRepositoryService)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        services.add_transient(SeederService)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return services.build_service_provider()
 | 
					 | 
				
			||||||
@@ -1,20 +0,0 @@
 | 
				
			|||||||
import os
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from cpl_core.application import StartupExtensionABC
 | 
					 | 
				
			||||||
from cpl_core.configuration import ConfigurationABC
 | 
					 | 
				
			||||||
from cpl_core.dependency_injection import ServiceCollectionABC
 | 
					 | 
				
			||||||
from cpl_core.environment import ApplicationEnvironmentABC
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class StartupTestExtension(StartupExtensionABC):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self):
 | 
					 | 
				
			||||||
        StartupExtensionABC.__init__(self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def configure_configuration(self, configuration: ConfigurationABC, environment: ApplicationEnvironmentABC):
 | 
					 | 
				
			||||||
        # this shit has to be done here because we need settings in subsequent startup extensions
 | 
					 | 
				
			||||||
        environment.set_working_directory(os.path.dirname(os.path.realpath(__file__)))
 | 
					 | 
				
			||||||
        environment.set_working_directory('../../src/bot/')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
 | 
					 | 
				
			||||||
        pass
 | 
					 | 
				
			||||||
@@ -1,64 +0,0 @@
 | 
				
			|||||||
from cpl_core.configuration import ConfigurationABC
 | 
					 | 
				
			||||||
from cpl_core.dependency_injection import ServiceProviderABC
 | 
					 | 
				
			||||||
from cpl_discord.application import DiscordBotApplicationABC
 | 
					 | 
				
			||||||
from cpl_discord.configuration import DiscordBotSettings
 | 
					 | 
				
			||||||
from cpl_discord.service import DiscordBotServiceABC
 | 
					 | 
				
			||||||
from cpl_translation import TranslationSettings, TranslationServiceABC
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from bot_core.configuration.bot_settings import BotSettings
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TestApplication(DiscordBotApplicationABC):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self, config: ConfigurationABC, services: ServiceProviderABC):
 | 
					 | 
				
			||||||
        DiscordBotApplicationABC.__init__(self, config, services)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self._config = config
 | 
					 | 
				
			||||||
        self._services = services
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self._bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC)
 | 
					 | 
				
			||||||
        self._translation: TranslationServiceABC = services.get_service(TranslationServiceABC)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        discord_bot_settings: DiscordBotSettings = config.get_configuration(DiscordBotSettings)
 | 
					 | 
				
			||||||
        self._discord_settings = self._get_settings(discord_bot_settings)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _get_settings(self, settings_from_config: DiscordBotSettings) -> DiscordBotSettings:
 | 
					 | 
				
			||||||
        new_settings = DiscordBotSettings()
 | 
					 | 
				
			||||||
        token = None if settings_from_config is None else settings_from_config.token
 | 
					 | 
				
			||||||
        prefix = None if settings_from_config is None else settings_from_config.prefix
 | 
					 | 
				
			||||||
        env_token = self._config.get_configuration('TOKEN')
 | 
					 | 
				
			||||||
        env_prefix = self._config.get_configuration('PREFIX')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        new_settings.from_dict({
 | 
					 | 
				
			||||||
            'Token': env_token if token is None or token == '' else token,
 | 
					 | 
				
			||||||
            'Prefix': ('! ' if self._is_string_invalid(env_prefix) else env_prefix) if self._is_string_invalid(prefix) else prefix
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        if new_settings.token is None or new_settings.token == '':
 | 
					 | 
				
			||||||
            raise Exception('You have to configure discord token by appsettings or environment variables')
 | 
					 | 
				
			||||||
        return new_settings
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @staticmethod
 | 
					 | 
				
			||||||
    def _is_string_invalid(x):
 | 
					 | 
				
			||||||
        return x is None or x == ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def config(self) -> ConfigurationABC:
 | 
					 | 
				
			||||||
        return self._config
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def services(self) -> ServiceProviderABC:
 | 
					 | 
				
			||||||
        return self._services
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    async def configure(self):
 | 
					 | 
				
			||||||
        self._translation.load_by_settings(self._configuration.get_configuration(TranslationSettings))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    async def main(self):
 | 
					 | 
				
			||||||
        if self._config.get_configuration('IS_UNITTEST'):
 | 
					 | 
				
			||||||
            await self._bot.login(self._discord_settings.token)
 | 
					 | 
				
			||||||
            self._bot.loop.create_task(self._bot.connect())
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await self._bot.start_async()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    async def stop_async(self):
 | 
					 | 
				
			||||||
        await self._bot.close()
 | 
					 | 
				
			||||||
@@ -1,47 +0,0 @@
 | 
				
			|||||||
import os
 | 
					 | 
				
			||||||
import unittest
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from cpl_core.configuration import ConfigurationABC
 | 
					 | 
				
			||||||
from cpl_core.console import Console, ForegroundColorEnum
 | 
					 | 
				
			||||||
from cpl_core.dependency_injection import ServiceProviderABC
 | 
					 | 
				
			||||||
from cpl_core.logging import LoggerABC
 | 
					 | 
				
			||||||
from cpl_discord.events import OnReadyABC
 | 
					 | 
				
			||||||
from cpl_discord.service import DiscordBotServiceABC
 | 
					 | 
				
			||||||
from cpl_translation import TranslatePipe
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TestOnReadyEvent(OnReadyABC):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(
 | 
					 | 
				
			||||||
            self,
 | 
					 | 
				
			||||||
            config: ConfigurationABC,
 | 
					 | 
				
			||||||
            bot: DiscordBotServiceABC,
 | 
					 | 
				
			||||||
            services: ServiceProviderABC,
 | 
					 | 
				
			||||||
            client_utils: ClientUtilsServiceABC,
 | 
					 | 
				
			||||||
            t: TranslatePipe
 | 
					 | 
				
			||||||
    ):
 | 
					 | 
				
			||||||
        OnReadyABC.__init__(self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self._config = config
 | 
					 | 
				
			||||||
        self._bot = bot
 | 
					 | 
				
			||||||
        self._services = services
 | 
					 | 
				
			||||||
        self._client_utils = client_utils
 | 
					 | 
				
			||||||
        self._t = t
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    async def on_ready(self):
 | 
					 | 
				
			||||||
        if self._config.get_configuration('IS_UNITTEST'):
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Console.write_line('\nStarting tests:\n')
 | 
					 | 
				
			||||||
        loader = unittest.TestLoader()
 | 
					 | 
				
			||||||
        path = f'{os.path.dirname(os.path.realpath(__file__))}/../'
 | 
					 | 
				
			||||||
        tests = loader.discover(path, pattern='*_test_case.py')
 | 
					 | 
				
			||||||
        runner = unittest.TextTestRunner()
 | 
					 | 
				
			||||||
        runner.run(tests)
 | 
					 | 
				
			||||||
        # for cls in CommandTestABC.__subclasses__():
 | 
					 | 
				
			||||||
        #     service: CommandTestABC = self._services.get_service(cls)
 | 
					 | 
				
			||||||
        #     await service.run(self._tests)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await self._bot.close()
 | 
					 | 
				
			||||||
@@ -1,49 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "ProjectSettings": {
 | 
					 | 
				
			||||||
    "Name": "ui-tests",
 | 
					 | 
				
			||||||
    "Version": {
 | 
					 | 
				
			||||||
      "Major": "0",
 | 
					 | 
				
			||||||
      "Minor": "0",
 | 
					 | 
				
			||||||
      "Micro": "0"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "Author": "",
 | 
					 | 
				
			||||||
    "AuthorEmail": "",
 | 
					 | 
				
			||||||
    "Description": "",
 | 
					 | 
				
			||||||
    "LongDescription": "",
 | 
					 | 
				
			||||||
    "URL": "",
 | 
					 | 
				
			||||||
    "CopyrightDate": "",
 | 
					 | 
				
			||||||
    "CopyrightName": "",
 | 
					 | 
				
			||||||
    "LicenseName": "",
 | 
					 | 
				
			||||||
    "LicenseDescription": "",
 | 
					 | 
				
			||||||
    "Dependencies": [
 | 
					 | 
				
			||||||
      "cpl-core>=2022.10.0.post9",
 | 
					 | 
				
			||||||
      "PyNaCl==1.5.0",
 | 
					 | 
				
			||||||
      "cffi==1.15.1",
 | 
					 | 
				
			||||||
      "pycparser==2.21",
 | 
					 | 
				
			||||||
      "selenium==4.6.1",
 | 
					 | 
				
			||||||
      "webdriver-manager==3.8.5"
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "DevDependencies": [
 | 
					 | 
				
			||||||
      "cpl-cli>=2022.10.0"
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					 | 
				
			||||||
    "PythonPath": {},
 | 
					 | 
				
			||||||
    "Classifiers": []
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "BuildSettings": {
 | 
					 | 
				
			||||||
    "ProjectType": "console",
 | 
					 | 
				
			||||||
    "SourcePath": "",
 | 
					 | 
				
			||||||
    "OutputPath": "../../dist",
 | 
					 | 
				
			||||||
    "Main": "ui_tests_shared.main",
 | 
					 | 
				
			||||||
    "EntryPoint": "ui-tests-shared",
 | 
					 | 
				
			||||||
    "IncludePackageData": false,
 | 
					 | 
				
			||||||
    "Included": [],
 | 
					 | 
				
			||||||
    "Excluded": [
 | 
					 | 
				
			||||||
      "*/__pycache__",
 | 
					 | 
				
			||||||
      "*/logs",
 | 
					 | 
				
			||||||
      "*/tests"
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "PackageData": {},
 | 
					 | 
				
			||||||
    "ProjectReferences": []
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
# imports: 
 | 
					 | 
				
			||||||
@@ -1,15 +0,0 @@
 | 
				
			|||||||
from enum import Enum
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CommandSelectorsEnum(Enum):
 | 
					 | 
				
			||||||
    cmd_chat = '/html/body/div[1]/div[2]/div/div[1]/div/div[2]/div/div[1]/div/div/div[3]/div[2]/main/form/div/div[1]/div/div[3]/div/div[2]/div'
 | 
					 | 
				
			||||||
    cmd_chat_input = '/html/body/div[1]/div[2]/div/div[1]/div/div[2]/div/div[1]/div/div/div[3]/div/main/form/div/div[2]/div/div[2]/div/div'
 | 
					 | 
				
			||||||
    msg_input = '/html/body/div[1]/div[2]/div/div[1]/div/div[2]/div/div[1]/div/div/div[3]/div[2]/main/form/div/div[1]/div/div[3]/div/div/div'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    kdb_test = "//*[contains (text(), 'Krümmelmonster-test')]"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ping = kdb_test
 | 
					 | 
				
			||||||
    info = kdb_test
 | 
					 | 
				
			||||||
    help = kdb_test
 | 
					 | 
				
			||||||
    afk = kdb_test
 | 
					 | 
				
			||||||
    purge = kdb_test
 | 
					 | 
				
			||||||
@@ -1,62 +0,0 @@
 | 
				
			|||||||
import time
 | 
					 | 
				
			||||||
from typing import Optional
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from cpl_discord.service import DiscordBotServiceABC
 | 
					 | 
				
			||||||
from cpl_translation import TranslatePipe
 | 
					 | 
				
			||||||
from selenium.common import NoSuchElementException, StaleElementReferenceException
 | 
					 | 
				
			||||||
from selenium.webdriver import Keys
 | 
					 | 
				
			||||||
from selenium.webdriver.common.by import By
 | 
					 | 
				
			||||||
from selenium.webdriver.remote.webelement import WebElement
 | 
					 | 
				
			||||||
from selenium.webdriver.support import expected_conditions
 | 
					 | 
				
			||||||
from selenium.webdriver.support.wait import WebDriverWait
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from ui_tests_shared.command_selectors_enum import CommandSelectorsEnum
 | 
					 | 
				
			||||||
from ui_tests_shared.test_case_with_app import TestCaseWithApp
 | 
					 | 
				
			||||||
from ui_tests_shared.ui import UI
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CommandTestCaseWithApp(TestCaseWithApp):
 | 
					 | 
				
			||||||
    _cmd: WebElement
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _bot: Optional[DiscordBotServiceABC] = None
 | 
					 | 
				
			||||||
    _t: Optional[TranslatePipe] = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def setUpClass(cls):
 | 
					 | 
				
			||||||
        TestCaseWithApp.setUpClass()
 | 
					 | 
				
			||||||
        cls._bot = cls._services.get_service(DiscordBotServiceABC)
 | 
					 | 
				
			||||||
        cls._t = cls._services.get_service(TranslatePipe)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def send_message(cls, msg: str):
 | 
					 | 
				
			||||||
        if UI.driver.current_url != cls._test_settings.cmd_url:
 | 
					 | 
				
			||||||
            UI.driver.get(cls._test_settings.cmd_url)
 | 
					 | 
				
			||||||
            time.sleep(2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cmd_element_ident = (By.XPATH, CommandSelectorsEnum.cmd_chat.value)
 | 
					 | 
				
			||||||
        cmd_element = UI.driver.find_element(*cmd_element_ident)
 | 
					 | 
				
			||||||
        cmd_element.send_keys(msg)
 | 
					 | 
				
			||||||
        time.sleep(2)
 | 
					 | 
				
			||||||
        UI.driver.find_element(By.XPATH, CommandSelectorsEnum.msg_input.value).send_keys(Keys.ENTER)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def send_command(cls, cmd: str, selector: CommandSelectorsEnum, reload=True):
 | 
					 | 
				
			||||||
        if reload or UI.driver.current_url != cls._test_settings.cmd_url:
 | 
					 | 
				
			||||||
            UI.driver.get(cls._test_settings.cmd_url)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        time.sleep(2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cmd_element_ident = (By.XPATH, CommandSelectorsEnum.cmd_chat.value)
 | 
					 | 
				
			||||||
        cmd_element = UI.driver.find_element(*cmd_element_ident)
 | 
					 | 
				
			||||||
        cmd_element.send_keys(f'/{cmd}')
 | 
					 | 
				
			||||||
        time.sleep(2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ignored_exceptions = (NoSuchElementException, StaleElementReferenceException,)
 | 
					 | 
				
			||||||
        WebDriverWait(UI.driver, 20, ignored_exceptions=ignored_exceptions).until(
 | 
					 | 
				
			||||||
            expected_conditions.presence_of_element_located((
 | 
					 | 
				
			||||||
                By.XPATH,
 | 
					 | 
				
			||||||
                selector.value
 | 
					 | 
				
			||||||
            ))
 | 
					 | 
				
			||||||
        ).click()
 | 
					 | 
				
			||||||
        time.sleep(2)
 | 
					 | 
				
			||||||
        UI.driver.find_element(By.XPATH, CommandSelectorsEnum.cmd_chat_input.value).send_keys(Keys.ENTER)
 | 
					 | 
				
			||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
# imports
 | 
					 | 
				
			||||||
@@ -1,53 +0,0 @@
 | 
				
			|||||||
import traceback
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
 | 
					 | 
				
			||||||
from cpl_core.console import Console
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TestSettings(ConfigurationModelABC):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self):
 | 
					 | 
				
			||||||
        ConfigurationModelABC.__init__(self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self._login_url = ''
 | 
					 | 
				
			||||||
        self._me_page_url = ''
 | 
					 | 
				
			||||||
        self._cmd_url = ''
 | 
					 | 
				
			||||||
        self._guild_id = 0
 | 
					 | 
				
			||||||
        self._bot_id = 0
 | 
					 | 
				
			||||||
        self._test_user_id = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def login_url(self) -> str:
 | 
					 | 
				
			||||||
        return self._login_url
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def me_page_url(self) -> str:
 | 
					 | 
				
			||||||
        return self._me_page_url
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def cmd_url(self) -> str:
 | 
					 | 
				
			||||||
        return self._cmd_url
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def guild_id(self) -> int:
 | 
					 | 
				
			||||||
        return self._guild_id
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def bot_id(self) -> int:
 | 
					 | 
				
			||||||
        return self._bot_id
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def test_user_id(self) -> int:
 | 
					 | 
				
			||||||
        return self._test_user_id
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def from_dict(self, settings: dict):
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            self._login_url = settings['LoginUrl']
 | 
					 | 
				
			||||||
            self._me_page_url = settings['MePageUrl']
 | 
					 | 
				
			||||||
            self._cmd_url = settings['CmdURL']
 | 
					 | 
				
			||||||
            self._guild_id = settings['GuildId']
 | 
					 | 
				
			||||||
            self._bot_id = settings['BotId']
 | 
					 | 
				
			||||||
            self._test_user_id = settings['TestUserId']
 | 
					 | 
				
			||||||
        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,12 +0,0 @@
 | 
				
			|||||||
from typing import Optional
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from cpl_core.environment import ApplicationEnvironmentABC
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from ui_tests.test_application import TestApplication
 | 
					 | 
				
			||||||
from ui_tests_shared.configuration.test_settings import TestSettings
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Declarations:
 | 
					 | 
				
			||||||
    app: Optional[TestApplication] = None
 | 
					 | 
				
			||||||
    env: Optional[ApplicationEnvironmentABC] = None
 | 
					 | 
				
			||||||
    test_settings: Optional[TestSettings] = None
 | 
					 | 
				
			||||||
@@ -1,18 +0,0 @@
 | 
				
			|||||||
import asyncio
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Async:
 | 
					 | 
				
			||||||
    _loop = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def async_func(cls, coro):
 | 
					 | 
				
			||||||
        def wrapper(*args, **kwargs):
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                if cls._loop is None:
 | 
					 | 
				
			||||||
                    cls._loop = asyncio.get_event_loop()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return cls._loop.run_until_complete(coro(*args, **kwargs))
 | 
					 | 
				
			||||||
            except Exception as e:
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return wrapper
 | 
					 | 
				
			||||||
@@ -1,44 +0,0 @@
 | 
				
			|||||||
import asyncio
 | 
					 | 
				
			||||||
import time
 | 
					 | 
				
			||||||
import unittest
 | 
					 | 
				
			||||||
from typing import Optional
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from cpl_core.configuration import ConfigurationABC
 | 
					 | 
				
			||||||
from cpl_core.dependency_injection import ServiceProviderABC
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from ui_tests.main import get_app
 | 
					 | 
				
			||||||
from ui_tests_shared.configuration.test_settings import TestSettings
 | 
					 | 
				
			||||||
from ui_tests_shared.declarations import Declarations
 | 
					 | 
				
			||||||
from ui_tests_shared.ui import UI
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TestCaseWithApp(unittest.TestCase):
 | 
					 | 
				
			||||||
    _config: Optional[ConfigurationABC] = None
 | 
					 | 
				
			||||||
    _services: Optional[ServiceProviderABC] = None
 | 
					 | 
				
			||||||
    _test_settings: Optional[TestSettings] = None
 | 
					 | 
				
			||||||
    _loop = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def setUpClass(cls):
 | 
					 | 
				
			||||||
        if Declarations.app is None:
 | 
					 | 
				
			||||||
            app = get_app()
 | 
					 | 
				
			||||||
            import nest_asyncio
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            nest_asyncio.apply()
 | 
					 | 
				
			||||||
            if cls._loop is None:
 | 
					 | 
				
			||||||
                cls._loop = asyncio.get_event_loop()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            cls._loop.run_until_complete(app.run_async())
 | 
					 | 
				
			||||||
            # asyncio.run(app.run_async())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cls._config = Declarations.app.config
 | 
					 | 
				
			||||||
        cls._services = Declarations.app.services
 | 
					 | 
				
			||||||
        cls._test_settings: TestSettings = cls._config.get_configuration(TestSettings)
 | 
					 | 
				
			||||||
        UI.set_settings(cls._test_settings)
 | 
					 | 
				
			||||||
        UI.login(cls._config.get_configuration('DISCORD_MAIL'), cls._config.get_configuration('DISCORD_PASSWORD'))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def tearDownClass(cls):
 | 
					 | 
				
			||||||
        if cls._config.get_configuration('IS_UNITTEST'):
 | 
					 | 
				
			||||||
            loop = asyncio.get_event_loop()
 | 
					 | 
				
			||||||
            loop.run_until_complete(Declarations.app.stop_async())
 | 
					 | 
				
			||||||
@@ -1,44 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "ProjectSettings": {
 | 
					 | 
				
			||||||
    "Name": "ui-tests-shared",
 | 
					 | 
				
			||||||
    "Version": {
 | 
					 | 
				
			||||||
      "Major": "0",
 | 
					 | 
				
			||||||
      "Minor": "0",
 | 
					 | 
				
			||||||
      "Micro": "0"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "Author": "",
 | 
					 | 
				
			||||||
    "AuthorEmail": "",
 | 
					 | 
				
			||||||
    "Description": "",
 | 
					 | 
				
			||||||
    "LongDescription": "",
 | 
					 | 
				
			||||||
    "URL": "",
 | 
					 | 
				
			||||||
    "CopyrightDate": "",
 | 
					 | 
				
			||||||
    "CopyrightName": "",
 | 
					 | 
				
			||||||
    "LicenseName": "",
 | 
					 | 
				
			||||||
    "LicenseDescription": "",
 | 
					 | 
				
			||||||
    "Dependencies": [
 | 
					 | 
				
			||||||
      "cpl-core>=2022.10.0.post9"
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "DevDependencies": [
 | 
					 | 
				
			||||||
      "cpl-cli>=2022.10.0"
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					 | 
				
			||||||
    "PythonPath": {},
 | 
					 | 
				
			||||||
    "Classifiers": []
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "BuildSettings": {
 | 
					 | 
				
			||||||
    "ProjectType": "console",
 | 
					 | 
				
			||||||
    "SourcePath": "",
 | 
					 | 
				
			||||||
    "OutputPath": "../../dist",
 | 
					 | 
				
			||||||
    "Main": "ui_tests_shared.main",
 | 
					 | 
				
			||||||
    "EntryPoint": "ui-tests-shared",
 | 
					 | 
				
			||||||
    "IncludePackageData": false,
 | 
					 | 
				
			||||||
    "Included": [],
 | 
					 | 
				
			||||||
    "Excluded": [
 | 
					 | 
				
			||||||
      "*/__pycache__",
 | 
					 | 
				
			||||||
      "*/logs",
 | 
					 | 
				
			||||||
      "*/tests"
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "PackageData": {},
 | 
					 | 
				
			||||||
    "ProjectReferences": []
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,69 +0,0 @@
 | 
				
			|||||||
import time
 | 
					 | 
				
			||||||
import unittest
 | 
					 | 
				
			||||||
from typing import Optional
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from cpl_core.configuration import ConfigurationABC
 | 
					 | 
				
			||||||
from cpl_core.dependency_injection import ServiceProviderABC
 | 
					 | 
				
			||||||
from selenium import webdriver
 | 
					 | 
				
			||||||
from selenium.webdriver import Keys
 | 
					 | 
				
			||||||
from selenium.webdriver.common.by import By
 | 
					 | 
				
			||||||
from selenium.webdriver.support import expected_conditions
 | 
					 | 
				
			||||||
from selenium.webdriver.support.wait import WebDriverWait
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from ui_tests.main import get_app
 | 
					 | 
				
			||||||
from ui_tests_shared.configuration.test_settings import TestSettings
 | 
					 | 
				
			||||||
from ui_tests_shared.declarations import Declarations
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class UI:
 | 
					 | 
				
			||||||
    _test_settings: Optional[TestSettings] = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    options = webdriver.ChromeOptions()
 | 
					 | 
				
			||||||
    options.add_argument("user-data-dir=selenium-data")
 | 
					 | 
				
			||||||
    options.add_experimental_option('useAutomationExtension', False)
 | 
					 | 
				
			||||||
    options.add_experimental_option("excludeSwitches", ["enable-automation"])
 | 
					 | 
				
			||||||
    options.add_experimental_option("prefs", {
 | 
					 | 
				
			||||||
        "profile.default_content_setting_values.media_stream_mic": 1,
 | 
					 | 
				
			||||||
        "profile.default_content_setting_values.media_stream_camera": 1,
 | 
					 | 
				
			||||||
        "profile.default_content_setting_values.geolocation": 1,
 | 
					 | 
				
			||||||
        "profile.default_content_setting_values.notifications": 1
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    driver = webdriver.Chrome(options=options)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _is_logged_in = False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def set_settings(cls, test_settings: TestSettings):
 | 
					 | 
				
			||||||
        cls._test_settings = test_settings
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def login(cls, mail: str, password: str):
 | 
					 | 
				
			||||||
        if cls._is_logged_in:
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # use full xpath: https://stackoverflow.com/questions/71179006/how-can-selenium-python-chrome-find-web-elements-visible-in-dev-tools-but-no
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cls.driver.get(cls._test_settings.login_url)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            WebDriverWait(cls.driver, 10).until(expected_conditions.url_matches(cls._test_settings.me_page_url))
 | 
					 | 
				
			||||||
            cls._is_logged_in = True
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
        except Exception as e:
 | 
					 | 
				
			||||||
            WebDriverWait(cls.driver, 20).until(expected_conditions.presence_of_element_located((By.NAME, 'email')))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        mail_element = cls.driver.find_element(By.NAME, 'email')
 | 
					 | 
				
			||||||
        mail_element.clear()
 | 
					 | 
				
			||||||
        mail_element.send_keys(mail)
 | 
					 | 
				
			||||||
        mail_element.send_keys(Keys.RETURN)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        pw_element = cls.driver.find_element(By.NAME, 'password')
 | 
					 | 
				
			||||||
        pw_element.clear()
 | 
					 | 
				
			||||||
        pw_element.send_keys(password)
 | 
					 | 
				
			||||||
        pw_element.send_keys(Keys.RETURN)
 | 
					 | 
				
			||||||
        time.sleep(1)
 | 
					 | 
				
			||||||
        pw_element.send_keys(Keys.RETURN)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        WebDriverWait(cls.driver, 20).until(expected_conditions.url_matches(cls._test_settings.me_page_url))
 | 
					 | 
				
			||||||
        time.sleep(4)
 | 
					 | 
				
			||||||
        cls._is_logged_in = True
 | 
					 | 
				
			||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
# imports: 
 | 
					 | 
				
			||||||
@@ -1,15 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "TimeFormatSettings": {
 | 
					 | 
				
			||||||
    "DateFormat": "%Y-%m-%d",
 | 
					 | 
				
			||||||
    "TimeFormat": "%H:%M:%S",
 | 
					 | 
				
			||||||
    "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
 | 
					 | 
				
			||||||
    "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  "LoggingSettings": {
 | 
					 | 
				
			||||||
    "Path": "logs/",
 | 
					 | 
				
			||||||
    "Filename": "log_$start_time.log",
 | 
					 | 
				
			||||||
    "ConsoleLogLevel": "ERROR",
 | 
					 | 
				
			||||||
    "FileLogLevel": "WARN"
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,48 +0,0 @@
 | 
				
			|||||||
import discord
 | 
					 | 
				
			||||||
from selenium.webdriver.common.by import By
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from ui_tests_shared.command_selectors_enum import CommandSelectorsEnum
 | 
					 | 
				
			||||||
from ui_tests_shared.command_test_case_with_app import CommandTestCaseWithApp
 | 
					 | 
				
			||||||
from ui_tests_shared.decorators import Async
 | 
					 | 
				
			||||||
from ui_tests_shared.ui import UI
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AFKCommandTestCase(CommandTestCaseWithApp):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def tearDownClass(cls):
 | 
					 | 
				
			||||||
        btn = UI.driver.find_elements(By.XPATH, '/html/body/div[1]/div[2]/div/div[1]/div/div[2]/div/div[1]/div/div/div[1]/section/div[1]/div/div[1]/div[2]/button')
 | 
					 | 
				
			||||||
        if len(btn) == 0:
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        btn[0].click()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Async.async_func
 | 
					 | 
				
			||||||
    async def test_error_message(self):
 | 
					 | 
				
			||||||
        correct_response = self._t.transform('modules.base.afk_command_channel_missing_message')
 | 
					 | 
				
			||||||
        self.assertIsNotNone(correct_response)
 | 
					 | 
				
			||||||
        self.send_command('afk', CommandSelectorsEnum.afk, reload=False)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def check(m: discord.Message):
 | 
					 | 
				
			||||||
            return m.author.id == self._test_settings.bot_id
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        response = await self._bot.wait_for('message', check=check, timeout=10)
 | 
					 | 
				
			||||||
        self.assertEqual(response.content, correct_response)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Async.async_func
 | 
					 | 
				
			||||||
    async def test_move(self):
 | 
					 | 
				
			||||||
        # correct_response = self._t.transform('modules.base.pong')
 | 
					 | 
				
			||||||
        # self.assertIsNotNone(correct_response)
 | 
					 | 
				
			||||||
        UI.driver.find_element(By.XPATH, '//*[@id="channels"]/ul/li[20]/div/div/div/a').click()
 | 
					 | 
				
			||||||
        def check1(member: discord.Member, before: discord.VoiceState, after: discord.VoiceState):
 | 
					 | 
				
			||||||
            return member.id == self._test_settings.test_user_id and after is not None and after.channel.id == 911578760476762153
 | 
					 | 
				
			||||||
        res = await self._bot.wait_for('voice_state_update', check=check1, timeout=10)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.send_command('afk', CommandSelectorsEnum.afk, reload=False)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def check2(member: discord.Member, before: discord.VoiceState, after: discord.VoiceState):
 | 
					 | 
				
			||||||
            return member.id == self._test_settings.test_user_id and after is not None and after.channel.id == 910199452915093594
 | 
					 | 
				
			||||||
        member, before, after = await self._bot.wait_for('voice_state_update', check=check2, timeout=10)
 | 
					 | 
				
			||||||
        self.assertIsNotNone(after.channel)
 | 
					 | 
				
			||||||
        self.assertEqual(after.channel.id, 910199452915093594)
 | 
					 | 
				
			||||||
        # self.assertEqual(response.content, correct_response)
 | 
					 | 
				
			||||||
@@ -1,20 +0,0 @@
 | 
				
			|||||||
import discord
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from ui_tests_shared.command_selectors_enum import CommandSelectorsEnum
 | 
					 | 
				
			||||||
from ui_tests_shared.command_test_case_with_app import CommandTestCaseWithApp
 | 
					 | 
				
			||||||
from ui_tests_shared.decorators import Async
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class HelpCommandTestCase(CommandTestCaseWithApp):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Async.async_func
 | 
					 | 
				
			||||||
    async def test_help(self):
 | 
					 | 
				
			||||||
        correct_response = 'https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot/wiki/Befehle'
 | 
					 | 
				
			||||||
        self.send_command('help', CommandSelectorsEnum.help)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def check(m: discord.Message):
 | 
					 | 
				
			||||||
            return m.author.id == self._test_settings.bot_id
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        response = await self._bot.wait_for('message', check=check, timeout=10)
 | 
					 | 
				
			||||||
        self.assertEqual(response.content, correct_response)
 | 
					 | 
				
			||||||
        await self._bot.close()
 | 
					 | 
				
			||||||
@@ -1,53 +0,0 @@
 | 
				
			|||||||
from datetime import datetime
 | 
					 | 
				
			||||||
from unittest import skip
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import discord
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import bot
 | 
					 | 
				
			||||||
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC
 | 
					 | 
				
			||||||
from ui_tests_shared.command_selectors_enum import CommandSelectorsEnum
 | 
					 | 
				
			||||||
from ui_tests_shared.command_test_case_with_app import CommandTestCaseWithApp
 | 
					 | 
				
			||||||
from ui_tests_shared.decorators import Async
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class InfoCommandTestCase(CommandTestCaseWithApp):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_embed(self) -> discord.Embed:
 | 
					 | 
				
			||||||
        client_utils: ClientUtilsServiceABC = self._services.get_service(ClientUtilsServiceABC)
 | 
					 | 
				
			||||||
        client = client_utils.get_client(self._test_settings.bot_id, self._test_settings.guild_id)
 | 
					 | 
				
			||||||
        embed = discord.Embed(
 | 
					 | 
				
			||||||
            title=self._t.transform('modules.base.info.title'),
 | 
					 | 
				
			||||||
            description=self._t.transform('modules.base.info.description'),
 | 
					 | 
				
			||||||
            color=int('ef9d0d', 16)
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.info.fields.version'), value=bot.__version__)
 | 
					 | 
				
			||||||
        # start_time = self._config.get_configuration('Bot_StartTime')
 | 
					 | 
				
			||||||
        start_time = str(datetime.now())
 | 
					 | 
				
			||||||
        ontime = round((datetime.now() - datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S.%f')).total_seconds() / 3600, 2)
 | 
					 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.info.fields.ontime'), value=f'{ontime}h')
 | 
					 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.info.fields.sent_message_count'), value=client.sent_message_count, inline=False)
 | 
					 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.info.fields.received_message_count'), value=client.received_message_count)
 | 
					 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.info.fields.deleted_message_count'), value=client.deleted_message_count, inline=False)
 | 
					 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.info.fields.received_command_count'), value=client.received_command_count)
 | 
					 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.info.fields.moved_users_count'), value=client.moved_users_count)
 | 
					 | 
				
			||||||
        from bot.module_list import ModuleList
 | 
					 | 
				
			||||||
        modules = ModuleList.get_modules()
 | 
					 | 
				
			||||||
        modules = modules.select(lambda x: x.__name__.replace('Module', ''))
 | 
					 | 
				
			||||||
        embed.add_field(name=self._t.transform('modules.base.info.fields.modules'), value='\n'.join(modules), inline=False)
 | 
					 | 
				
			||||||
        return embed
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @skip('stage db not ready yet')
 | 
					 | 
				
			||||||
    @Async.async_func
 | 
					 | 
				
			||||||
    async def test_info(self):
 | 
					 | 
				
			||||||
        correct_response = self.get_embed()
 | 
					 | 
				
			||||||
        self.send_command('info', CommandSelectorsEnum.info)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def check(m: discord.Message):
 | 
					 | 
				
			||||||
            return m.embeds[0] == correct_response and m.author.id == self._test_settings.bot_id
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        response: discord.Message = await self._bot.wait_for('message', check=check, timeout=10)
 | 
					 | 
				
			||||||
        self.assertEqual(len(response.embeds), 1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.assertEqual(response.embeds[0], correct_response)
 | 
					 | 
				
			||||||
        await self._bot.close()
 | 
					 | 
				
			||||||
@@ -1,20 +0,0 @@
 | 
				
			|||||||
import discord
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from ui_tests_shared.command_selectors_enum import CommandSelectorsEnum
 | 
					 | 
				
			||||||
from ui_tests_shared.command_test_case_with_app import CommandTestCaseWithApp
 | 
					 | 
				
			||||||
from ui_tests_shared.decorators import Async
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PingCommandTestCase(CommandTestCaseWithApp):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Async.async_func
 | 
					 | 
				
			||||||
    async def test_ping(self):
 | 
					 | 
				
			||||||
        correct_response = self._t.transform('modules.base.pong')
 | 
					 | 
				
			||||||
        self.assertIsNotNone(correct_response)
 | 
					 | 
				
			||||||
        self.send_command('ping', CommandSelectorsEnum.ping)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def check(m: discord.Message):
 | 
					 | 
				
			||||||
            return m.author.id == self._test_settings.bot_id
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        response = await self._bot.wait_for('message', check=check, timeout=10)
 | 
					 | 
				
			||||||
        self.assertEqual(response.content, correct_response)
 | 
					 | 
				
			||||||
@@ -1,34 +0,0 @@
 | 
				
			|||||||
import time
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import discord
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from ui_tests_shared.command_selectors_enum import CommandSelectorsEnum
 | 
					 | 
				
			||||||
from ui_tests_shared.command_test_case_with_app import CommandTestCaseWithApp
 | 
					 | 
				
			||||||
from ui_tests_shared.decorators import Async
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PurgeCommandTestCase(CommandTestCaseWithApp):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def setUp(self):
 | 
					 | 
				
			||||||
        self.send_message('test nachricht 1')
 | 
					 | 
				
			||||||
        self.send_message('test nachricht 2')
 | 
					 | 
				
			||||||
        self.send_message('test nachricht 3')
 | 
					 | 
				
			||||||
        self.send_message('test nachricht 4')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Async.async_func
 | 
					 | 
				
			||||||
    async def test_purge(self):
 | 
					 | 
				
			||||||
        correct_response = self._t.transform('modules.moderator.purge_message')
 | 
					 | 
				
			||||||
        self.assertIsNotNone(correct_response)
 | 
					 | 
				
			||||||
        self.send_command('purge', CommandSelectorsEnum.purge)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def check(m: discord.Message):
 | 
					 | 
				
			||||||
            return m.author.id == self._test_settings.bot_id
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        response = await self._bot.wait_for('message', check=check, timeout=10)
 | 
					 | 
				
			||||||
        self.assertEqual(response.content, correct_response)
 | 
					 | 
				
			||||||
        time.sleep(20)
 | 
					 | 
				
			||||||
        channel = self._bot.get_channel(911578680998895687)
 | 
					 | 
				
			||||||
        message_count = 0
 | 
					 | 
				
			||||||
        async for _ in channel.history(limit=None):
 | 
					 | 
				
			||||||
            message_count += 1
 | 
					 | 
				
			||||||
        self.assertEqual(message_count, 0)
 | 
					 | 
				
			||||||
@@ -1,44 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "ProjectSettings": {
 | 
					 | 
				
			||||||
    "Name": "ui-tests-tests",
 | 
					 | 
				
			||||||
    "Version": {
 | 
					 | 
				
			||||||
      "Major": "0",
 | 
					 | 
				
			||||||
      "Minor": "0",
 | 
					 | 
				
			||||||
      "Micro": "0"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "Author": "",
 | 
					 | 
				
			||||||
    "AuthorEmail": "",
 | 
					 | 
				
			||||||
    "Description": "",
 | 
					 | 
				
			||||||
    "LongDescription": "",
 | 
					 | 
				
			||||||
    "URL": "",
 | 
					 | 
				
			||||||
    "CopyrightDate": "",
 | 
					 | 
				
			||||||
    "CopyrightName": "",
 | 
					 | 
				
			||||||
    "LicenseName": "",
 | 
					 | 
				
			||||||
    "LicenseDescription": "",
 | 
					 | 
				
			||||||
    "Dependencies": [
 | 
					 | 
				
			||||||
      "cpl-core>=2022.10.0.post9"
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "DevDependencies": [
 | 
					 | 
				
			||||||
      "cpl-cli>=2022.10.0"
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					 | 
				
			||||||
    "PythonPath": {},
 | 
					 | 
				
			||||||
    "Classifiers": []
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "BuildSettings": {
 | 
					 | 
				
			||||||
    "ProjectType": "console",
 | 
					 | 
				
			||||||
    "SourcePath": "",
 | 
					 | 
				
			||||||
    "OutputPath": "../../dist",
 | 
					 | 
				
			||||||
    "Main": "ui_tests__tests.main",
 | 
					 | 
				
			||||||
    "EntryPoint": "ui-tests_tests",
 | 
					 | 
				
			||||||
    "IncludePackageData": false,
 | 
					 | 
				
			||||||
    "Included": [],
 | 
					 | 
				
			||||||
    "Excluded": [
 | 
					 | 
				
			||||||
      "*/__pycache__",
 | 
					 | 
				
			||||||
      "*/logs",
 | 
					 | 
				
			||||||
      "*/tests"
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "PackageData": {},
 | 
					 | 
				
			||||||
    "ProjectReferences": []
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "MIT",
 | 
					    "LicenseName": "MIT",
 | 
				
			||||||
    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
					    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core==2022.10.0.post7"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli==2022.10.0"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
    "LicenseName": "MIT",
 | 
					    "LicenseName": "MIT",
 | 
				
			||||||
    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
					    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core>=2022.10.0.post7"
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli>=2022.10.0"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,11 +16,11 @@
 | 
				
			|||||||
    "LicenseName": "MIT",
 | 
					    "LicenseName": "MIT",
 | 
				
			||||||
    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
					    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core==2022.10.0.post7",
 | 
					      "cpl-core==2022.12.0"
 | 
				
			||||||
      "GitPython==3.1.27"
 | 
					      "GitPython==3.1.27"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "cpl-cli==2022.10.0"
 | 
					      "cpl-cli==2022.12.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +0,0 @@
 | 
				
			|||||||
import { NgModule } from "@angular/core";
 | 
					 | 
				
			||||||
import { RouterModule, Routes } from "@angular/router";
 | 
					 | 
				
			||||||
import { MembersComponent } from "./component/members/members.component";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const routes: Routes = [
 | 
					 | 
				
			||||||
  { path: '', component: MembersComponent },
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@NgModule({
 | 
					 | 
				
			||||||
  imports: [RouterModule.forChild(routes)],
 | 
					 | 
				
			||||||
  exports: [RouterModule]
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
export class MembersRoutingModule { }
 | 
					 | 
				
			||||||
@@ -1,11 +1,9 @@
 | 
				
			|||||||
import { NgModule } from '@angular/core';
 | 
					import { NgModule } from "@angular/core";
 | 
				
			||||||
import { RouterModule, Routes } from '@angular/router';
 | 
					import { RouterModule, Routes } from "@angular/router";
 | 
				
			||||||
import { ServerDashboardComponent } from './server-dashboard/server-dashboard.component';
 | 
					import { ServerDashboardComponent } from "./server-dashboard/server-dashboard.component";
 | 
				
			||||||
import { AuthGuard } from "../../shared/guards/auth/auth.guard";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const routes: Routes = [
 | 
					const routes: Routes = [
 | 
				
			||||||
  { path: '', component: ServerDashboardComponent },
 | 
					  { path: '', component: ServerDashboardComponent },
 | 
				
			||||||
  { path: 'members', loadChildren: () => import('./members/members.module').then(m => m.MembersModule), canActivate: [AuthGuard] },
 | 
					 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@NgModule({
 | 
					@NgModule({
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user