Compare commits
409 Commits
0.3.1
...
9db00516c3
Author | SHA1 | Date | |
---|---|---|---|
9db00516c3 | |||
44e225c273 | |||
99e75ba325 | |||
3a078271ff | |||
1f9991eeda | |||
bfe72668dc | |||
51d95c81c1 | |||
6c39cd1ae1 | |||
5d36f1188a | |||
4c42949516 | |||
8922524f44 | |||
eac367c611 | |||
f02acd7f94 | |||
05ddfb3de3 | |||
5c2c89ca45 | |||
ec1ce4adef | |||
71f1f972c9 | |||
23757bc841 | |||
9671090385 | |||
a03ddf3fc2 | |||
da3538a836 | |||
c782c11b6d | |||
05a2ea9b18 | |||
a482c72a56 | |||
22bdf13835 | |||
0a3affc5d0 | |||
d642322985 | |||
9f63a9c6dd | |||
11a4874bfb | |||
d4dd55944a | |||
23d6216029 | |||
f7297ddf78 | |||
eb3715d00b | |||
aae6472e11 | |||
a71e3e4720 | |||
189128f0d3 | |||
3fb951a748 | |||
2293849d94 | |||
cd5b3b6523 | |||
c8a2ed290b | |||
184d241695 | |||
cab65477b0 | |||
3507623c92 | |||
b99dd1bded | |||
a0d38bec49 | |||
f312a2d776 | |||
bfb816dd17 | |||
d6854d44b7 | |||
fdbba1b89c | |||
7f197a0ea7 | |||
2c9569b75f | |||
607b7d8aee | |||
00db6ac10f | |||
f034413e35 | |||
ff16eae477 | |||
dbd82930d4 | |||
2e9cf0bd97 | |||
8a2edc7228 | |||
6d14ba9d79 | |||
ba5f83f3d0 | |||
9f614e8a31 | |||
6e0d4a5144 | |||
bd8bd40863 | |||
c7a1069c0c | |||
dc0c6ca6a0 | |||
ff009ffb61 | |||
074b03eecf | |||
9201cbf357 | |||
5ea698ef97 | |||
400e54a501 | |||
3c0233e8b3 | |||
8d2ae38d85 | |||
2b866b5ab1 | |||
4da87ae3cb | |||
1ebad89c97 | |||
b8320c83fe | |||
0ee26ccf3d | |||
31ca9cd8f4 | |||
089de53136 | |||
280b22af55 | |||
ebdf375283 | |||
c058312af7 | |||
2befa921ea | |||
1792359e68 | |||
faaf14d63e | |||
49d1ec75c8 | |||
629556b5fc | |||
9ece541e52 | |||
fd51db8cac | |||
2005d93f44 | |||
010dafc655 | |||
bea9dd1590 | |||
ef0da25f11 | |||
c01a6b97fe | |||
059bd3aaf1 | |||
a9d180fdf1 | |||
c71b1092f2 | |||
c1e8274f46 | |||
583218b215 | |||
e05e67785b | |||
72d3ccded3 | |||
f30bd119df | |||
858fc062b3 | |||
6d622a70d3 | |||
4a0a6a4631 | |||
17c2acd77c | |||
27363522d3 | |||
1960b18058 | |||
91034cee09 | |||
a4d3cffa93 | |||
809c6d4cb9 | |||
2fecbf2c31 | |||
c439d5925f | |||
1777a32899 | |||
3e5301b2d8 | |||
653562b908 | |||
8025c31339 | |||
ccf41bec79 | |||
f75d8f2068 | |||
da02aca7e4 | |||
3762f16c7e | |||
b3099121ab | |||
6a750ee31b | |||
3c371ec074 | |||
d818eafb9d | |||
b4a5fdb258 | |||
cf69436168 | |||
ccf171e876 | |||
5a312bf660 | |||
0003255d7c | |||
27a4c140e4 | |||
3183461195 | |||
cb4f8d870c | |||
7c447bb0f2 | |||
4debe4e2ba | |||
3cd3df3e5f | |||
b4a631d4e4 | |||
7ba0247519 | |||
209e75fdcc | |||
3bca3f86eb | |||
657a8fa586 | |||
3c8a092f40 | |||
61bf508cea | |||
75ad07477a | |||
132d41f0a2 | |||
707a835672 | |||
f56dbf8e2a | |||
c311e534d7 | |||
87b277515c | |||
e6c614dfdc | |||
24d5bbf4d8 | |||
52035af0cc | |||
fdc9a118c8 | |||
ba1f4ee955 | |||
35d161c080 | |||
818163cbed | |||
468ebb5f79 | |||
085726bf60 | |||
223abbe66f | |||
4c5a8baed5 | |||
59162408e5 | |||
634b81d23b | |||
c0cd5bb70e | |||
cc0a0a5c69 | |||
4420c0e11c | |||
7be40ed236 | |||
ff415c354d | |||
283eaabef6 | |||
b7e72888f7 | |||
b29227e8d5 | |||
9f57182fc1 | |||
699377be54 | |||
efba1a4ce8 | |||
68fa1b8c2d | |||
8b79d69e41 | |||
c1b75dff78 | |||
5f284597aa | |||
e1b1a68b07 | |||
b1a0115e8b | |||
ad00dce5d9 | |||
e3c47ce5b1 | |||
68026e4b47 | |||
ee503f76f2 | |||
a1f7b8b2dc | |||
b8e4146b33 | |||
51f0ee5744 | |||
69ce659328 | |||
325a17b5a8 | |||
5df0501505 | |||
c3ef7a746f | |||
bca33c6e56 | |||
d24d3fa4de | |||
1755efb5d9 | |||
54b0086a14 | |||
f404287cc1 | |||
7966ca16e5 | |||
c0e5f0d4b0 | |||
80769a1bf0 | |||
bc92dc4536 | |||
16ef29999c | |||
33279b7053 | |||
04fcfddbd9 | |||
21f0f32322 | |||
d1420d18c0 | |||
22d26bf032 | |||
a701807831 | |||
3324cf3ac3 | |||
1664c67763 | |||
bddcd3929a | |||
23e17c1f38 | |||
883811d156 | |||
4d0e8898fe | |||
505c87b996 | |||
18fe6ecb86 | |||
f02268c1a1 | |||
1b328dc20e | |||
34c362a391 | |||
15dfc3f47c | |||
91b2cf7546 | |||
a8dad6b223 | |||
124209c371 | |||
d24c8e40de | |||
54004d10a5 | |||
a510cf731f | |||
23b7e4f59c | |||
24f90657e1 | |||
454fabb3e3 | |||
a588f8bf72 | |||
d75503569e | |||
5b265488df | |||
2d995544c3 | |||
e5fb9fd504 | |||
a80bbc33cf | |||
6915515932 | |||
42b71525bd | |||
2674af64e9 | |||
1eb625fe7a | |||
19f47a01e5 | |||
8ff21debf0 | |||
89bcb655d2 | |||
b9d33c5fd0 | |||
9ea1b14852 | |||
2763f254af | |||
f7dc8d135a | |||
d42b76ba87 | |||
0f26db3d74 | |||
d9d3f8c8b0 | |||
23ee963d65 | |||
f3024d2ea5 | |||
|
e463b19a73 | ||
15214b1c99 | |||
|
dfcd958965 | ||
9274be6bb7 | |||
ac1affa937 | |||
4e722d9c47 | |||
6585576266 | |||
8937243725 | |||
c841f39a03 | |||
a3fa7cb7b9 | |||
f38b517b98 | |||
7d450a12ac | |||
0ea1edff4d | |||
70775111c5 | |||
f42f2086e7 | |||
1f3b12501b | |||
c0882a8ad3 | |||
75ab159539 | |||
ec9bc80392 | |||
02d04725bd | |||
10d79f8c2c | |||
a2dcbbc465 | |||
81fe7433bd | |||
ed5564dc7c | |||
e0ca057399 | |||
8f95e196ec | |||
16b2deec6b | |||
85e664e642 | |||
64985f5983 | |||
|
02ed6eb75b | ||
|
b615f2608f | ||
|
bf776177d4 | ||
|
a2a0056873 | ||
|
eb18fdea46 | ||
|
6945cd2eac | ||
ef040f2b91 | |||
ba4ef693da | |||
07f2c4921c | |||
96339ed168 | |||
9667f40730 | |||
5a9ad77761 | |||
e4d1e229eb | |||
299fc65d1f | |||
aa38623633 | |||
fd9d938b8a | |||
efbe6efc20 | |||
da3680a83e | |||
610ce42fa2 | |||
6149825101 | |||
7193e58ba1 | |||
38417bd712 | |||
43b6df2ba3 | |||
7d67b08ce6 | |||
afff27b273 | |||
de8262dae1 | |||
b96288f4a3 | |||
1ca6debc59 | |||
dfe4f28e24 | |||
fea259fa3b | |||
85452c9a74 | |||
f44f77d7e5 | |||
b15bcec20a | |||
ee351ee749 | |||
f847841582 | |||
e2ef4f3bde | |||
3456c5f021 | |||
065e8b0645 | |||
f04a6066a1 | |||
c0d1288aef | |||
c4507d3aa1 | |||
1039a58d4f | |||
ed4d41d424 | |||
645e84a8fa | |||
b9087dccb3 | |||
4bb486f1d5 | |||
8efd0fc993 | |||
6c0b48a941 | |||
77946cb3a8 | |||
5953c82a9b | |||
6bf73fcf91 | |||
3844240930 | |||
efa18944fe | |||
f435d779a7 | |||
cd34d18205 | |||
9e2a0441d3 | |||
898e27550e | |||
60990db88d | |||
ce1cdd4017 | |||
9a8f8a13f6 | |||
667bb708d9 | |||
54cb6cf8a0 | |||
aa16847fbf | |||
2ef4d079ed | |||
bd4e088032 | |||
1e74584e71 | |||
0b5acdea58 | |||
91bbb2f2e9 | |||
dd64435c65 | |||
84937dde0a | |||
ca5744ea39 | |||
f68bd875b5 | |||
429f8b2819 | |||
7fb8b521e4 | |||
936b8e9cb6 | |||
1fa6f44f76 | |||
f04d40ce75 | |||
45a6b49cf5 | |||
4822348e01 | |||
1d1fc8a876 | |||
a6df06f13a | |||
7f14aff1bd | |||
d03ea1d970 | |||
f144564806 | |||
f7c27b77ee | |||
6aca981fd1 | |||
4266db7e35 | |||
667b9fa87e | |||
79837afdfb | |||
8273b2b98e | |||
eaa22efd08 | |||
b33c5dc9bf | |||
e9559dec08 | |||
5d470be583 | |||
1dfe7edcba | |||
af8c2dea60 | |||
23e238b7d5 | |||
fde318b85d | |||
93c60b9176 | |||
12f8f669ed | |||
36fd3c73b9 | |||
3f7cfc47af | |||
eb58c34c4d | |||
e3c0a0dea3 | |||
dbfae8d8a4 | |||
e1c89814da | |||
53cdaf3fa0 | |||
b11ce18ac9 | |||
16066864ed | |||
807827e30f | |||
c75cc54d16 | |||
6a1ad1ec9f | |||
8256ebed71 | |||
eb7fce140a | |||
ebcf876457 | |||
5efb1da0b8 | |||
b9e66bba9d | |||
b8484185e9 | |||
552e686aeb | |||
efb772094b | |||
95b9eea236 | |||
b95a951a1b | |||
df42acec26 | |||
44204f5b94 | |||
ce85bb332a | |||
7a836a7f59 | |||
dacb429d9b | |||
77e18027a0 | |||
b13695b018 | |||
75500076a7 | |||
5455a6b359 |
9
LICENSE
9
LICENSE
@@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022-2023 sh-edraft.de
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
100
kdb-bot/.cpl/schematic_db_table.py
Normal file
100
kdb-bot/.cpl/schematic_db_table.py
Normal file
@@ -0,0 +1,100 @@
|
||||
from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC
|
||||
|
||||
|
||||
class DBTable(GenerateSchematicABC):
|
||||
def __init__(self, *args: str):
|
||||
GenerateSchematicABC.__init__(self, *args)
|
||||
self._name = self._name.replace("_db_table", "")
|
||||
self._class_name = self._class_name.split("Db_table")[0]
|
||||
|
||||
def get_code(self) -> str:
|
||||
import textwrap
|
||||
|
||||
code = textwrap.dedent(
|
||||
"""\
|
||||
from datetime import datetime
|
||||
|
||||
from cpl_core.database import TableABC
|
||||
|
||||
|
||||
class $ClassName(TableABC):
|
||||
def __init__(
|
||||
self,
|
||||
value: str,
|
||||
created_at: datetime = None,
|
||||
modified_at: datetime = None,
|
||||
id=0,
|
||||
):
|
||||
self._id = id
|
||||
self._value = value
|
||||
|
||||
TableABC.__init__(self)
|
||||
self._created_at = created_at if created_at is not None else self._created_at
|
||||
self._modified_at = modified_at if modified_at is not None else self._modified_at
|
||||
|
||||
@property
|
||||
def value(self) -> str:
|
||||
return self._value
|
||||
|
||||
@value.setter
|
||||
def value(self, value: str):
|
||||
self._value = value
|
||||
|
||||
@staticmethod
|
||||
def get_select_all_string() -> str:
|
||||
return str(
|
||||
f\"""
|
||||
SELECT * FROM `$TableName`;
|
||||
\"""
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_select_by_id_string(id: int) -> str:
|
||||
return str(
|
||||
f\"""
|
||||
SELECT * FROM `$TableName`
|
||||
WHERE `Id` = {id};
|
||||
\"""
|
||||
)
|
||||
|
||||
@property
|
||||
def insert_string(self) -> str:
|
||||
return str(
|
||||
f\"""
|
||||
INSERT INTO `$TableName` (
|
||||
`Value`
|
||||
) VALUES (
|
||||
{self._value}
|
||||
);
|
||||
\"""
|
||||
)
|
||||
|
||||
@property
|
||||
def udpate_string(self) -> str:
|
||||
return str(
|
||||
f\"""
|
||||
UPDATE `$TableName`
|
||||
SET `Value` = {self._value}
|
||||
WHERE `Id` = {self._id};
|
||||
\"""
|
||||
)
|
||||
|
||||
@property
|
||||
def delete_string(self) -> str:
|
||||
return str(
|
||||
f\"""
|
||||
DELETE FROM `$TableName`
|
||||
WHERE `Id` = {self._id};
|
||||
\"""
|
||||
)
|
||||
"""
|
||||
)
|
||||
return self.build_code_str(
|
||||
code,
|
||||
ClassName=self._class_name,
|
||||
TableName=self._class_name,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def register(cls):
|
||||
GenerateSchematicABC.register(cls, "db-table", [])
|
55
kdb-bot/.cpl/schematic_migration.py
Normal file
55
kdb-bot/.cpl/schematic_migration.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC
|
||||
|
||||
|
||||
class Migration(GenerateSchematicABC):
|
||||
def __init__(self, *args: str):
|
||||
GenerateSchematicABC.__init__(self, *args)
|
||||
|
||||
def get_code(self) -> str:
|
||||
import textwrap
|
||||
|
||||
code = textwrap.dedent(
|
||||
"""\
|
||||
from bot_core.logging.database_logger import DatabaseLogger
|
||||
from bot_data.abc.migration_abc import MigrationABC
|
||||
from bot_data.db_context import DBContext
|
||||
|
||||
|
||||
class $ClassName(MigrationABC):
|
||||
name = "1.0_$ClassName"
|
||||
|
||||
def __init__(self, logger: DatabaseLogger, db: DBContext):
|
||||
MigrationABC.__init__(self)
|
||||
self._logger = logger
|
||||
self._db = db
|
||||
self._cursor = db.cursor
|
||||
|
||||
def upgrade(self):
|
||||
self._logger.debug(__name__, "Running upgrade")
|
||||
|
||||
self._cursor.execute(
|
||||
str(
|
||||
f\"""
|
||||
CREATE TABLE IF NOT EXISTS `$TableName` (
|
||||
`Id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`CreatedAt` DATETIME(6),
|
||||
`LastModifiedAt` DATETIME(6),
|
||||
PRIMARY KEY(`Id`)
|
||||
);
|
||||
\"""
|
||||
)
|
||||
)
|
||||
|
||||
def downgrade(self):
|
||||
self._cursor.execute("DROP TABLE `$TableName`;")
|
||||
"""
|
||||
)
|
||||
return self.build_code_str(
|
||||
code,
|
||||
ClassName=self._class_name,
|
||||
TableName=self._class_name.split("Migration")[0],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def register(cls):
|
||||
GenerateSchematicABC.register(cls, "migration", [])
|
34
kdb-bot/.cpl/schematic_query.py
Normal file
34
kdb-bot/.cpl/schematic_query.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC
|
||||
|
||||
|
||||
class Query(GenerateSchematicABC):
|
||||
def __init__(self, *args: str):
|
||||
GenerateSchematicABC.__init__(self, *args)
|
||||
|
||||
def get_code(self) -> str:
|
||||
import textwrap
|
||||
|
||||
code = textwrap.dedent(
|
||||
"""\
|
||||
from bot_graphql.abc.data_query_abc import DataQueryABC
|
||||
|
||||
|
||||
class $ClassName(DataQueryABC):
|
||||
def __init__(self):
|
||||
DataQueryABC.__init__(self, "Name")
|
||||
|
||||
self.set_field("id", self.resolve_id)
|
||||
|
||||
@staticmethod
|
||||
def resolve_id(x, *_):
|
||||
return x.id
|
||||
"""
|
||||
)
|
||||
return self.build_code_str(
|
||||
code,
|
||||
ClassName=self._class_name,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def register(cls):
|
||||
GenerateSchematicABC.register(cls, "query", [])
|
@@ -6,39 +6,35 @@
|
||||
"bot-api": "src/bot_api/bot-api.json",
|
||||
"bot-core": "src/bot_core/bot-core.json",
|
||||
"bot-data": "src/bot_data/bot-data.json",
|
||||
"bot-graphql": "src/bot_graphql/bot-graphql.json",
|
||||
"achievements": "src/modules/achievements/achievements.json",
|
||||
"auto-role": "src/modules/auto_role/auto-role.json",
|
||||
"base": "src/modules/base/base.json",
|
||||
"boot-log": "src/modules/boot_log/boot-log.json",
|
||||
"config": "src/modules/config/modules/config.json",
|
||||
"database": "src/modules/database/database.json",
|
||||
"level": "src/modules/level/level.json",
|
||||
"permission": "src/modules/permission/permission.json",
|
||||
"stats": "src/modules/stats/stats.json",
|
||||
"technician": "src/modules/technician/technician.json",
|
||||
"checks": "tools/checks/checks.json",
|
||||
"get-version": "tools/get_version/get-version.json",
|
||||
"post-build": "tools/post_build/post-build.json",
|
||||
"set-version": "tools/set_version/set-version.json"
|
||||
},
|
||||
"Scripts": {
|
||||
"format": "black ./",
|
||||
|
||||
"sv": "cpl set-version $ARGS",
|
||||
"set-version": "cpl run set-version $ARGS --dev; echo '';",
|
||||
|
||||
"gv": "cpl get-version",
|
||||
"get-version": "export VERSION=$(cpl run get-version --dev); echo $VERSION;",
|
||||
|
||||
"pre-build": "cpl set-version $ARGS; black ./;",
|
||||
"post-build": "cpl run post-build --dev; black ./;",
|
||||
|
||||
"pre-prod": "cpl build",
|
||||
"prod": "export KDB_ENVIRONMENT=production; export KDB_NAME=KDB-Prod; cpl start;",
|
||||
|
||||
"pre-stage": "cpl build",
|
||||
"stage": "export KDB_ENVIRONMENT=staging; export KDB_NAME=KDB-Stage; cpl start;",
|
||||
|
||||
"pre-dev": "cpl build",
|
||||
"dev": "export KDB_ENVIRONMENT=development; export KDB_NAME=KDB-Dev; cpl start;",
|
||||
|
||||
"docker-build": "cpl build $ARGS; docker build -t kdb-bot/kdb-bot:$(cpl gv) .;",
|
||||
"dc-up": "docker-compose up -d",
|
||||
"dc-down": "docker-compose down",
|
||||
|
Submodule kdb-bot/docker updated: 6b25cc87fc...62475d6546
@@ -15,4 +15,7 @@ RUN apk add nano
|
||||
RUN pip install -r requirements.txt --extra-index-url https://pip.sh-edraft.de
|
||||
RUN pip install flask[async]
|
||||
|
||||
# RUN pip install dnspython==2.2.1 # https://stackoverflow.com/questions/75137717/eventlet-dns-python-attribute-error-module-dns-rdtypes-has-no-attribute-any
|
||||
# ^ probably fixed py package updates
|
||||
|
||||
CMD [ "bash", "/app/bot/bot"]
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -10,6 +10,7 @@ from cpl_translation import TranslatePipe, TranslationServiceABC, TranslationSet
|
||||
from bot_api.api_thread import ApiThread
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||
from bot_core.service.data_integrity_service import DataIntegrityService
|
||||
|
||||
|
||||
class Application(DiscordBotApplicationABC):
|
||||
@@ -21,6 +22,7 @@ class Application(DiscordBotApplicationABC):
|
||||
|
||||
# cpl-core
|
||||
self._logger: LoggerABC = services.get_service(LoggerABC)
|
||||
self._data_integrity: DataIntegrityService = services.get_service(DataIntegrityService)
|
||||
# cpl-discord
|
||||
self._bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC)
|
||||
self._bot_settings: DiscordBotSettings = config.get_configuration(DiscordBotSettings)
|
||||
@@ -52,7 +54,7 @@ class Application(DiscordBotApplicationABC):
|
||||
self._api.join()
|
||||
return
|
||||
|
||||
self._logger.trace(__name__, f"Try to start {DiscordBotService.__name__}")
|
||||
self._logger.info(__name__, f"Try to start {DiscordBotService.__name__}")
|
||||
await self._bot.start_async()
|
||||
await self._bot.stop_async()
|
||||
except Exception as e:
|
||||
@@ -64,13 +66,17 @@ class Application(DiscordBotApplicationABC):
|
||||
|
||||
self._is_stopping = True
|
||||
try:
|
||||
self._logger.trace(__name__, f"Try to stop {DiscordBotService.__name__}")
|
||||
self._logger.info(__name__, f"Try to stop {DiscordBotService.__name__}")
|
||||
if self._feature_flags.get_flag(FeatureFlagsEnum.api_module):
|
||||
self._api.stop()
|
||||
|
||||
await self._bot.close()
|
||||
self._logger.trace(__name__, f"Stopped {DiscordBotService.__name__}")
|
||||
self._data_integrity.check_data_integrity(is_for_shutdown=True)
|
||||
self._logger.info(__name__, f"Stopped {DiscordBotService.__name__}")
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, "stop failed", e)
|
||||
|
||||
Console.write_line()
|
||||
|
||||
def is_restart(self):
|
||||
return True if self._configuration.get_configuration("IS_RESTART") == "true" else False #
|
||||
return True if self._configuration.get_configuration("IS_RESTART") == "true" else False
|
||||
|
@@ -2,9 +2,9 @@
|
||||
"ProjectSettings": {
|
||||
"Name": "bot",
|
||||
"Version": {
|
||||
"Major": "0",
|
||||
"Minor": "3",
|
||||
"Micro": "1"
|
||||
"Major": "1",
|
||||
"Minor": "0",
|
||||
"Micro": "7"
|
||||
},
|
||||
"Author": "Sven Heidemann",
|
||||
"AuthorEmail": "sven.heidemann@sh-edraft.de",
|
||||
@@ -16,22 +16,25 @@
|
||||
"LicenseName": "MIT",
|
||||
"LicenseDescription": "MIT, see LICENSE for more details.",
|
||||
"Dependencies": [
|
||||
"cpl-core==2022.12.1.post2",
|
||||
"cpl-translation==2022.12.1",
|
||||
"cpl-query==2022.12.2.post1",
|
||||
"cpl-discord==2022.12.1.post2",
|
||||
"Flask==2.2.2",
|
||||
"cpl-core==2023.4.0.post5",
|
||||
"cpl-translation==2023.4.0.post1",
|
||||
"cpl-query==2023.4.0.post1",
|
||||
"cpl-discord==2023.4.0.post3",
|
||||
"Flask==2.3.2",
|
||||
"Flask-Classful==0.14.2",
|
||||
"Flask-Cors==3.0.10",
|
||||
"PyJWT==2.6.0",
|
||||
"Flask-Cors==4.0.0",
|
||||
"PyJWT==2.8.0",
|
||||
"waitress==2.1.2",
|
||||
"Flask-SocketIO==5.3.2",
|
||||
"eventlet==0.33.2",
|
||||
"Flask-SocketIO==5.3.4",
|
||||
"eventlet==0.33.3",
|
||||
"requests-oauthlib==1.3.1",
|
||||
"icmplib==3.0.3"
|
||||
"icmplib==3.0.3",
|
||||
"ariadne==0.20.1",
|
||||
"cryptography==41.0.2"
|
||||
],
|
||||
"DevDependencies": [
|
||||
"cpl-cli==2022.12.1.post2"
|
||||
"cpl-cli==2023.4.0.post3",
|
||||
"pygount==1.6.1"
|
||||
],
|
||||
"PythonVersion": ">=3.10.4",
|
||||
"PythonPath": {},
|
||||
@@ -55,13 +58,13 @@
|
||||
"../bot_api/bot-api.json",
|
||||
"../bot_core/bot-core.json",
|
||||
"../bot_data/bot-data.json",
|
||||
"../bot_graphql/bot-graphql.json",
|
||||
"../modules/auto_role/auto-role.json",
|
||||
"../modules/base/base.json",
|
||||
"../modules/boot_log/boot-log.json",
|
||||
"../modules/database/database.json",
|
||||
"../modules/level/level.json",
|
||||
"../modules/permission/permission.json",
|
||||
"../modules/stats/stats.json",
|
||||
"../modules/technician/technician.json"
|
||||
]
|
||||
}
|
||||
|
Submodule kdb-bot/src/bot/config updated: 54b1b3860c...359f9c38c3
@@ -15,7 +15,7 @@ __title__ = "bot.extension"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -3,7 +3,7 @@ from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.dependency_injection import ServiceProviderABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
|
||||
from bot_core.configuration.bot_settings import BotSettings
|
||||
from bot_data.model.technician_config import TechnicianConfig
|
||||
|
||||
|
||||
class InitBotExtension(ApplicationExtensionABC):
|
||||
@@ -11,6 +11,6 @@ class InitBotExtension(ApplicationExtensionABC):
|
||||
ApplicationExtensionABC.__init__(self)
|
||||
|
||||
async def run(self, config: ConfigurationABC, services: ServiceProviderABC):
|
||||
settings = config.get_configuration(BotSettings)
|
||||
settings = config.get_configuration(TechnicianConfig)
|
||||
|
||||
bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC, max_messages=settings.cache_max_messages)
|
||||
|
@@ -15,6 +15,7 @@ from bot.startup_settings_extension import StartupSettingsExtension
|
||||
from bot_api.app_api_extension import AppApiExtension
|
||||
from bot_core.core_extension.core_extension import CoreExtension
|
||||
from modules.boot_log.boot_log_extension import BootLogExtension
|
||||
from modules.config.config_extension import ConfigExtension
|
||||
from modules.database.database_extension import DatabaseExtension
|
||||
|
||||
|
||||
@@ -30,6 +31,7 @@ class Program:
|
||||
.use_extension(StartupDiscordExtension)
|
||||
.use_extension(StartupModuleExtension)
|
||||
.use_extension(StartupMigrationExtension)
|
||||
.use_extension(ConfigExtension)
|
||||
.use_extension(InitBotExtension)
|
||||
.use_extension(BootLogExtension)
|
||||
.use_extension(DatabaseExtension)
|
||||
@@ -39,6 +41,7 @@ class Program:
|
||||
)
|
||||
self.app: Application = await app_builder.build_async()
|
||||
await self.app.run_async()
|
||||
Console.write_line(f"[ INFO ] [ {__name__} ]: Finished app.run_async")
|
||||
|
||||
async def stop(self):
|
||||
if self.app is None:
|
||||
|
@@ -4,13 +4,15 @@ from bot_api.api_module import ApiModule
|
||||
from bot_core.core_extension.core_extension_module import CoreExtensionModule
|
||||
from bot_core.core_module import CoreModule
|
||||
from bot_data.data_module import DataModule
|
||||
from bot_graphql.graphql_module import GraphQLModule
|
||||
from modules.achievements.achievements_module import AchievementsModule
|
||||
from modules.auto_role.auto_role_module import AutoRoleModule
|
||||
from modules.base.base_module import BaseModule
|
||||
from modules.boot_log.boot_log_module import BootLogModule
|
||||
from modules.config.config_module import ConfigModule
|
||||
from modules.database.database_module import DatabaseModule
|
||||
from modules.level.level_module import LevelModule
|
||||
from modules.permission.permission_module import PermissionModule
|
||||
from modules.stats.stats_module import StatsModule
|
||||
from modules.technician.technician_module import TechnicianModule
|
||||
|
||||
|
||||
@@ -23,14 +25,16 @@ class ModuleList:
|
||||
[
|
||||
CoreModule, # has to be first!
|
||||
DataModule,
|
||||
PermissionModule,
|
||||
DatabaseModule,
|
||||
ConfigModule, # has be to after db check
|
||||
GraphQLModule,
|
||||
PermissionModule,
|
||||
AutoRoleModule,
|
||||
BaseModule,
|
||||
LevelModule,
|
||||
ApiModule,
|
||||
StatsModule,
|
||||
TechnicianModule,
|
||||
AchievementsModule,
|
||||
# has to be last!
|
||||
BootLogModule,
|
||||
CoreExtensionModule,
|
||||
|
@@ -4,15 +4,22 @@ from cpl_core.dependency_injection import ServiceCollectionABC
|
||||
from cpl_core.environment import ApplicationEnvironmentABC
|
||||
|
||||
from bot_data.abc.migration_abc import MigrationABC
|
||||
from bot_data.migration.achievements_migration import AchievementsMigration
|
||||
from bot_data.migration.api_key_migration import ApiKeyMigration
|
||||
from bot_data.migration.api_migration import ApiMigration
|
||||
from bot_data.migration.auto_role_fix1_migration import AutoRoleFix1Migration
|
||||
from bot_data.migration.auto_role_migration import AutoRoleMigration
|
||||
from bot_data.migration.config_migration import ConfigMigration
|
||||
from bot_data.migration.db_history_migration import DBHistoryMigration
|
||||
from bot_data.migration.initial_migration import InitialMigration
|
||||
from bot_data.migration.level_migration import LevelMigration
|
||||
from bot_data.migration.remove_stats_migration import RemoveStatsMigration
|
||||
from bot_data.migration.stats_migration import StatsMigration
|
||||
from bot_data.migration.user_joined_game_server_migration import UserJoinedGameServerMigration
|
||||
from bot_data.migration.user_message_count_per_hour_migration import (
|
||||
UserMessageCountPerHourMigration,
|
||||
)
|
||||
from bot_data.migration.user_warning_migration import UserWarningMigration
|
||||
from bot_data.service.migration_service import MigrationService
|
||||
|
||||
|
||||
@@ -32,3 +39,10 @@ class StartupMigrationExtension(StartupExtensionABC):
|
||||
services.add_transient(MigrationABC, StatsMigration) # 09.11.2022 #46 - 0.3.0
|
||||
services.add_transient(MigrationABC, AutoRoleFix1Migration) # 30.12.2022 #151 - 0.3.0
|
||||
services.add_transient(MigrationABC, UserMessageCountPerHourMigration) # 11.01.2023 #168 - 0.3.1
|
||||
services.add_transient(MigrationABC, ApiKeyMigration) # 09.02.2023 #162 - 1.0.0
|
||||
services.add_transient(MigrationABC, UserJoinedGameServerMigration) # 12.02.2023 #181 - 1.0.0
|
||||
services.add_transient(MigrationABC, RemoveStatsMigration) # 19.02.2023 #190 - 1.0.0
|
||||
services.add_transient(MigrationABC, UserWarningMigration) # 21.02.2023 #35 - 1.0.0
|
||||
services.add_transient(MigrationABC, DBHistoryMigration) # 06.03.2023 #246 - 1.0.0
|
||||
services.add_transient(MigrationABC, AchievementsMigration) # 14.06.2023 #268 - 1.1.0
|
||||
services.add_transient(MigrationABC, ConfigMigration) # 19.07.2023 #127 - 1.1.0
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
from datetime import datetime
|
||||
from typing import Callable, Type, Optional
|
||||
from typing import Optional, Type, Callable
|
||||
|
||||
from cpl_core.application import StartupExtensionABC
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
@@ -8,11 +8,6 @@ from cpl_core.dependency_injection import ServiceCollectionABC
|
||||
from cpl_core.environment import ApplicationEnvironmentABC
|
||||
|
||||
from bot_core.configuration.bot_logging_settings import BotLoggingSettings
|
||||
from bot_core.configuration.bot_settings import BotSettings
|
||||
from modules.base.configuration.base_settings import BaseSettings
|
||||
from modules.boot_log.configuration.boot_log_settings import BootLogSettings
|
||||
from modules.level.configuration.level_settings import LevelSettings
|
||||
from modules.permission.configuration.permission_settings import PermissionSettings
|
||||
|
||||
|
||||
class StartupSettingsExtension(StartupExtensionABC):
|
||||
@@ -34,13 +29,6 @@ class StartupSettingsExtension(StartupExtensionABC):
|
||||
configuration.add_json_file(f"config/feature-flags.{environment.host_name}.json", optional=True)
|
||||
|
||||
configuration.add_configuration("Startup_StartTime", str(self._start_time))
|
||||
self._configure_settings_with_sub_settings(configuration, BotSettings, lambda x: x.servers, lambda x: x.id)
|
||||
self._configure_settings_with_sub_settings(configuration, BaseSettings, lambda x: x.servers, lambda x: x.id)
|
||||
self._configure_settings_with_sub_settings(configuration, BootLogSettings, lambda x: x.servers, lambda x: x.id)
|
||||
self._configure_settings_with_sub_settings(configuration, LevelSettings, lambda x: x.servers, lambda x: x.id)
|
||||
self._configure_settings_with_sub_settings(
|
||||
configuration, PermissionSettings, lambda x: x.servers, lambda x: x.id
|
||||
)
|
||||
self._configure_settings_with_sub_settings(
|
||||
configuration, BotLoggingSettings, lambda x: x.files, lambda x: x.key
|
||||
)
|
||||
@@ -50,9 +38,9 @@ class StartupSettingsExtension(StartupExtensionABC):
|
||||
|
||||
@staticmethod
|
||||
def _configure_settings_with_sub_settings(
|
||||
config: ConfigurationABC, settings: Type, list_atr: Callable, atr: Callable
|
||||
config: ConfigurationABC, settings_type: Type, list_atr: Callable, atr: Callable
|
||||
):
|
||||
settings: Optional[settings] = config.get_configuration(settings)
|
||||
settings: Optional[settings_type] = config.get_configuration(settings_type)
|
||||
if settings is None:
|
||||
return
|
||||
|
||||
|
@@ -1,51 +1,27 @@
|
||||
{
|
||||
"api": {
|
||||
"api": {
|
||||
"test_mail": {
|
||||
"message": "Dies ist eine Test-Mail vom Krümelmonster Web Interface\nGesendet von {}-{}",
|
||||
"subject": "Krümelmonster Web Interface Test-Mail"
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"confirmation": {
|
||||
"message": "Öffne den Link, um die E-Mail zu bestätigen:\n{}auth/register/{}",
|
||||
"subject": "E-Mail für {} {} bestätigen"
|
||||
},
|
||||
"forgot_password": {
|
||||
"message": "Öffne den Link, um das Passwort zu ändern:\n{}auth/forgot-password/{}",
|
||||
"subject": "Passwort für {} {} zurücksetzen"
|
||||
}
|
||||
},
|
||||
"mail": {
|
||||
"automatic_mail": "\n\nDies ist eine automatische E-Mail.\nGesendet von {}-{}@{}"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"hello_world": "Hallo Welt",
|
||||
"bot_has_no_permission_message": "Ey!!!\nWas soll das?\nIch habe keine Berechtigungen :(\nScheiß System...",
|
||||
"no_permission_message": "Nein!\nIch höre nicht auf dich ¯\\_(ツ)_/¯",
|
||||
"not_implemented_yet": "Ey Alter, das kann ich noch nicht...",
|
||||
"presence": {
|
||||
"booting": "{} Ich fahre gerade hoch...",
|
||||
"running": "{} Ich esse Kekse :D",
|
||||
"restart": "{} Muss neue Kekse holen...",
|
||||
"shutdown": "{} Ich werde bestimmt wieder kommen..."
|
||||
},
|
||||
"errors": {
|
||||
"error": "Es gab einen Fehler. Meld dich bitte bei einem Admin.",
|
||||
"command_error": "Es gab einen Fehler beim bearbeiten des Befehls. Meld dich bitte bei einem Admin.",
|
||||
"missing_required_argument": "Fehler: Ein benötigter Parameter fehlt!",
|
||||
"argument_parsing_error": "Fehler: Parameter konnte nicht gelesen werden!",
|
||||
"unexpected_quote_error": "Fehler: Unerwarteter Zitat Fehler!",
|
||||
"invalid_end_of_quoted_string_error": "Fehler: Ungültiges Zitatende!",
|
||||
"expected_closing_quote_error": "Fehler: Erwarte Zitatende!",
|
||||
"bad_argument": "Fehler: Ungültiger Parameter!",
|
||||
"bad_union_argument": "Fehler: Ungültiger Union Parameter!",
|
||||
"private_message_only": "Fehler: Nur private Nachrichten sind erlaubt!",
|
||||
"no_private_message": "Fehler: Private Nachrichten sind nicht erlaubt!",
|
||||
"check_failure": "Fehler: Du hast nicht die benötigte Berechtigung!",
|
||||
"check_any_failure": "Fehler: Alle checks sind Fehlgeschlagen!",
|
||||
"command_not_found": "Fehler: Befehl konnte nicht gefunden werden!",
|
||||
"disabled_command": "Fehler: Befehl wurde deaktiviert!",
|
||||
"command_invoke_error": "Fehler: Befehl konnte nicht aufgerufen werden!",
|
||||
"too_many_arguments": "Fehler: Zu viele Parameter!",
|
||||
"user_input_error": "Fehler: Eingabefehler!",
|
||||
"command_on_cooldown": "Fehler: Befehl befindet sich im cooldown!",
|
||||
"max_concurrency_reached": "Fehler: Maximale Parallelität erreicht!",
|
||||
"not_owner": "Fehler: Du bist nicht mein besitzer!",
|
||||
"missing_permissions": "Fehler: Berechtigungen fehlen!",
|
||||
"bot_missing_permissions": "Fehler: Mir fehlen Berechtigungen!",
|
||||
"missing_role": "Fehler: Benötigte Rolle fehlt!",
|
||||
"bot_missing_role": "Fehler: Mir fehlt eine benötigte Rolle!",
|
||||
"missing_any_role": "Fehler: Alle benötigten Rollen fehlen!",
|
||||
"bot_missing_any_role": "Fehler: Mir fehlen alle benötigten Rollen!",
|
||||
"nsfw_channel_required": "Fehler: NSFW Kanal benötigt!",
|
||||
"extension_error": "Fehler: Erweiterungsfehler!",
|
||||
"extension_already_loaded": "Fehler: Erweiterung wurde bereits geladen!",
|
||||
"extension_not_loaded": "Fehler: Erweiterung wurde nicht geladen!",
|
||||
"no_entry_point_error": "Fehler: Kein Eintrittspunkt!",
|
||||
"extension_failed": "Fehler: Erweiterung ist fehlgeschlagen!",
|
||||
"bot_not_ready_yet": "Ey Alter! Gedulde dich doch mal! ..."
|
||||
},
|
||||
"colors": {
|
||||
"blue": "Blau",
|
||||
"dark_blue": "Dunkelblau",
|
||||
@@ -69,242 +45,315 @@
|
||||
"red": "Rot",
|
||||
"teal": "Blaugrün",
|
||||
"yellow": "Gelb"
|
||||
},
|
||||
"errors": {
|
||||
"argument_parsing_error": "Fehler: Parameter konnte nicht gelesen werden!",
|
||||
"bad_argument": "Fehler: Ungültiger Parameter!",
|
||||
"bad_union_argument": "Fehler: Ungültiger Union Parameter!",
|
||||
"bot_missing_any_role": "Fehler: Mir fehlen alle benötigten Rollen!",
|
||||
"bot_missing_permissions": "Fehler: Mir fehlen Berechtigungen!",
|
||||
"bot_missing_role": "Fehler: Mir fehlt eine benötigte Rolle!",
|
||||
"bot_not_ready_yet": "Ey Alter! Gedulde dich doch mal! ...",
|
||||
"check_any_failure": "Fehler: Alle Checks sind Fehlgeschlagen!",
|
||||
"check_failure": "Fehler: Du hast nicht die benötigte Berechtigung!",
|
||||
"command_error": "Es gab einen Fehler beim Bearbeiten des Befehls. Melde dich bitte bei einem Admin.",
|
||||
"command_invoke_error": "Fehler: Befehl konnte nicht aufgerufen werden!",
|
||||
"command_not_found": "Fehler: Befehl konnte nicht gefunden werden!",
|
||||
"command_on_cooldown": "Fehler: Befehl befindet sich im Cooldown!",
|
||||
"disabled_command": "Fehler: Befehl wurde deaktiviert!",
|
||||
"error": "Es gab einen Fehler. Melde dich bitte bei einem Admin.",
|
||||
"expected_closing_quote_error": "Fehler: Erwarte Zitatende!",
|
||||
"extension_already_loaded": "Fehler: Erweiterung wurde bereits geladen!",
|
||||
"extension_error": "Fehler: Erweiterungsfehler!",
|
||||
"extension_failed": "Fehler: Erweiterung ist fehlgeschlagen!",
|
||||
"extension_not_loaded": "Fehler: Erweiterung wurde nicht geladen!",
|
||||
"invalid_end_of_quoted_string_error": "Fehler: Ungültiges Zitatende!",
|
||||
"max_concurrency_reached": "Fehler: Maximale Parallelität erreicht!",
|
||||
"missing_any_role": "Fehler: Alle benötigten Rollen fehlen!",
|
||||
"missing_permissions": "Fehler: Berechtigungen fehlen!",
|
||||
"missing_required_argument": "Fehler: Ein benötigter Parameter fehlt!",
|
||||
"missing_role": "Fehler: Benötigte Rolle fehlt!",
|
||||
"no_entry_point_error": "Fehler: Kein Eintrittspunkt!",
|
||||
"no_private_message": "Fehler: Private Nachrichten sind nicht erlaubt!",
|
||||
"not_owner": "Fehler: Du bist nicht mein besitzer!",
|
||||
"nsfw_channel_required": "Fehler: NSFW Kanal benötigt!",
|
||||
"private_message_only": "Fehler: Nur private Nachrichten sind erlaubt!",
|
||||
"too_many_arguments": "Fehler: Zu viele Parameter!",
|
||||
"unexpected_quote_error": "Fehler: Unerwarteter Fehler beim Anführungszeichen!",
|
||||
"user_input_error": "Fehler: Eingabefehler!"
|
||||
},
|
||||
"hello_world": "Hallo Welt",
|
||||
"no_permission_message": "Nein!\nIch höre nicht auf dich ¯\\_(ツ)_/¯",
|
||||
"not_implemented_yet": "Ey Alter, das kann ich noch nicht...",
|
||||
"presence": {
|
||||
"booting": "Ich fahre gerade hoch...",
|
||||
"restart": "Muss neue Kekse holen...",
|
||||
"running": "Ich esse Kekse :D",
|
||||
"shutdown": "Ich werde bestimmt wieder kommen..."
|
||||
}
|
||||
},
|
||||
"modules": {
|
||||
"achievements": {
|
||||
"got_new_achievement": "{} hat die Errungenschaft {} freigeschaltet :D",
|
||||
"commands": {
|
||||
"check": "Alles klar, ich schaue eben nach... nom nom"
|
||||
}
|
||||
},
|
||||
"auto_role": {
|
||||
"list": {
|
||||
"title": "Beobachtete Nachrichten:",
|
||||
"description": "Von auto-role beobachtete Nachrichten:",
|
||||
"auto_role_id": "auto-role Id",
|
||||
"message_id": "Nachricht-Id"
|
||||
},
|
||||
"add": {
|
||||
"success": "auto-role für die Nachricht {} wurde hinzugefügt :D",
|
||||
"error": {
|
||||
"not_found": "Nachricht {} in {} nicht gefunden!",
|
||||
"already_exists": "auto-role für die Nachricht {} existiert bereits!"
|
||||
}
|
||||
"already_exists": "auto-role für die Nachricht {} existiert bereits!",
|
||||
"not_found": "Nachricht {} in {} nicht gefunden!"
|
||||
},
|
||||
"remove": {
|
||||
"success": "auto-role {} wurde entfernt :D",
|
||||
"error": {
|
||||
"not_found": "auto-role {} nicht gefunden!"
|
||||
}
|
||||
"success": "auto-role für die Nachricht {} wurde hinzugefügt :D"
|
||||
},
|
||||
"error": {
|
||||
"nothing_found": "Keine auto-role Einträge gefunden."
|
||||
},
|
||||
"rule": {
|
||||
"list": {
|
||||
"title": "auto-role Regeln:",
|
||||
"description": "Von auto-role angewendete Regeln:",
|
||||
"auto_role_rule_id": "auto-role Regel Id",
|
||||
"emoji": "Emoji",
|
||||
"role": "Rolle"
|
||||
},
|
||||
"add": {
|
||||
"success": "Regel {} -> {} für auto-role {} wurde hinzugefügt :D",
|
||||
"error": {
|
||||
"not_found": "Regel für auto-role {} nicht gefunden!",
|
||||
"emoji_not_found": "Emoji {} für auto-role Regel {} nicht gefunden!",
|
||||
"role_not_found": "Rolle {} für auto-role Regel {} nicht gefunden!",
|
||||
"already_exists": "Regel für auto-role {} existiert bereits!"
|
||||
}
|
||||
"auto_role_id": "auto-role Id",
|
||||
"description": "Von auto-role beobachtete Nachrichten:",
|
||||
"message_id": "Nachricht-Id",
|
||||
"title": "Beobachtete Nachrichten:"
|
||||
},
|
||||
"remove": {
|
||||
"success": "Regel für auto-role {} wurde entfernt :D",
|
||||
"error": {
|
||||
"not_found": "Regel für auto-role {} nicht gefunden!"
|
||||
}
|
||||
"not_found": "auto-role {} nicht gefunden!"
|
||||
},
|
||||
"success": "auto-role {} wurde entfernt :D"
|
||||
},
|
||||
"rule": {
|
||||
"add": {
|
||||
"error": {
|
||||
"already_exists": "Regel für auto-role {} existiert bereits!",
|
||||
"emoji_not_found": "Emoji {} für auto-role Regel {} nicht gefunden!",
|
||||
"not_found": "Regel für auto-role {} nicht gefunden!",
|
||||
"role_not_found": "Rolle {} für auto-role Regel {} nicht gefunden!"
|
||||
},
|
||||
"success": "Regel {} -> {} für auto-role {} wurde hinzugefügt :D"
|
||||
},
|
||||
"error": {
|
||||
"id_not_found": "Kein auto-role Eintrag mit der Id gefunden!"
|
||||
}
|
||||
}
|
||||
},
|
||||
"moderator": {
|
||||
"purge_message": "Na gut..., ich lösche alle Nachrichten wenns sein muss."
|
||||
"list": {
|
||||
"auto_role_rule_id": "auto-role Regel Id",
|
||||
"description": "Von auto-role angewendete Regeln:",
|
||||
"emoji": "Emoji",
|
||||
"role": "Rolle",
|
||||
"title": "auto-role Regeln:"
|
||||
},
|
||||
"remove": {
|
||||
"error": {
|
||||
"not_found": "Regel für auto-role {} nicht gefunden!"
|
||||
},
|
||||
"success": "Regel für auto-role {} wurde entfernt :D"
|
||||
}
|
||||
}
|
||||
},
|
||||
"base": {
|
||||
"technician_error_message": "Es gab ein Fehler mit dem Event: {}\nDatum und Zeit: {}\nSchau bitte ins log für Details.\nUUID: {}",
|
||||
"technician_command_error_message": "Es gab ein Fehler mit dem Befehl: {} ausgelöst von {} -> {}\nDatum und Zeit: {}\nSchau bitte ins log für Details.\nUUID: {}",
|
||||
"welcome_message": "Hello There!\nIch heiße dich bei {} herzlichst Willkommen!",
|
||||
"welcome_message_for_team": "{} hat gerade das Irrenhaus betreten.",
|
||||
"goodbye_message": "Schade, dass du uns so schnell verlässt :(",
|
||||
"member_left_message": "{} hat uns leider verlassen :(",
|
||||
"complaints": {
|
||||
"title": "Beschwerde einreichen",
|
||||
"label": "Beschwerde",
|
||||
"message": "{} hat eine Beschwerde eingereicht:\n{}",
|
||||
"response": "Danke für deine Beschwerde"
|
||||
},
|
||||
"bug": {
|
||||
"title": "Bug melden",
|
||||
"label": "Bug",
|
||||
"message": "{} meldet einen Bug:\n{}",
|
||||
"response": "Danke für dein Feedback :D"
|
||||
},
|
||||
"afk_command_channel_missing_message": "Zu unfähig einem Sprachkanal beizutreten?",
|
||||
"afk_command_move_message": "Ich verschiebe dich ja schon... (◔_◔)",
|
||||
"member_joined_help_voice_channel": "{} braucht hilfe, bitte kümmer dich drum :D",
|
||||
"pong": "Pong",
|
||||
"info": {
|
||||
"title": "Krümmelmonster",
|
||||
"description": "Informationen über mich",
|
||||
"fields": {
|
||||
"version": "Version",
|
||||
"ontime": "Ontime",
|
||||
"sent_message_count": "Gesendete Nachrichten",
|
||||
"received_message_count": "Empfangene Nachrichten",
|
||||
"deleted_message_count": "Gelöschte Nachrichten",
|
||||
"received_command_count": "Empfangene Befehle",
|
||||
"moved_users_count": "Verschobene Benutzer",
|
||||
"modules": "Module"
|
||||
},
|
||||
"footer": ""
|
||||
},
|
||||
"mass_move": {
|
||||
"moved": "Alle Personen aus {} wurden nach {} verschoben.",
|
||||
"channel_from_error": "Du musst dich in einem Voicechannel befinden oder die Option \"channel_from\" mit angeben."
|
||||
},
|
||||
"presence": {
|
||||
"changed": "Presence wurde geändert.",
|
||||
"removed": "Presence wurde entfernt.",
|
||||
"max_char_count_exceeded": "Der Text darf nicht mehr als 128 Zeichen lang sein!"
|
||||
},
|
||||
"user": {
|
||||
"atr": {
|
||||
"id": "Id",
|
||||
"name": "Name",
|
||||
"discord_join": "Discord beigetreten am",
|
||||
"last_join": "Server beigetreten am",
|
||||
"xp": "XP",
|
||||
"ontime": "Ontime",
|
||||
"roles": "Rollen",
|
||||
"joins": "Beitritte",
|
||||
"lefts": "Abgänge",
|
||||
"warnings": "Verwarnungen"
|
||||
},
|
||||
"info": {
|
||||
"footer": ""
|
||||
},
|
||||
"get": {
|
||||
"xp": "{} hat {} xp",
|
||||
"ontime": "{} war insgesamt {} Stunden aktiv in einem Sprachkanal"
|
||||
},
|
||||
"set": {
|
||||
"xp": "{} hat nun {} xp",
|
||||
"game_server": {
|
||||
"error": {
|
||||
"value_type_not_numeric": "Der angegebende Wert ist keine Ganzzahl! :(",
|
||||
"type_error": "Der angegebene Wert ist keine Zahl! :("
|
||||
}
|
||||
"nothing_found": "Keine Gameserver gefunden."
|
||||
},
|
||||
"list": {
|
||||
"title": "Gameserver",
|
||||
"description": "Konfigurierte Gameserver:",
|
||||
"name": "Name",
|
||||
"api_key": "API Key"
|
||||
},
|
||||
"add": {
|
||||
"success": "Gameserver {} wurde hinzugefügt :)"
|
||||
},
|
||||
"remove": {
|
||||
"success": "Gameserver wurde entfernt :D"
|
||||
}
|
||||
},
|
||||
"goodbye_message": "Schade, dass du uns so schnell verlässt :(",
|
||||
"info": {
|
||||
"description": "Informationen über mich",
|
||||
"fields": {
|
||||
"deleted_message_count": "Gelöschte Nachrichten",
|
||||
"modules": "Module",
|
||||
"moved_users_count": "Verschobene Benutzer",
|
||||
"ontime": "Ontime",
|
||||
"received_command_count": "Empfangene Befehle",
|
||||
"received_message_count": "Empfangene Nachrichten",
|
||||
"sent_message_count": "Gesendete Nachrichten",
|
||||
"version": "Version"
|
||||
},
|
||||
"footer": "",
|
||||
"title": "Krümelmonster"
|
||||
},
|
||||
"mass_move": {
|
||||
"channel_from_error": "Du musst dich in einem Voicechannel befinden oder die Option \"channel_from\" mit angeben.",
|
||||
"moved": "Alle Personen aus {} wurden nach {} verschoben."
|
||||
},
|
||||
"member_joined_help_voice_channel": "{} braucht Hilfe, bitte kümmere dich drum :D",
|
||||
"pong": "Pong",
|
||||
"presence": {
|
||||
"changed": "Presence wurde geändert.",
|
||||
"max_char_count_exceeded": "Der Text darf nicht mehr als 128 Zeichen lang sein!",
|
||||
"removed": "Presence wurde entfernt."
|
||||
},
|
||||
"register": {
|
||||
"not_found": "Benutzer konnte nicht gefunden werden!",
|
||||
"success": "Spieler wurde mit dem Mitglied verlinkt :D"
|
||||
},
|
||||
"technician_command_error_message": "Es gab ein Fehler mit dem Befehl: {} ausgelöst von {} -> {}\nDatum und Zeit: {}\nSchau bitte ins Log für Details.\nUUID: {}",
|
||||
"technician_error_message": "Es gab ein Fehler mit dem Event: {}\nDatum und Zeit: {}\nSchau bitte ins Log für Details.\nUUID: {}",
|
||||
"unregister": {
|
||||
"success": "Verlinkung wurde entfernt :D"
|
||||
},
|
||||
"user": {
|
||||
"add": {
|
||||
"xp": "Die {} von {} wurden um {} erhöht"
|
||||
},
|
||||
"atr": {
|
||||
"discord_join": "Discord beigetreten am",
|
||||
"id": "Id",
|
||||
"joins": "Beitritte",
|
||||
"last_join": "Server beigetreten am",
|
||||
"lefts": "Abgänge",
|
||||
"name": "Name",
|
||||
"ontime": "Ontime",
|
||||
"roles": "Rollen",
|
||||
"warnings": "Verwarnungen",
|
||||
"xp": "XP"
|
||||
},
|
||||
"error": {
|
||||
"atr_not_found": "Das Attribut {} konnte nicht gefunden werden :("
|
||||
},
|
||||
"get": {
|
||||
"ontime": "{} war insgesamt {} Stunden aktiv in einem Sprachkanal",
|
||||
"xp": "{} hat {} xp"
|
||||
},
|
||||
"info": {
|
||||
"footer": ""
|
||||
},
|
||||
"remove": {
|
||||
"xp": "Die {} von {} wurden um {} verringert"
|
||||
},
|
||||
"reset": {
|
||||
"xp": "Die {} von {} wurden entfernt",
|
||||
"ontime": "Die {} von {} wurden entfernt"
|
||||
"ontime": "Die {} von {} wurden entfernt",
|
||||
"xp": "Die {} von {} wurden entfernt"
|
||||
},
|
||||
"set": {
|
||||
"error": {
|
||||
"atr_not_found": "Das Attribut {} konnte nicht gefunden werden :("
|
||||
}
|
||||
"type_error": "Der angegebene Wert ist keine Zahl! :(",
|
||||
"value_type_not_numeric": "Der angegebende Wert ist keine Ganzzahl! :("
|
||||
},
|
||||
"xp": "{} hat nun {} xp"
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"add": {
|
||||
"failed": "Verwarnung konnte nicht hinzugefügt werden :(",
|
||||
"success": "Verwarnung wurde hinzugefügt :)"
|
||||
},
|
||||
"first": "Bei der nächsten Verwarnung wirst du auf das vorherige Level zurückgesetzt!",
|
||||
"kick": "Ich musste {} aufgrund zu vieler Verwarnungen kicken",
|
||||
"remove": {
|
||||
"failed": "Verwarnung konnte nicht entfernt werden :(",
|
||||
"success": "Verwarnung wurde entfernt :)"
|
||||
},
|
||||
"removed": "Die Verwarnung '{}' wurde entfernt.",
|
||||
"second": "Bei der nächsten verwarnung wirst du auf das erste Level zurückgesetzt!",
|
||||
"show": {
|
||||
"description": "Beschreibung",
|
||||
"id": "Id"
|
||||
},
|
||||
"team_removed": "Die Verwarnung '{}' an {} wurde entfernt.",
|
||||
"team_warned": "{} wurde verwarnt. Der Grund ist: {}",
|
||||
"third": "Bei der nächsten verwarnung wirst du gekickt und zurückgesetzt!",
|
||||
"warned": "Du wurdest verwarnt. Der Grund ist: {}"
|
||||
},
|
||||
"welcome_message": "Hello There!\nIch heiße dich bei {} herzlichst Willkommen!",
|
||||
"welcome_message_for_team": "{} hat gerade das Irrenhaus betreten."
|
||||
},
|
||||
"boot_log": {
|
||||
"login_message": "Ich bin on the line :D\nDer Scheiß hat {} Sekunden gedauert"
|
||||
},
|
||||
"level": {
|
||||
"new_level_message": "{} ist nun Level {}",
|
||||
"seeding_started": "Levelsystem wird neu geladen...",
|
||||
"seeding_failed": "Levelsystem konnte nicht neu geladen werden :(",
|
||||
"seeding_finished": "Levelsystem wurde Erfolgreich neu geladen :)",
|
||||
"error": {
|
||||
"nothing_found": "Keine Level Einträge gefunden.",
|
||||
"level_with_name_already_exists": "Ein Level mit dem Namen {} existiert bereits!",
|
||||
"level_with_xp_already_exists": "Das Level {} hat bereits die Mindest-XP {}!"
|
||||
},
|
||||
"list": {
|
||||
"title": "Level:",
|
||||
"description": "Konfigurierte Level:",
|
||||
"name": "Name",
|
||||
"min_xp": "Mindest-XP",
|
||||
"permission_int": "Berechtigungen"
|
||||
},
|
||||
"create": {
|
||||
"created": "Level {} mit Berechtigungen {} wurde erstellt :D"
|
||||
},
|
||||
"edit": {
|
||||
"edited": "Level {} wurde bearbeitet :D",
|
||||
"color_invalid": "Die Farbe {} ist ungültig!",
|
||||
"permission_invalid": "Der Berechtigungswert {} ist ungültig!",
|
||||
"not_found": "Level {} nicht gefunden!"
|
||||
},
|
||||
"remove": {
|
||||
"success": "Level {} wurde entfernt :D",
|
||||
"error": {
|
||||
"not_found": "Level {} nicht gefunden!"
|
||||
}
|
||||
},
|
||||
"down": {
|
||||
"already_first": "{} hat bereits das erste Level.",
|
||||
"success": "{} wurde auf Level {} runtergesetzt :)",
|
||||
"failed": "{} konnte nicht runtergesetzt werden :("
|
||||
"failed": "{} konnte nicht runtergesetzt werden :(",
|
||||
"success": "{} wurde auf Level {} runtergesetzt :)"
|
||||
},
|
||||
"edit": {
|
||||
"color_invalid": "Die Farbe {} ist ungültig!",
|
||||
"edited": "Level {} wurde bearbeitet :D",
|
||||
"not_found": "Level {} nicht gefunden!",
|
||||
"permission_invalid": "Der Berechtigungswert {} ist ungültig!"
|
||||
},
|
||||
"error": {
|
||||
"level_with_name_already_exists": "Ein Level mit dem Namen {} existiert bereits!",
|
||||
"level_with_xp_already_exists": "Das Level {} hat bereits die Mindest-XP {}!",
|
||||
"nothing_found": "Keine Einträge gefunden."
|
||||
},
|
||||
"list": {
|
||||
"description": "Konfigurierte Level:",
|
||||
"min_xp": "Mindest-XP",
|
||||
"name": "Name",
|
||||
"permission_int": "Berechtigungen",
|
||||
"title": "Level:"
|
||||
},
|
||||
"new_level_message": "{} ist nun Level {}",
|
||||
"remove": {
|
||||
"error": {
|
||||
"not_found": "Level {} nicht gefunden!"
|
||||
},
|
||||
"success": "Level {} wurde entfernt :D"
|
||||
},
|
||||
"seeding_failed": "Levelsystem konnte nicht neu geladen werden :(",
|
||||
"seeding_finished": "Levelsystem wurde erfolgreich neu geladen :)",
|
||||
"seeding_started": "Levelsystem wird neu geladen...",
|
||||
"set": {
|
||||
"already_level": "{} hat bereits das Level {} :/",
|
||||
"failed": "Das Level von {} konnte nicht auf {} gesetzt werden :(",
|
||||
"not_found": "Das Level {} konnte nicht gefunden werden :(",
|
||||
"success": "{} ist nun Level {} :)"
|
||||
},
|
||||
"up": {
|
||||
"already_last": "{} hat bereits das höchste Level.",
|
||||
"success": "{} wurde auf Level {} hochgesetzt :)",
|
||||
"failed": "{} konnte nicht hochgesetzt werden :("
|
||||
},
|
||||
"set": {
|
||||
"already_level": "{} hat bereits das Level {} :/",
|
||||
"success": "{} ist nun Level {} :)",
|
||||
"failed": "Das Level von {} konnte nicht auf {} gesetzt werden :(",
|
||||
"not_found": "Das Level {} konnte nicht gefunden werden :("
|
||||
"failed": "{} konnte nicht hochgesetzt werden :(",
|
||||
"success": "{} wurde auf Level {} hochgesetzt :)"
|
||||
}
|
||||
},
|
||||
"database": {},
|
||||
"permission": {},
|
||||
"stats": {
|
||||
"list": {
|
||||
"statistic": "Statistik",
|
||||
"description": "Beschreibung",
|
||||
"nothing_found": "Keine Statistiken gefunden."
|
||||
},
|
||||
"view": {
|
||||
"statistic": "Statistik",
|
||||
"description": "Beschreibung",
|
||||
"failed": "Statistik kann nicht gezeigt werden :("
|
||||
},
|
||||
"add": {
|
||||
"failed": "Statistik kann nicht hinzugefügt werden :(",
|
||||
"success": "Statistik wurde hinzugefügt :D"
|
||||
},
|
||||
"edit": {
|
||||
"failed": "Statistik kann nicht bearbeitet werden :(",
|
||||
"success": "Statistik wurde gespeichert :D"
|
||||
},
|
||||
"remove": {
|
||||
"failed": "Statistik kann nicht gelöscht werden :(",
|
||||
"success": "Statistik wurde gelöscht :D"
|
||||
}
|
||||
"moderator": {
|
||||
"purge_message": "Na gut..., ich lösche alle Nachrichten wenns sein muss."
|
||||
},
|
||||
"technician": {
|
||||
"api_key": {
|
||||
"add": {
|
||||
"success": "API-Schlüssel für {} wurde erstellt: {}"
|
||||
},
|
||||
"get": "API-Schlüssel für {}: {}",
|
||||
"remove": {
|
||||
"not_found": "API-Schlüssel konnte nicht gefunden werden!",
|
||||
"success": "API-Schlüssel wurde entfernt :D"
|
||||
}
|
||||
},
|
||||
"log_message": "Hier sind deine Logdateien! :)",
|
||||
"restart_message": "Bin gleich wieder da :D",
|
||||
"shutdown_message": "Trauert nicht um mich, es war eine logische Entscheidung. Das Wohl von Vielen, es wiegt schwerer als das Wohl von Wenigen oder eines Einzelnen. Ich war es und ich werde es immer sein, Euer Freund. Lebt lange und in Frieden :)",
|
||||
"log_message": "Hier sind deine Logdateien! :)"
|
||||
}
|
||||
},
|
||||
"api": {
|
||||
"mail": {
|
||||
"automatic_mail": "\n\nDies ist eine automatische E-Mail.\nGesendet von {}-{}@{}"
|
||||
},
|
||||
"api": {
|
||||
"test_mail": {
|
||||
"subject": "Krümmelmonster Web Interface Test-Mail",
|
||||
"message": "Dies ist eine Test-Mail vom Krümmelmonster Web Interface\nGesendet von {}-{}"
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"confirmation": {
|
||||
"subject": "E-Mail für {} {} bestätigen",
|
||||
"message": "Öffne den Link um die E-Mail zu bestätigen:\n{}auth/register/{}"
|
||||
},
|
||||
"forgot_password": {
|
||||
"subject": "Passwort für {} {} zurücksetzen",
|
||||
"message": "Öffne den Link um das Passwort zu ändern:\n{}auth/forgot-password/{}"
|
||||
}
|
||||
"shutdown_message": "Trauert nicht um mich, es war eine logische Entscheidung. Das Wohl von Vielen, es wiegt schwerer als das Wohl von Wenigen oder eines Einzelnen. Ich war es und ich werde es immer sein, euer Freund. Lebt lange und in Frieden :)"
|
||||
}
|
||||
}
|
||||
}
|
@@ -15,7 +15,7 @@ __title__ = "bot_api"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_api.abc"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -52,17 +52,13 @@ class AuthServiceABC(ABC):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def add_auth_user_async(self, user_dto: AuthUserDTO):
|
||||
def add_auth_user(self, user_dto: AuthUserDTO):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def add_auth_user_by_oauth_async(self, dto: OAuthDTO):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO, dc_id: int) -> OAuthDTO:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def update_user_async(self, update_user_dto: UpdateAuthUserDTO):
|
||||
pass
|
||||
@@ -83,12 +79,16 @@ class AuthServiceABC(ABC):
|
||||
async def verify_login(self, token_str: str) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def verify_api_key(self, api_key: str) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def login_discord_async(self, oauth_dto: AuthUserDTO) -> TokenDTO:
|
||||
async def login_discord_async(self, oauth_dto: AuthUserDTO, dc_id: int) -> TokenDTO:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
|
@@ -1,9 +1,9 @@
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
import textwrap
|
||||
import uuid
|
||||
from functools import partial
|
||||
from typing import Union
|
||||
from typing import Union, Optional
|
||||
|
||||
import eventlet
|
||||
from cpl_core.dependency_injection import ServiceProviderABC
|
||||
@@ -16,7 +16,6 @@ from werkzeug.exceptions import NotFound
|
||||
|
||||
from bot_api.configuration.api_settings import ApiSettings
|
||||
from bot_api.configuration.authentication_settings import AuthenticationSettings
|
||||
from bot_api.configuration.frontend_settings import FrontendSettings
|
||||
from bot_api.exception.service_error_code_enum import ServiceErrorCode
|
||||
from bot_api.exception.service_exception import ServiceException
|
||||
from bot_api.logging.api_logger import ApiLogger
|
||||
@@ -30,7 +29,6 @@ class Api(Flask):
|
||||
logger: ApiLogger,
|
||||
services: ServiceProviderABC,
|
||||
api_settings: ApiSettings,
|
||||
frontend_settings: FrontendSettings,
|
||||
auth_settings: AuthenticationSettings,
|
||||
*args,
|
||||
**kwargs,
|
||||
@@ -56,10 +54,15 @@ class Api(Flask):
|
||||
self.register_error_handler(exc_class, self.handle_exception)
|
||||
|
||||
# websockets
|
||||
self._socketio = SocketIO(self, cors_allowed_origins="*", path="/api/socket.io")
|
||||
# Added async_mode see link below
|
||||
# https://github.com/miguelgrinberg/Flask-SocketIO/discussions/1849
|
||||
# https://stackoverflow.com/questions/39370848/flask-socket-io-sometimes-client-calls-freeze-the-server
|
||||
self._socketio = SocketIO(self, cors_allowed_origins="*", path="/api/socket.io", async_mode="eventlet")
|
||||
self._socketio.on_event("connect", self.on_connect)
|
||||
self._socketio.on_event("disconnect", self.on_disconnect)
|
||||
|
||||
self._socket: Optional[socket] = None
|
||||
|
||||
self._requests = {}
|
||||
|
||||
@staticmethod
|
||||
@@ -146,20 +149,20 @@ class Api(Flask):
|
||||
return response
|
||||
|
||||
def start(self):
|
||||
self._logger.info(
|
||||
__name__,
|
||||
f"Starting API {self._api_settings.host}:{self._api_settings.port}",
|
||||
)
|
||||
self._logger.info(__name__, f"Starting API {self._api_settings.host}:{self._api_settings.port}")
|
||||
self._register_routes()
|
||||
self.secret_key = CredentialManager.decrypt(self._auth_settings.secret_key)
|
||||
# from waitress import serve
|
||||
# https://docs.pylonsproject.org/projects/waitress/en/stable/arguments.html
|
||||
# serve(self, host=self._apt_settings.host, port=self._apt_settings.port, threads=10, connection_limit=1000, channel_timeout=10)
|
||||
wsgi.server(
|
||||
eventlet.listen((self._api_settings.host, self._api_settings.port)),
|
||||
self,
|
||||
log_output=False,
|
||||
)
|
||||
self._socket = eventlet.listen((self._api_settings.host, self._api_settings.port))
|
||||
wsgi.server(self._socket, self, log_output=False)
|
||||
|
||||
def stop(self):
|
||||
if self._socket is None:
|
||||
return
|
||||
self._socket.shutdown(socket.SHUT_RDWR)
|
||||
self._socket.close()
|
||||
|
||||
def on_connect(self):
|
||||
self._logger.info(__name__, f"Client connected")
|
||||
|
@@ -13,7 +13,7 @@ from bot_api.api import Api
|
||||
from bot_api.api_thread import ApiThread
|
||||
from bot_api.controller.auth_controller import AuthController
|
||||
from bot_api.controller.auth_discord_controller import AuthDiscordController
|
||||
from bot_api.controller.discord.server_controller import ServerController
|
||||
from bot_api.controller.graphql_controller import GraphQLController
|
||||
from bot_api.controller.gui_controller import GuiController
|
||||
from bot_api.event.bot_api_on_ready_event import BotApiOnReadyEvent
|
||||
from bot_api.service.auth_service import AuthService
|
||||
@@ -45,7 +45,7 @@ class ApiModule(ModuleABC):
|
||||
services.add_transient(AuthDiscordController)
|
||||
services.add_transient(GuiController)
|
||||
services.add_transient(DiscordService)
|
||||
services.add_transient(ServerController)
|
||||
services.add_transient(GraphQLController)
|
||||
|
||||
# cpl-discord
|
||||
self._dc.add_event(DiscordEventTypesEnum.on_ready.value, BotApiOnReadyEvent)
|
||||
|
@@ -17,3 +17,10 @@ class ApiThread(threading.Thread):
|
||||
self._api.start()
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, "Start failed", e)
|
||||
|
||||
def stop(self):
|
||||
try:
|
||||
self._logger.trace(__name__, f"Try to stop {type(self._api).__name__}")
|
||||
self._api.stop()
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, "Stop failed", e)
|
||||
|
@@ -2,12 +2,9 @@ from cpl_core.application import ApplicationExtensionABC
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.dependency_injection import ServiceProviderABC
|
||||
|
||||
from bot_api.abc.auth_service_abc import AuthServiceABC
|
||||
from bot_api.configuration.authentication_settings import AuthenticationSettings
|
||||
from bot_api.route.route import Route
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
|
||||
|
||||
|
||||
class AppApiExtension(ApplicationExtensionABC):
|
||||
@@ -19,7 +16,4 @@ class AppApiExtension(ApplicationExtensionABC):
|
||||
if not feature_flags.get_flag(FeatureFlagsEnum.api_module):
|
||||
return
|
||||
|
||||
auth_settings: AuthenticationSettings = config.get_configuration(AuthenticationSettings)
|
||||
auth_users: AuthUserRepositoryABC = services.get_service(AuthUserRepositoryABC)
|
||||
auth: AuthServiceABC = services.get_service(AuthServiceABC)
|
||||
Route.init_authorize(auth_users, auth)
|
||||
Route.init_authorize()
|
||||
|
@@ -2,9 +2,9 @@
|
||||
"ProjectSettings": {
|
||||
"Name": "bot-api",
|
||||
"Version": {
|
||||
"Major": "0",
|
||||
"Minor": "3",
|
||||
"Micro": "1"
|
||||
"Major": "1",
|
||||
"Minor": "0",
|
||||
"Micro": "7"
|
||||
},
|
||||
"Author": "",
|
||||
"AuthorEmail": "",
|
||||
|
Submodule kdb-bot/src/bot_api/config updated: e6046881b5...6d3f253f41
@@ -15,7 +15,7 @@ __title__ = "bot_api.configuration"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -1,16 +1,13 @@
|
||||
import traceback
|
||||
|
||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl_core.console import Console
|
||||
|
||||
|
||||
class ApiSettings(ConfigurationModelABC):
|
||||
def __init__(self):
|
||||
def __init__(self, port: int = None, host: str = None, redirect_uri: bool = None):
|
||||
ConfigurationModelABC.__init__(self)
|
||||
|
||||
self._port = 80
|
||||
self._host = ""
|
||||
self._redirect_to_https = False
|
||||
self._port = 80 if port is None else port
|
||||
self._host = "" if host is None else host
|
||||
self._redirect_to_https = False if redirect_uri is None else redirect_uri
|
||||
|
||||
@property
|
||||
def port(self) -> int:
|
||||
@@ -23,12 +20,3 @@ class ApiSettings(ConfigurationModelABC):
|
||||
@property
|
||||
def redirect_to_https(self) -> bool:
|
||||
return self._redirect_to_https
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
self._port = int(settings["Port"])
|
||||
self._host = settings["Host"]
|
||||
self._redirect_to_https = bool(settings["RedirectToHTTPS"])
|
||||
except Exception as e:
|
||||
Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
|
||||
Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
|
||||
|
@@ -1,19 +1,22 @@
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
|
||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl_core.console import Console
|
||||
|
||||
|
||||
class AuthenticationSettings(ConfigurationModelABC):
|
||||
def __init__(self):
|
||||
def __init__(
|
||||
self,
|
||||
secret_key: str = None,
|
||||
issuer: str = None,
|
||||
audience: str = None,
|
||||
token_expire_time: int = None,
|
||||
refresh_token_expire_time: int = None,
|
||||
):
|
||||
ConfigurationModelABC.__init__(self)
|
||||
|
||||
self._secret_key = ""
|
||||
self._issuer = ""
|
||||
self._audience = ""
|
||||
self._token_expire_time = 0
|
||||
self._refresh_token_expire_time = 0
|
||||
self._secret_key = "" if secret_key is None else secret_key
|
||||
self._issuer = "" if issuer is None else issuer
|
||||
self._audience = "" if audience is None else audience
|
||||
self._token_expire_time = 0 if token_expire_time is None else token_expire_time
|
||||
self._refresh_token_expire_time = 0 if refresh_token_expire_time is None else refresh_token_expire_time
|
||||
|
||||
@property
|
||||
def secret_key(self) -> str:
|
||||
@@ -34,14 +37,3 @@ class AuthenticationSettings(ConfigurationModelABC):
|
||||
@property
|
||||
def refresh_token_expire_time(self) -> int:
|
||||
return self._refresh_token_expire_time
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
self._secret_key = settings["SecretKey"]
|
||||
self._issuer = settings["Issuer"]
|
||||
self._audience = settings["Audience"]
|
||||
self._token_expire_time = int(settings["TokenExpireTime"])
|
||||
self._refresh_token_expire_time = int(settings["RefreshTokenExpireTime"])
|
||||
except Exception as e:
|
||||
Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
|
||||
Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
|
||||
|
@@ -1,19 +1,23 @@
|
||||
import traceback
|
||||
|
||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl_core.console import Console
|
||||
from cpl_query.extension import List
|
||||
|
||||
|
||||
class DiscordAuthenticationSettings(ConfigurationModelABC):
|
||||
def __init__(self):
|
||||
def __init__(
|
||||
self,
|
||||
client_secret: str = None,
|
||||
redirect_uri: str = None,
|
||||
scope: list = None,
|
||||
token_url: str = None,
|
||||
auth_url: str = None,
|
||||
):
|
||||
ConfigurationModelABC.__init__(self)
|
||||
|
||||
self._client_secret = ""
|
||||
self._redirect_url = ""
|
||||
self._scope = List()
|
||||
self._token_url = ""
|
||||
self._auth_url = ""
|
||||
self._client_secret = "" if client_secret is None else client_secret
|
||||
self._redirect_url = "" if redirect_uri is None else redirect_uri
|
||||
self._scope = List() if scope is None else List(str, scope)
|
||||
self._token_url = "" if token_url is None else token_url
|
||||
self._auth_url = "" if auth_url is None else auth_url
|
||||
|
||||
@property
|
||||
def client_secret(self) -> str:
|
||||
@@ -34,14 +38,3 @@ class DiscordAuthenticationSettings(ConfigurationModelABC):
|
||||
@property
|
||||
def auth_url(self) -> str:
|
||||
return self._auth_url
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
self._client_secret = settings["ClientSecret"]
|
||||
self._redirect_url = settings["RedirectURL"]
|
||||
self._scope = List(str, settings["Scope"])
|
||||
self._token_url = settings["TokenURL"]
|
||||
self._auth_url = settings["AuthURL"]
|
||||
except Exception as e:
|
||||
Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
|
||||
Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
|
||||
|
@@ -1,22 +1,12 @@
|
||||
import traceback
|
||||
|
||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl_core.console import Console
|
||||
|
||||
|
||||
class FrontendSettings(ConfigurationModelABC):
|
||||
def __init__(self):
|
||||
def __init__(self, url: str = None):
|
||||
ConfigurationModelABC.__init__(self)
|
||||
|
||||
self._url = ""
|
||||
self._url = "" if url is None else url
|
||||
|
||||
@property
|
||||
def url(self) -> str:
|
||||
return self._url
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
self._url = settings["URL"]
|
||||
except Exception as e:
|
||||
Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
|
||||
Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
|
||||
|
@@ -1,49 +0,0 @@
|
||||
from typing import Optional
|
||||
|
||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl_cli.configuration.version_settings_name_enum import VersionSettingsNameEnum
|
||||
|
||||
|
||||
class VersionSettings(ConfigurationModelABC):
|
||||
def __init__(self, major: str = None, minor: str = None, micro: str = None):
|
||||
ConfigurationModelABC.__init__(self)
|
||||
|
||||
self._major: Optional[str] = major
|
||||
self._minor: Optional[str] = minor
|
||||
self._micro: Optional[str] = micro
|
||||
|
||||
@property
|
||||
def major(self) -> str:
|
||||
return self._major
|
||||
|
||||
@property
|
||||
def minor(self) -> str:
|
||||
return self._minor
|
||||
|
||||
@property
|
||||
def micro(self) -> str:
|
||||
return self._micro
|
||||
|
||||
def to_str(self) -> str:
|
||||
if self._micro is None:
|
||||
return f"{self._major}.{self._minor}"
|
||||
else:
|
||||
return f"{self._major}.{self._minor}.{self._micro}"
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
self._major = settings[VersionSettingsNameEnum.major.value]
|
||||
self._minor = settings[VersionSettingsNameEnum.minor.value]
|
||||
micro = settings[VersionSettingsNameEnum.micro.value]
|
||||
if micro != "":
|
||||
self._micro = micro
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
version = {
|
||||
VersionSettingsNameEnum.major.value: self._major,
|
||||
VersionSettingsNameEnum.minor.value: self._minor,
|
||||
}
|
||||
|
||||
if self._micro is not None:
|
||||
version[VersionSettingsNameEnum.micro.value] = self._micro
|
||||
|
||||
return version
|
@@ -15,7 +15,7 @@ __title__ = "bot_api.controller"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -6,8 +6,6 @@ from flask import request, jsonify, Response
|
||||
|
||||
from bot_api.abc.auth_service_abc import AuthServiceABC
|
||||
from bot_api.api import Api
|
||||
from bot_api.exception.service_error_code_enum import ServiceErrorCode
|
||||
from bot_api.exception.service_exception import ServiceException
|
||||
from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria
|
||||
from bot_api.json_processor import JSONProcessor
|
||||
from bot_api.logging.api_logger import ApiLogger
|
||||
@@ -73,7 +71,7 @@ class AuthController:
|
||||
@Route.post(f"{BasePath}/register")
|
||||
async def register(self):
|
||||
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
|
||||
await self._auth_service.add_auth_user_async(dto)
|
||||
self._auth_service.add_auth_user(dto)
|
||||
return "", 200
|
||||
|
||||
@Route.post(f"{BasePath}/register-by-id/<id>")
|
||||
@@ -131,7 +129,6 @@ class AuthController:
|
||||
return "", 200
|
||||
|
||||
@Route.post(f"{BasePath}/refresh")
|
||||
@Route.authorize
|
||||
async def refresh(self) -> Response:
|
||||
dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True))
|
||||
result = await self._auth_service.refresh_async(dto)
|
||||
|
@@ -8,7 +8,7 @@ from cpl_core.utils import CredentialManager
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
from cpl_translation import TranslatePipe
|
||||
from flask import jsonify, Response
|
||||
from flask import request, session
|
||||
from flask import request
|
||||
from requests_oauthlib import OAuth2Session
|
||||
|
||||
from bot_api.abc.auth_service_abc import AuthServiceABC
|
||||
@@ -16,10 +16,8 @@ from bot_api.api import Api
|
||||
from bot_api.configuration.discord_authentication_settings import (
|
||||
DiscordAuthenticationSettings,
|
||||
)
|
||||
from bot_api.json_processor import JSONProcessor
|
||||
from bot_api.logging.api_logger import ApiLogger
|
||||
from bot_api.model.auth_user_dto import AuthUserDTO
|
||||
from bot_api.model.o_auth_dto import OAuthDTO
|
||||
from bot_api.route.route import Route
|
||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
||||
|
||||
@@ -59,7 +57,7 @@ class AuthDiscordController:
|
||||
self._bot.user.id,
|
||||
redirect_uri=self._auth_settings.redirect_url,
|
||||
state=request.args.get("state"),
|
||||
scope=self._auth_settings.scope,
|
||||
scope=self._auth_settings.scope.to_list(),
|
||||
)
|
||||
token = discord.fetch_token(
|
||||
self._auth_settings.token_url,
|
||||
@@ -74,28 +72,11 @@ class AuthDiscordController:
|
||||
oauth = OAuth2Session(
|
||||
self._bot.user.id,
|
||||
redirect_uri=self._auth_settings.redirect_url,
|
||||
scope=self._auth_settings.scope,
|
||||
scope=self._auth_settings.scope.to_list(),
|
||||
)
|
||||
login_url, state = oauth.authorization_url(self._auth_settings.auth_url)
|
||||
return jsonify({"loginUrl": login_url})
|
||||
|
||||
@Route.get(f"{BasePath}/create-user")
|
||||
async def discord_create_user(self) -> Response:
|
||||
response = self._get_user_from_discord_response()
|
||||
result = await self._auth_service.add_auth_user_by_discord_async(
|
||||
AuthUserDTO(
|
||||
0,
|
||||
response["username"],
|
||||
response["discriminator"],
|
||||
response["email"],
|
||||
str(uuid.uuid4()),
|
||||
None,
|
||||
AuthRoleEnum.normal,
|
||||
),
|
||||
response["id"],
|
||||
)
|
||||
return jsonify(result.to_dict())
|
||||
|
||||
@Route.get(f"{BasePath}/login")
|
||||
async def discord_login(self) -> Response:
|
||||
response = self._get_user_from_discord_response()
|
||||
@@ -109,5 +90,5 @@ class AuthDiscordController:
|
||||
AuthRoleEnum.normal,
|
||||
)
|
||||
|
||||
result = await self._auth_service.login_discord_async(dto)
|
||||
result = await self._auth_service.login_discord_async(dto, response["id"])
|
||||
return jsonify(result.to_dict())
|
||||
|
@@ -1,67 +0,0 @@
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.environment import ApplicationEnvironmentABC
|
||||
from cpl_core.mailing import EMailClientABC, EMailClientSettings
|
||||
from cpl_translation import TranslatePipe
|
||||
from flask import Response, jsonify, request
|
||||
|
||||
from bot_api.api import Api
|
||||
from bot_api.filter.discord.server_select_criteria import ServerSelectCriteria
|
||||
from bot_api.json_processor import JSONProcessor
|
||||
from bot_api.logging.api_logger import ApiLogger
|
||||
from bot_api.route.route import Route
|
||||
from bot_api.service.discord_service import DiscordService
|
||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
||||
|
||||
|
||||
class ServerController:
|
||||
BasePath = f"/api/discord/server"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
env: ApplicationEnvironmentABC,
|
||||
logger: ApiLogger,
|
||||
t: TranslatePipe,
|
||||
api: Api,
|
||||
mail_settings: EMailClientSettings,
|
||||
mailer: EMailClientABC,
|
||||
discord_service: DiscordService,
|
||||
):
|
||||
self._config = config
|
||||
self._env = env
|
||||
self._logger = logger
|
||||
self._t = t
|
||||
self._api = api
|
||||
self._mail_settings = mail_settings
|
||||
self._mailer = mailer
|
||||
self._discord_service = discord_service
|
||||
|
||||
@Route.get(f"{BasePath}/get/servers")
|
||||
@Route.authorize(role=AuthRoleEnum.admin)
|
||||
async def get_all_servers(self) -> Response:
|
||||
result = await self._discord_service.get_all_servers()
|
||||
result = result.select(lambda x: x.to_dict()).to_list()
|
||||
return jsonify(result)
|
||||
|
||||
@Route.get(f"{BasePath}/get/servers-by-user")
|
||||
@Route.authorize
|
||||
async def get_all_servers_by_user(self) -> Response:
|
||||
result = await self._discord_service.get_all_servers_by_user()
|
||||
result = result.select(lambda x: x.to_dict()).to_list()
|
||||
return jsonify(result)
|
||||
|
||||
@Route.post(f"{BasePath}/get/filtered")
|
||||
@Route.authorize
|
||||
async def get_filtered_servers(self) -> Response:
|
||||
dto: ServerSelectCriteria = JSONProcessor.process(
|
||||
ServerSelectCriteria, request.get_json(force=True, silent=True)
|
||||
)
|
||||
result = await self._discord_service.get_filtered_servers_async(dto)
|
||||
result.result = result.result.select(lambda x: x.to_dict()).to_list()
|
||||
return jsonify(result.to_dict())
|
||||
|
||||
@Route.get(f"{BasePath}/get/<id>")
|
||||
@Route.authorize
|
||||
async def get_server_by_id(self, id: int) -> Response:
|
||||
result = await self._discord_service.get_server_by_id_async(id).to_list()
|
||||
return jsonify(result.to_dict())
|
44
kdb-bot/src/bot_api/controller/graphql_controller.py
Normal file
44
kdb-bot/src/bot_api/controller/graphql_controller.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from ariadne import graphql_sync
|
||||
from ariadne.explorer import ExplorerPlayground
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.environment import ApplicationEnvironmentABC
|
||||
from flask import request, jsonify
|
||||
|
||||
from bot_api.logging.api_logger import ApiLogger
|
||||
from bot_api.route.route import Route
|
||||
from bot_graphql.schema import Schema
|
||||
|
||||
|
||||
class GraphQLController:
|
||||
BasePath = f"/api/graphql"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
env: ApplicationEnvironmentABC,
|
||||
logger: ApiLogger,
|
||||
schema: Schema,
|
||||
):
|
||||
self._config = config
|
||||
self._env = env
|
||||
self._logger = logger
|
||||
self._schema = schema
|
||||
|
||||
@Route.get(f"{BasePath}/playground")
|
||||
@Route.authorize(skip_in_dev=True)
|
||||
async def playground(self):
|
||||
if self._env.environment_name != "development":
|
||||
return "", 403
|
||||
|
||||
return ExplorerPlayground().html(None), 200
|
||||
|
||||
@Route.post(f"{BasePath}")
|
||||
@Route.authorize(by_api_key=True)
|
||||
async def graphql(self):
|
||||
data = request.get_json()
|
||||
|
||||
# Note: Passing the request to the context is optional.
|
||||
# In Flask, the current request is always accessible as flask.request
|
||||
success, result = graphql_sync(self._schema.schema, data, context_value=request)
|
||||
|
||||
return jsonify(result), 200 if success else 400
|
@@ -15,7 +15,7 @@ __title__ = "bot_api.event"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_api.exception"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -4,7 +4,6 @@ from werkzeug.exceptions import Unauthorized
|
||||
|
||||
|
||||
class ServiceErrorCode(Enum):
|
||||
|
||||
Unknown = 0
|
||||
|
||||
InvalidDependencies = 1
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_api.filter"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_api.filter.discord"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_api.logging"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_api.model"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -1,6 +1,10 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_api.abc.dto_abc import DtoABC
|
||||
from bot_api.model.user_dto import UserDTO
|
||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
||||
|
||||
|
||||
@@ -14,6 +18,9 @@ class AuthUserDTO(DtoABC):
|
||||
password: str = None,
|
||||
confirmation_id: Optional[str] = None,
|
||||
auth_role: AuthRoleEnum = None,
|
||||
users: List[UserDTO] = None,
|
||||
created_at: datetime = None,
|
||||
modified_at: datetime = None,
|
||||
):
|
||||
DtoABC.__init__(self)
|
||||
|
||||
@@ -24,6 +31,13 @@ class AuthUserDTO(DtoABC):
|
||||
self._password = password
|
||||
self._is_confirmed = confirmation_id is None
|
||||
self._auth_role = auth_role
|
||||
self._created_at = created_at
|
||||
self._modified_at = modified_at
|
||||
|
||||
if users is None:
|
||||
self._users = List(UserDTO)
|
||||
else:
|
||||
self._users = users
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
@@ -77,6 +91,18 @@ class AuthUserDTO(DtoABC):
|
||||
def auth_role(self, value: AuthRoleEnum):
|
||||
self._auth_role = value
|
||||
|
||||
@property
|
||||
def users(self) -> List[UserDTO]:
|
||||
return self._users
|
||||
|
||||
@property
|
||||
def created_at(self) -> datetime:
|
||||
return self._created_at
|
||||
|
||||
@property
|
||||
def modified_at(self) -> datetime:
|
||||
return self._modified_at
|
||||
|
||||
def from_dict(self, values: dict):
|
||||
self._id = values["id"]
|
||||
self._first_name = values["firstName"]
|
||||
@@ -85,6 +111,15 @@ class AuthUserDTO(DtoABC):
|
||||
self._password = values["password"]
|
||||
self._is_confirmed = values["isConfirmed"]
|
||||
self._auth_role = AuthRoleEnum(values["authRole"])
|
||||
if "users" in values:
|
||||
self._users = List(UserDTO)
|
||||
for u in values["users"]:
|
||||
user = UserDTO()
|
||||
user.from_dict(u)
|
||||
self._users.add(user)
|
||||
|
||||
self._created_at = values["createdAt"]
|
||||
self._modified_at = values["modifiedAt"]
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
@@ -95,4 +130,7 @@ class AuthUserDTO(DtoABC):
|
||||
"password": self._password,
|
||||
"isConfirmed": self._is_confirmed,
|
||||
"authRole": self._auth_role.value,
|
||||
"users": self._users.select(lambda u: u.to_dict()).to_list(),
|
||||
"createdAt": self._created_at,
|
||||
"modifiedAt": self._modified_at,
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_api.model.discord"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -1,16 +1,13 @@
|
||||
import traceback
|
||||
|
||||
from cpl_core.console import Console
|
||||
|
||||
from bot_api.abc.dto_abc import DtoABC
|
||||
|
||||
|
||||
class TokenDTO(DtoABC):
|
||||
def __init__(self, token: str, refresh_token: str):
|
||||
def __init__(self, token: str, refresh_token: str, first_login: bool = False):
|
||||
DtoABC.__init__(self)
|
||||
|
||||
self._token = token
|
||||
self._refresh_token = refresh_token
|
||||
self._first_login = first_login
|
||||
|
||||
@property
|
||||
def token(self) -> str:
|
||||
@@ -20,9 +17,14 @@ class TokenDTO(DtoABC):
|
||||
def refresh_token(self) -> str:
|
||||
return self._refresh_token
|
||||
|
||||
@property
|
||||
def first_login(self) -> bool:
|
||||
return self._first_login
|
||||
|
||||
def from_dict(self, values: dict):
|
||||
self._token = values["token"]
|
||||
self._refresh_token = values["refreshToken"]
|
||||
self._first_login = values["firstLogin"]
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {"token": self._token, "refreshToken": self._refresh_token}
|
||||
return {"token": self._token, "refreshToken": self._refresh_token, "firstLogin": self._first_login}
|
||||
|
76
kdb-bot/src/bot_api/model/user_dto.py
Normal file
76
kdb-bot/src/bot_api/model/user_dto.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from typing import Optional
|
||||
|
||||
from bot_api.abc.dto_abc import DtoABC
|
||||
from bot_data.model.server import Server
|
||||
|
||||
|
||||
class UserDTO(DtoABC):
|
||||
def __init__(
|
||||
self,
|
||||
id: int = None,
|
||||
dc_id: int = None,
|
||||
xp: int = None,
|
||||
server: Optional[Server] = None,
|
||||
is_technician: Optional[bool] = None,
|
||||
is_admin: Optional[bool] = None,
|
||||
is_moderator: Optional[bool] = None,
|
||||
):
|
||||
DtoABC.__init__(self)
|
||||
|
||||
self._user_id = id
|
||||
self._discord_id = dc_id
|
||||
self._xp = xp
|
||||
self._server = server
|
||||
|
||||
self._is_technician = is_technician
|
||||
self._is_admin = is_admin
|
||||
self._is_moderator = is_moderator
|
||||
|
||||
@property
|
||||
def user_id(self) -> int:
|
||||
return self._user_id
|
||||
|
||||
@property
|
||||
def discord_id(self) -> int:
|
||||
return self._discord_id
|
||||
|
||||
@property
|
||||
def xp(self) -> int:
|
||||
return self._xp
|
||||
|
||||
@xp.setter
|
||||
def xp(self, value: int):
|
||||
self._xp = value
|
||||
|
||||
@property
|
||||
def server(self) -> Optional[Server]:
|
||||
return self._server
|
||||
|
||||
@property
|
||||
def is_technician(self) -> bool:
|
||||
return self._is_technician if self._is_technician is not None else False
|
||||
|
||||
@property
|
||||
def is_admin(self) -> bool:
|
||||
return self._is_admin if self._is_admin is not None else False
|
||||
|
||||
@property
|
||||
def is_moderator(self) -> bool:
|
||||
return self._is_moderator if self._is_moderator is not None else False
|
||||
|
||||
def from_dict(self, values: dict):
|
||||
self._user_id = values["id"]
|
||||
self._discord_id = values["dcId"]
|
||||
self._xp = values["xp"]
|
||||
self._server = values["server"]
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"id": self._user_id,
|
||||
"dcId": self._discord_id,
|
||||
"xp": self._xp,
|
||||
"server": self._server.id,
|
||||
"isTechnician": self.is_technician,
|
||||
"isAdmin": self.is_admin,
|
||||
"isModerator": self.is_moderator,
|
||||
}
|
@@ -15,7 +15,7 @@ __title__ = "bot_api.route"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -1,7 +1,9 @@
|
||||
import functools
|
||||
from functools import wraps
|
||||
from typing import Optional, Callable
|
||||
from typing import Optional, Callable, Union
|
||||
|
||||
from cpl_core.dependency_injection import ServiceProviderABC
|
||||
from cpl_core.environment import ApplicationEnvironmentABC
|
||||
from flask import request, jsonify
|
||||
from flask_cors import cross_origin
|
||||
|
||||
@@ -11,6 +13,7 @@ from bot_api.exception.service_exception import ServiceException
|
||||
from bot_api.model.error_dto import ErrorDTO
|
||||
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
|
||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
||||
from bot_data.model.auth_user import AuthUser
|
||||
|
||||
|
||||
class Route:
|
||||
@@ -18,23 +21,77 @@ class Route:
|
||||
|
||||
_auth_users: Optional[AuthUserRepositoryABC] = None
|
||||
_auth: Optional[AuthServiceABC] = None
|
||||
_env = "production"
|
||||
|
||||
@classmethod
|
||||
def init_authorize(cls, auth_users: AuthUserRepositoryABC, auth: AuthServiceABC):
|
||||
@ServiceProviderABC.inject
|
||||
def init_authorize(cls, env: ApplicationEnvironmentABC, auth_users: AuthUserRepositoryABC, auth: AuthServiceABC):
|
||||
cls._auth_users = auth_users
|
||||
cls._auth = auth
|
||||
cls._env = env.environment_name
|
||||
|
||||
@classmethod
|
||||
def authorize(cls, f: Callable = None, role: AuthRoleEnum = None):
|
||||
def get_user(cls) -> Optional[Union[str, AuthUser]]:
|
||||
token = None
|
||||
api_key = None
|
||||
authorization = request.headers.get("Authorization").split()
|
||||
match authorization[0]:
|
||||
case "Bearer":
|
||||
token = authorization[1]
|
||||
case "API-Key":
|
||||
api_key = authorization[1]
|
||||
|
||||
if api_key is not None:
|
||||
return "system"
|
||||
|
||||
if token is None:
|
||||
return None
|
||||
|
||||
jwt = cls._auth.decode_token(token)
|
||||
user = cls._auth_users.get_auth_user_by_email(jwt["email"])
|
||||
return user
|
||||
|
||||
@classmethod
|
||||
def authorize(cls, f: Callable = None, role: AuthRoleEnum = None, skip_in_dev=False, by_api_key=False):
|
||||
if f is None:
|
||||
return functools.partial(cls.authorize, role=role)
|
||||
return functools.partial(cls.authorize, role=role, skip_in_dev=skip_in_dev, by_api_key=by_api_key)
|
||||
|
||||
@wraps(f)
|
||||
async def decorator(*args, **kwargs):
|
||||
if skip_in_dev and cls._env == "development":
|
||||
return await f(*args, **kwargs)
|
||||
|
||||
token = None
|
||||
api_key = None
|
||||
if "Authorization" in request.headers:
|
||||
bearer = request.headers.get("Authorization")
|
||||
token = bearer.split()[1]
|
||||
if " " not in request.headers.get("Authorization"):
|
||||
ex = ServiceException(ServiceErrorCode.Unauthorized, f"Token not set")
|
||||
error = ErrorDTO(ex.error_code, ex.message)
|
||||
return jsonify(error.to_dict()), 401
|
||||
|
||||
authorization = request.headers.get("Authorization").split()
|
||||
match authorization[0]:
|
||||
case "Bearer":
|
||||
token = authorization[1]
|
||||
case "API-Key":
|
||||
api_key = authorization[1]
|
||||
|
||||
if api_key is not None:
|
||||
valid = False
|
||||
try:
|
||||
valid = cls._auth.verify_api_key(api_key)
|
||||
except ServiceException as e:
|
||||
error = ErrorDTO(e.error_code, e.message)
|
||||
return jsonify(error.to_dict()), 403
|
||||
except Exception as e:
|
||||
return jsonify(e), 500
|
||||
|
||||
if not valid:
|
||||
ex = ServiceException(ServiceErrorCode.Unauthorized, f"API-Key invalid")
|
||||
error = ErrorDTO(ex.error_code, ex.message)
|
||||
return jsonify(error.to_dict()), 401
|
||||
|
||||
return await f(*args, **kwargs)
|
||||
|
||||
if token is None:
|
||||
ex = ServiceException(ServiceErrorCode.Unauthorized, f"Token not set")
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_api.service"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -31,9 +31,11 @@ from bot_api.model.reset_password_dto import ResetPasswordDTO
|
||||
from bot_api.model.token_dto import TokenDTO
|
||||
from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO
|
||||
from bot_api.transformer.auth_user_transformer import AuthUserTransformer as AUT
|
||||
from bot_data.abc.api_key_repository_abc import ApiKeyRepositoryABC
|
||||
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||
from bot_data.model.api_key import ApiKey
|
||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
||||
from bot_data.model.auth_user import AuthUser
|
||||
from bot_data.model.auth_user_users_relation import AuthUserUsersRelation
|
||||
@@ -49,9 +51,9 @@ class AuthService(AuthServiceABC):
|
||||
bot: DiscordBotServiceABC,
|
||||
db: DatabaseContextABC,
|
||||
auth_users: AuthUserRepositoryABC,
|
||||
api_keys: ApiKeyRepositoryABC,
|
||||
users: UserRepositoryABC,
|
||||
servers: ServerRepositoryABC,
|
||||
# mailer: MailThread,
|
||||
mailer: EMailClientABC,
|
||||
t: TranslatePipe,
|
||||
auth_settings: AuthenticationSettings,
|
||||
@@ -64,6 +66,7 @@ class AuthService(AuthServiceABC):
|
||||
self._bot = bot
|
||||
self._db = db
|
||||
self._auth_users = auth_users
|
||||
self._api_keys = api_keys
|
||||
self._users = users
|
||||
self._servers = servers
|
||||
self._mailer = mailer
|
||||
@@ -77,11 +80,19 @@ class AuthService(AuthServiceABC):
|
||||
|
||||
@staticmethod
|
||||
def _is_email_valid(email: str) -> bool:
|
||||
if email is None:
|
||||
raise False
|
||||
|
||||
if re.fullmatch(_email_regex, email) is not None:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _get_api_key_str(self, api_key: ApiKey) -> str:
|
||||
return hashlib.sha256(
|
||||
f"{api_key.identifier}:{api_key.key}+{self._auth_settings.secret_key}".encode("utf-8")
|
||||
).hexdigest()
|
||||
|
||||
def generate_token(self, user: AuthUser) -> str:
|
||||
token = jwt.encode(
|
||||
payload={
|
||||
@@ -215,7 +226,7 @@ class AuthService(AuthServiceABC):
|
||||
user = self._auth_users.find_auth_user_by_email(email)
|
||||
return AUT.to_dto(user) if user is not None else None
|
||||
|
||||
async def add_auth_user_async(self, user_dto: AuthUserDTO):
|
||||
def add_auth_user(self, user_dto: AuthUserDTO):
|
||||
db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
|
||||
if db_user is not None:
|
||||
raise ServiceException(ServiceErrorCode.InvalidUser, "User already exists")
|
||||
@@ -264,51 +275,6 @@ class AuthService(AuthServiceABC):
|
||||
|
||||
self._db.save_changes()
|
||||
|
||||
async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO, dc_id: int) -> OAuthDTO:
|
||||
db_auth_user = self._auth_users.find_auth_user_by_email(user_dto.email)
|
||||
|
||||
# user exists
|
||||
if db_auth_user is not None and db_auth_user.users.count() > 0:
|
||||
# raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists')
|
||||
self._logger.debug(__name__, f"Discord user already exists")
|
||||
return OAuthDTO(AUT.to_dto(db_auth_user), None)
|
||||
|
||||
# user exists but discord user id not set
|
||||
elif db_auth_user is not None and db_auth_user.users.count() == 0:
|
||||
self._logger.debug(__name__, f"Auth user exists but not linked with discord")
|
||||
# users = self._users.get_users_by_discord_id(user_dto.user_id)
|
||||
# add auth_user to user refs
|
||||
db_auth_user.oauth_id = None
|
||||
|
||||
else:
|
||||
# user does not exists
|
||||
self._logger.debug(__name__, f"Auth user does not exist")
|
||||
try:
|
||||
user_dto.user_id = self._users.get_users_by_discord_id(user_dto.user_id).single().user_id
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"User not found")
|
||||
user_dto.user_id = None
|
||||
|
||||
await self.add_auth_user_async(user_dto)
|
||||
db_auth_user = self._auth_users.get_auth_user_by_email(user_dto.email)
|
||||
db_auth_user.oauth_id = uuid.uuid4()
|
||||
|
||||
for g in self._bot.guilds:
|
||||
member = g.get_member(int(dc_id))
|
||||
if member is None:
|
||||
continue
|
||||
|
||||
server = self._servers.get_server_by_discord_id(g.id)
|
||||
users = self._users.get_users_by_discord_id(dc_id)
|
||||
for user in users:
|
||||
if user.server.server_id != server.server_id:
|
||||
continue
|
||||
self._auth_users.add_auth_user_user_rel(AuthUserUsersRelation(db_auth_user, user))
|
||||
|
||||
self._auth_users.update_auth_user(db_auth_user)
|
||||
self._db.save_changes()
|
||||
return OAuthDTO(AUT.to_dto(db_auth_user), db_auth_user.oauth_id)
|
||||
|
||||
async def update_user_async(self, update_user_dto: UpdateAuthUserDTO):
|
||||
if update_user_dto is None:
|
||||
raise ServiceException(ServiceErrorCode.InvalidData, f"User is empty")
|
||||
@@ -478,6 +444,18 @@ class AuthService(AuthServiceABC):
|
||||
|
||||
return True
|
||||
|
||||
def verify_api_key(self, api_key: str) -> bool:
|
||||
try:
|
||||
keys = self._api_keys.get_api_keys().select(self._get_api_key_str)
|
||||
|
||||
if not keys.contains(api_key):
|
||||
raise ServiceException(ServiceErrorCode.InvalidData, "API-Key invalid")
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"API-Key invalid", e)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
async def login_async(self, user_dto: AuthUser) -> TokenDTO:
|
||||
if user_dto is None:
|
||||
raise ServiceException(ServiceErrorCode.InvalidData, "User not set")
|
||||
@@ -490,6 +468,9 @@ class AuthService(AuthServiceABC):
|
||||
if db_user.password != user_dto.password:
|
||||
raise ServiceException(ServiceErrorCode.InvalidUser, "Wrong password")
|
||||
|
||||
if db_user.confirmation_id is not None:
|
||||
raise ServiceException(ServiceErrorCode.Forbidden, "E-Mail not verified")
|
||||
|
||||
token = self.generate_token(db_user)
|
||||
refresh_token = self._create_and_save_refresh_token(db_user)
|
||||
if db_user.forgot_password_id is not None:
|
||||
@@ -498,23 +479,34 @@ class AuthService(AuthServiceABC):
|
||||
self._db.save_changes()
|
||||
return TokenDTO(token, refresh_token)
|
||||
|
||||
async def login_discord_async(self, user_dto: AuthUserDTO) -> TokenDTO:
|
||||
async def login_discord_async(self, user_dto: AuthUserDTO, dc_id: int) -> TokenDTO:
|
||||
if user_dto is None:
|
||||
raise ServiceException(ServiceErrorCode.InvalidData, "User not set")
|
||||
|
||||
members = self._users.get_users_by_discord_id(dc_id)
|
||||
if members.count() == 0:
|
||||
raise ServiceException(ServiceErrorCode.InvalidUser, f"Member not found")
|
||||
|
||||
added_user = False
|
||||
db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
|
||||
if db_user is None:
|
||||
await self.add_auth_user_async(user_dto)
|
||||
# raise ServiceException(ServiceErrorCode.InvalidUser, f'User not found')
|
||||
self.add_auth_user(user_dto)
|
||||
added_user = True
|
||||
|
||||
db_user = self._auth_users.get_auth_user_by_email(user_dto.email)
|
||||
if db_user.users.count() == 0:
|
||||
members.for_each(lambda x: self._auth_users.add_auth_user_user_rel(AuthUserUsersRelation(db_user, x)))
|
||||
|
||||
if db_user.confirmation_id is not None and not added_user:
|
||||
raise ServiceException(ServiceErrorCode.Forbidden, "E-Mail not verified")
|
||||
|
||||
token = self.generate_token(db_user)
|
||||
refresh_token = self._create_and_save_refresh_token(db_user)
|
||||
if db_user.forgot_password_id is not None:
|
||||
db_user.forgot_password_id = None
|
||||
|
||||
self._db.save_changes()
|
||||
return TokenDTO(token, refresh_token)
|
||||
return TokenDTO(token, refresh_token, first_login=added_user)
|
||||
|
||||
async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO:
|
||||
if token_dto is None:
|
||||
|
@@ -2,7 +2,6 @@ from typing import Optional
|
||||
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
from cpl_query.extension import List
|
||||
from flask import jsonify
|
||||
|
||||
from bot_api.abc.auth_service_abc import AuthServiceABC
|
||||
from bot_api.exception.service_error_code_enum import ServiceErrorCode
|
||||
@@ -10,7 +9,6 @@ from bot_api.exception.service_exception import ServiceException
|
||||
from bot_api.filter.discord.server_select_criteria import ServerSelectCriteria
|
||||
from bot_api.model.discord.server_dto import ServerDTO
|
||||
from bot_api.model.discord.server_filtered_result_dto import ServerFilteredResultDTO
|
||||
from bot_api.model.error_dto import ErrorDTO
|
||||
from bot_api.transformer.server_transformer import ServerTransformer
|
||||
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
@@ -35,7 +33,7 @@ class DiscordService:
|
||||
self._users = users
|
||||
|
||||
def _to_dto(self, x: Server) -> Optional[ServerDTO]:
|
||||
guild = self._bot.get_guild(x.discord_server_id)
|
||||
guild = self._bot.get_guild(x.discord_id)
|
||||
if guild is None:
|
||||
return ServerTransformer.to_dto(x, "", 0, None)
|
||||
|
||||
@@ -55,8 +53,8 @@ class DiscordService:
|
||||
if role != AuthRoleEnum.admin:
|
||||
auth_user = self._auth_users.find_auth_user_by_email(token["email"])
|
||||
if auth_user is not None:
|
||||
user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.server_id)
|
||||
servers = servers.where(lambda x: x.server_id in user_ids)
|
||||
user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.id)
|
||||
servers = servers.where(lambda x: x.id in user_ids)
|
||||
|
||||
servers = List(ServerDTO, servers)
|
||||
return servers.select(self._to_dto).where(lambda x: x.name != "")
|
||||
@@ -72,8 +70,8 @@ class DiscordService:
|
||||
if role != AuthRoleEnum.admin:
|
||||
auth_user = self._auth_users.find_auth_user_by_email(token["email"])
|
||||
if auth_user is not None:
|
||||
user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.server_id)
|
||||
filtered_result.result = filtered_result.result.where(lambda x: x.server_id in user_ids)
|
||||
user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.id)
|
||||
filtered_result.result = filtered_result.result.where(lambda x: x.id in user_ids)
|
||||
|
||||
servers: List = filtered_result.result.select(self._to_dto).where(lambda x: x.name != "")
|
||||
result = List(ServerDTO, servers)
|
||||
@@ -87,7 +85,7 @@ class DiscordService:
|
||||
|
||||
async def get_server_by_id_async(self, id: int) -> ServerDTO:
|
||||
server = self._servers.get_server_by_id(id)
|
||||
guild = self._bot.get_guild(server.discord_server_id)
|
||||
guild = self._bot.get_guild(server.discord_id)
|
||||
|
||||
server_dto = ServerTransformer.to_dto(server, guild.name, guild.member_count, guild.icon)
|
||||
return server_dto
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_api.transformer"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -1,9 +1,16 @@
|
||||
from datetime import datetime, timezone
|
||||
from datetime import datetime
|
||||
|
||||
from cpl_core.dependency_injection import ServiceProviderABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_api.abc.transformer_abc import TransformerABC
|
||||
from bot_api.model.auth_user_dto import AuthUserDTO
|
||||
from bot_api.model.user_dto import UserDTO
|
||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
||||
from bot_data.model.auth_user import AuthUser
|
||||
from bot_data.model.user import User
|
||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
||||
|
||||
|
||||
class AuthUserTransformer(TransformerABC):
|
||||
@@ -25,7 +32,28 @@ class AuthUserTransformer(TransformerABC):
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def to_dto(db: AuthUser, password: str = None) -> AuthUserDTO:
|
||||
@ServiceProviderABC.inject
|
||||
def _is_technician(user: User, bot: DiscordBotServiceABC, permissions: PermissionServiceABC):
|
||||
guild = bot.get_guild(user.server.discord_id)
|
||||
member = guild.get_member(user.discord_id)
|
||||
return permissions.is_member_technician(member)
|
||||
|
||||
@staticmethod
|
||||
@ServiceProviderABC.inject
|
||||
def _is_admin(user: User, bot: DiscordBotServiceABC, permissions: PermissionServiceABC):
|
||||
guild = bot.get_guild(user.server.discord_id)
|
||||
member = guild.get_member(user.discord_id)
|
||||
return permissions.is_member_admin(member)
|
||||
|
||||
@staticmethod
|
||||
@ServiceProviderABC.inject
|
||||
def _is_moderator(user: User, bot: DiscordBotServiceABC, permissions: PermissionServiceABC):
|
||||
guild = bot.get_guild(user.server.discord_id)
|
||||
member = guild.get_member(user.discord_id)
|
||||
return permissions.is_member_moderator(member)
|
||||
|
||||
@classmethod
|
||||
def to_dto(cls, db: AuthUser, password: str = None) -> AuthUserDTO:
|
||||
return AuthUserDTO(
|
||||
db.id,
|
||||
db.first_name,
|
||||
@@ -34,4 +62,20 @@ class AuthUserTransformer(TransformerABC):
|
||||
"" if password is None else password,
|
||||
db.confirmation_id,
|
||||
db.auth_role,
|
||||
List(
|
||||
UserDTO,
|
||||
db.users.select(
|
||||
lambda u: UserDTO(
|
||||
u.id,
|
||||
u.discord_id,
|
||||
u.xp,
|
||||
u.server,
|
||||
cls._is_technician(u),
|
||||
cls._is_admin(u),
|
||||
cls._is_moderator(u),
|
||||
)
|
||||
),
|
||||
),
|
||||
db.created_at,
|
||||
db.modified_at,
|
||||
)
|
||||
|
@@ -15,8 +15,8 @@ class ServerTransformer(TransformerABC):
|
||||
@staticmethod
|
||||
def to_dto(db: Server, name: str, member_count: int, icon_url: Optional[discord.Asset]) -> ServerDTO:
|
||||
return ServerDTO(
|
||||
db.server_id,
|
||||
db.discord_server_id,
|
||||
db.id,
|
||||
db.discord_id,
|
||||
name,
|
||||
member_count,
|
||||
icon_url.url if icon_url is not None else None,
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_core"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_core.abc"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -2,11 +2,13 @@ from abc import ABC, abstractmethod
|
||||
from datetime import datetime
|
||||
from typing import Callable
|
||||
|
||||
import discord
|
||||
from cpl_query.extension import List
|
||||
from discord.ext.commands import Context
|
||||
|
||||
from bot_data.model.auto_role_rule import AutoRoleRule
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from bot_data.model.user import User
|
||||
from modules.base.configuration.base_server_settings import BaseServerSettings
|
||||
|
||||
|
||||
class ClientUtilsABC(ABC):
|
||||
@@ -51,7 +53,7 @@ class ClientUtilsABC(ABC):
|
||||
self,
|
||||
created_at: datetime,
|
||||
user: User,
|
||||
settings: BaseServerSettings,
|
||||
settings: ServerConfig,
|
||||
is_reaction: bool = False,
|
||||
) -> bool:
|
||||
pass
|
||||
@@ -59,3 +61,9 @@ class ClientUtilsABC(ABC):
|
||||
@abstractmethod
|
||||
def get_ontime_for_user(self, user: User) -> float:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def react_to_message_by_auto_role_rule(
|
||||
self, discord_channel_id: int, discord_message_id: int, rule: AutoRoleRule, guild: discord.Guild
|
||||
):
|
||||
pass
|
||||
|
@@ -25,7 +25,9 @@ class MessageServiceABC(ABC):
|
||||
self,
|
||||
channel: discord.TextChannel,
|
||||
message: Union[str, discord.Embed],
|
||||
without_tracking=True,
|
||||
is_persistent: bool = False,
|
||||
wait_before_delete: int = None,
|
||||
without_tracking=False,
|
||||
):
|
||||
pass
|
||||
|
||||
|
@@ -2,9 +2,9 @@
|
||||
"ProjectSettings": {
|
||||
"Name": "bot-core",
|
||||
"Version": {
|
||||
"Major": "0",
|
||||
"Minor": "3",
|
||||
"Micro": "1"
|
||||
"Major": "1",
|
||||
"Minor": "0",
|
||||
"Micro": "7"
|
||||
},
|
||||
"Author": "Sven Heidemann",
|
||||
"AuthorEmail": "sven.heidemann@sh-edraft.de",
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_core.configuration"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -1,32 +1,25 @@
|
||||
import traceback
|
||||
|
||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl_core.console import Console, ForegroundColorEnum
|
||||
from cpl_core.utils.json_processor import JSONProcessor
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_core.configuration.file_logging_settings import FileLoggingSettings
|
||||
|
||||
|
||||
class BotLoggingSettings(ConfigurationModelABC):
|
||||
def __init__(self):
|
||||
def __init__(self, **kwargs: dict):
|
||||
ConfigurationModelABC.__init__(self)
|
||||
self._files: List[FileLoggingSettings] = List(FileLoggingSettings)
|
||||
|
||||
if kwargs is not None:
|
||||
self._files_from_dict(kwargs)
|
||||
|
||||
@property
|
||||
def files(self) -> List[FileLoggingSettings]:
|
||||
return self._files
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
def _files_from_dict(self, settings: dict):
|
||||
files = List(FileLoggingSettings)
|
||||
for s in settings:
|
||||
st = FileLoggingSettings()
|
||||
settings[s]["Key"] = s
|
||||
st.from_dict(settings[s])
|
||||
files.append(st)
|
||||
files.append(JSONProcessor.process(FileLoggingSettings, settings[s]))
|
||||
self._files = files
|
||||
except Exception as e:
|
||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||
Console.write_line(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
|
||||
Console.write_line(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
@@ -1,62 +0,0 @@
|
||||
import traceback
|
||||
|
||||
from cpl_core.configuration import ConfigurationModelABC
|
||||
from cpl_core.console import Console
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_core.configuration.server_settings import ServerSettings
|
||||
|
||||
|
||||
class BotSettings(ConfigurationModelABC):
|
||||
def __init__(self):
|
||||
ConfigurationModelABC.__init__(self)
|
||||
|
||||
self._servers: List[ServerSettings] = List(ServerSettings)
|
||||
self._technicians: List[int] = List(int)
|
||||
self._wait_for_restart = 2
|
||||
self._wait_for_shutdown = 2
|
||||
self._cache_max_messages = 1000
|
||||
|
||||
@property
|
||||
def servers(self) -> List[ServerSettings]:
|
||||
return self._servers
|
||||
|
||||
@property
|
||||
def technicians(self) -> List[int]:
|
||||
return self._technicians
|
||||
|
||||
@property
|
||||
def wait_for_restart(self) -> int:
|
||||
return self._wait_for_restart
|
||||
|
||||
@property
|
||||
def wait_for_shutdown(self) -> int:
|
||||
return self._wait_for_shutdown
|
||||
|
||||
@property
|
||||
def cache_max_messages(self) -> int:
|
||||
return self._cache_max_messages
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
self._technicians = settings["Technicians"]
|
||||
self._wait_for_restart = settings["WaitForRestart"]
|
||||
self._wait_for_shutdown = settings["WaitForShutdown"]
|
||||
settings.pop("Technicians")
|
||||
settings.pop("WaitForRestart")
|
||||
settings.pop("WaitForShutdown")
|
||||
|
||||
if "CacheMaxMessages" in settings:
|
||||
self._cache_max_messages = settings["CacheMaxMessages"]
|
||||
settings.pop("CacheMaxMessages")
|
||||
|
||||
servers = List(ServerSettings)
|
||||
for s in settings:
|
||||
st = ServerSettings()
|
||||
settings[s]["Id"] = s
|
||||
st.from_dict(settings[s])
|
||||
servers.append(st)
|
||||
self._servers = servers
|
||||
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()}")
|
@@ -3,6 +3,7 @@ from enum import Enum
|
||||
|
||||
class FeatureFlagsEnum(Enum):
|
||||
# modules
|
||||
achievements_module = "AchievementsModule"
|
||||
api_module = "ApiModule"
|
||||
admin_module = "AdminModule"
|
||||
auto_role_module = "AutoRoleModule"
|
||||
@@ -10,12 +11,13 @@ class FeatureFlagsEnum(Enum):
|
||||
boot_log_module = "BootLogModule"
|
||||
core_module = "CoreModule"
|
||||
core_extension_module = "CoreExtensionModule"
|
||||
data_module = ("DataModule",)
|
||||
database_module = ("DatabaseModule",)
|
||||
data_module = "DataModule"
|
||||
database_module = "DatabaseModule"
|
||||
level_module = "LevelModule"
|
||||
moderator_module = "ModeratorModule"
|
||||
permission_module = "PermissionModule"
|
||||
stats_module = "StatsModule"
|
||||
config_module = "ConfigModule"
|
||||
# features
|
||||
api_only = "ApiOnly"
|
||||
presence = "Presence"
|
||||
version_in_presence = "VersionInPresence"
|
||||
|
@@ -1,18 +1,12 @@
|
||||
import traceback
|
||||
from typing import Optional, Callable
|
||||
|
||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl_core.console import Console
|
||||
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
|
||||
|
||||
class FeatureFlagsSettings(ConfigurationModelABC):
|
||||
def __init__(self):
|
||||
ConfigurationModelABC.__init__(self)
|
||||
|
||||
self._flags = {
|
||||
_flags = {
|
||||
# modules
|
||||
FeatureFlagsEnum.achievements_module.value: False, # 14.06.2023 #268
|
||||
FeatureFlagsEnum.api_module.value: False, # 13.10.2022 #70
|
||||
FeatureFlagsEnum.admin_module.value: False, # 02.10.2022 #48
|
||||
FeatureFlagsEnum.auto_role_module.value: True, # 03.10.2022 #54
|
||||
@@ -24,12 +18,22 @@ class FeatureFlagsSettings(ConfigurationModelABC):
|
||||
FeatureFlagsEnum.database_module.value: True, # 02.10.2022 #48
|
||||
FeatureFlagsEnum.moderator_module.value: False, # 02.10.2022 #48
|
||||
FeatureFlagsEnum.permission_module.value: True, # 02.10.2022 #48
|
||||
FeatureFlagsEnum.stats_module.value: True, # 08.11.2022 #46
|
||||
FeatureFlagsEnum.config_module.value: True, # 19.07.2023 #127
|
||||
# features
|
||||
FeatureFlagsEnum.api_only.value: False, # 13.10.2022 #70
|
||||
FeatureFlagsEnum.presence.value: True, # 03.10.2022 #56
|
||||
FeatureFlagsEnum.version_in_presence.value: False, # 21.03.2023 #253
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs: dict):
|
||||
ConfigurationModelABC.__init__(self)
|
||||
|
||||
if len(kwargs.keys()) == 0:
|
||||
return
|
||||
|
||||
for flag in [f.value for f in FeatureFlagsEnum]:
|
||||
self._load_flag(kwargs, FeatureFlagsEnum(flag))
|
||||
|
||||
def get_flag(self, key: FeatureFlagsEnum) -> bool:
|
||||
if key.value not in self._flags:
|
||||
return False
|
||||
@@ -40,11 +44,3 @@ class FeatureFlagsSettings(ConfigurationModelABC):
|
||||
return
|
||||
|
||||
self._flags[key.value] = bool(settings[key.value])
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
for flag in [f.value for f in FeatureFlagsEnum]:
|
||||
self._load_flag(settings, FeatureFlagsEnum(flag))
|
||||
except Exception as e:
|
||||
Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings")
|
||||
Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
|
||||
|
@@ -1,23 +1,19 @@
|
||||
import traceback
|
||||
|
||||
from cpl_core.console import Console
|
||||
from cpl_core.logging import LoggingSettings
|
||||
from cpl_core.logging import LoggingSettings, LoggingLevelEnum
|
||||
|
||||
|
||||
class FileLoggingSettings(LoggingSettings):
|
||||
def __init__(self):
|
||||
LoggingSettings.__init__(self)
|
||||
def __init__(
|
||||
self,
|
||||
key: str,
|
||||
path: str = None,
|
||||
filename: str = None,
|
||||
console_log_level: LoggingLevelEnum = None,
|
||||
file_log_level: LoggingLevelEnum = None,
|
||||
):
|
||||
LoggingSettings.__init__(self, path, filename, console_log_level, file_log_level)
|
||||
|
||||
self._key = ""
|
||||
self._key = key
|
||||
|
||||
@property
|
||||
def key(self) -> str:
|
||||
return self._key
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
self._key = settings["Key"]
|
||||
super().from_dict(settings)
|
||||
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,28 +0,0 @@
|
||||
import traceback
|
||||
|
||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl_core.console import Console
|
||||
|
||||
|
||||
class ServerSettings(ConfigurationModelABC):
|
||||
def __init__(self):
|
||||
ConfigurationModelABC.__init__(self)
|
||||
|
||||
self._id: int = 0
|
||||
self._message_delete_timer: int = 0
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def message_delete_timer(self) -> int:
|
||||
return self._message_delete_timer
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
self._id = int(settings["Id"])
|
||||
self._message_delete_timer = int(settings["MessageDeleteTimer"])
|
||||
except Exception as e:
|
||||
Console.error(f"[ ERROR ] [ {__name__} ]: Reading error in settings")
|
||||
Console.error(f"[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}")
|
@@ -15,7 +15,7 @@ __title__ = "bot_core.core_extension"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -11,6 +11,7 @@ from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_core.events.core_on_ready_event import CoreOnReadyEvent
|
||||
from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
|
||||
from bot_core.service.client_utils_service import ClientUtilsService
|
||||
from bot_core.service.data_integrity_service import DataIntegrityService
|
||||
from bot_core.service.message_service import MessageService
|
||||
|
||||
|
||||
@@ -24,6 +25,7 @@ class CoreModule(ModuleABC):
|
||||
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
|
||||
services.add_transient(MessageServiceABC, MessageService)
|
||||
services.add_transient(ClientUtilsABC, ClientUtilsService)
|
||||
services.add_transient(DataIntegrityService)
|
||||
|
||||
# pipes
|
||||
services.add_transient(DateTimeOffsetPipe)
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_core.events"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_core.exception"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_core.helper"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -1,13 +1,9 @@
|
||||
from typing import Optional
|
||||
|
||||
from cpl_translation import TranslatePipe
|
||||
from discord.ext import commands
|
||||
from discord.ext.commands import Context
|
||||
|
||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||
from bot_core.exception.check_error import CheckError
|
||||
from modules.permission.abc.permission_service_abc import PermissionServiceABC
|
||||
|
||||
|
||||
class EventChecks:
|
||||
@@ -23,7 +19,7 @@ class EventChecks:
|
||||
@classmethod
|
||||
def check_is_ready(cls):
|
||||
async def check_if_bot_is_ready() -> bool:
|
||||
result = await cls._client_utils.check_if_bot_is_ready()
|
||||
result = await cls._client_utils.check_if_bot_is_ready_yet()
|
||||
if not result:
|
||||
raise CheckError(f"Bot is not ready")
|
||||
return result
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_core.logging"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_core.pipes"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_core.service"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -9,6 +9,7 @@ from cpl_core.time import TimeFormatSettings
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
from cpl_query.extension import List
|
||||
from cpl_translation import TranslatePipe
|
||||
from discord import Guild
|
||||
from discord.ext.commands import Context
|
||||
|
||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
||||
@@ -23,9 +24,10 @@ from bot_data.abc.user_joined_voice_channel_repository_abc import (
|
||||
from bot_data.abc.user_message_count_per_hour_repository_abc import (
|
||||
UserMessageCountPerHourRepositoryABC,
|
||||
)
|
||||
from bot_data.model.auto_role_rule import AutoRoleRule
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from bot_data.model.user import User
|
||||
from bot_data.model.user_message_count_per_hour import UserMessageCountPerHour
|
||||
from modules.base.configuration.base_server_settings import BaseServerSettings
|
||||
|
||||
|
||||
class ClientUtilsService(ClientUtilsABC):
|
||||
@@ -60,28 +62,28 @@ class ClientUtilsService(ClientUtilsABC):
|
||||
|
||||
def received_command(self, guild_id: int):
|
||||
server = self._servers.get_server_by_discord_id(guild_id)
|
||||
client = self._clients.find_client_by_discord_id_and_server_id(self._bot.user.id, server.server_id)
|
||||
client = self._clients.find_client_by_discord_id_and_server_id(self._bot.user.id, server.id)
|
||||
client.received_command_count += 1
|
||||
self._clients.update_client(client)
|
||||
self._db.save_changes()
|
||||
|
||||
def moved_user(self, guild_id: int):
|
||||
server = self._servers.get_server_by_discord_id(guild_id)
|
||||
client = self._clients.find_client_by_discord_id_and_server_id(self._bot.user.id, server.server_id)
|
||||
client = self._clients.find_client_by_discord_id_and_server_id(self._bot.user.id, server.id)
|
||||
client.moved_users_count += 1
|
||||
self._clients.update_client(client)
|
||||
self._db.save_changes()
|
||||
|
||||
def moved_users(self, guild_id: int, count: int):
|
||||
server = self._servers.get_server_by_discord_id(guild_id)
|
||||
client = self._clients.find_client_by_discord_id_and_server_id(self._bot.user.id, server.server_id)
|
||||
client = self._clients.find_client_by_discord_id_and_server_id(self._bot.user.id, server.id)
|
||||
client.moved_users_count += count
|
||||
self._clients.update_client(client)
|
||||
self._db.save_changes()
|
||||
|
||||
def get_client(self, dc_ic: int, guild_id: int):
|
||||
server = self._servers.get_server_by_discord_id(guild_id)
|
||||
client = self._clients.find_client_by_discord_id_and_server_id(self._bot.user.id, server.server_id)
|
||||
client = self._clients.find_client_by_discord_id_and_server_id(self._bot.user.id, server.id)
|
||||
return client
|
||||
|
||||
async def check_if_bot_is_ready_yet(self) -> bool:
|
||||
@@ -111,7 +113,11 @@ class ClientUtilsService(ClientUtilsABC):
|
||||
|
||||
import bot
|
||||
|
||||
name = self._t.transform(t_key).format(bot.__version__)
|
||||
if self._feature_flags.get_flag(FeatureFlagsEnum.version_in_presence):
|
||||
name = f"{bot.__version__} {self._t.transform(t_key)}"
|
||||
else:
|
||||
name = self._t.transform(t_key)
|
||||
|
||||
await self._bot.change_presence(activity=discord.Game(name=name))
|
||||
self._logger.info(__name__, f"Set presence {name}")
|
||||
|
||||
@@ -133,12 +139,12 @@ class ClientUtilsService(ClientUtilsABC):
|
||||
self,
|
||||
created_at: datetime,
|
||||
user: User,
|
||||
settings: BaseServerSettings,
|
||||
settings: ServerConfig,
|
||||
is_reaction: bool = False,
|
||||
) -> bool:
|
||||
umcph = None
|
||||
try:
|
||||
umcph = self._umcphs.find_user_message_count_per_hour_by_user_id_and_date(user.user_id, created_at)
|
||||
umcph = self._umcphs.find_user_message_count_per_hour_by_user_id_and_date(user.id, created_at)
|
||||
if umcph is None:
|
||||
self._umcphs.add_user_message_count_per_hour(
|
||||
UserMessageCountPerHour(
|
||||
@@ -151,7 +157,7 @@ class ClientUtilsService(ClientUtilsABC):
|
||||
|
||||
self._db.save_changes()
|
||||
|
||||
umcph = self._umcphs.get_user_message_count_per_hour_by_user_id_and_date(user.user_id, created_at)
|
||||
umcph = self._umcphs.get_user_message_count_per_hour_by_user_id_and_date(user.id, created_at)
|
||||
except Exception as e:
|
||||
self._logger.error(
|
||||
__name__,
|
||||
@@ -183,8 +189,32 @@ class ClientUtilsService(ClientUtilsABC):
|
||||
|
||||
def get_ontime_for_user(self, user: User) -> float:
|
||||
return round(
|
||||
self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.user_id)
|
||||
self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.id)
|
||||
.where(lambda x: x.leaved_on is not None and x.joined_on is not None)
|
||||
.sum(lambda join: (join.leaved_on - join.joined_on).total_seconds() / 3600),
|
||||
2,
|
||||
)
|
||||
|
||||
async def react_to_message_by_auto_role_rule(
|
||||
self, discord_channel_id: int, discord_message_id: int, rule: AutoRoleRule, guild: discord.Guild
|
||||
):
|
||||
try:
|
||||
guild: Guild = self._bot.guilds.where(lambda g: g == guild).single()
|
||||
channel = guild.get_channel(discord_channel_id)
|
||||
message = await channel.fetch_message(discord_message_id)
|
||||
emoji = List(discord.Emoji, guild.emojis).where(lambda x: x.name == rule.emoji_name).single()
|
||||
|
||||
if emoji is None:
|
||||
self._logger.debug(__name__, f"Emoji {rule.emoji_name} not found")
|
||||
return
|
||||
await message.add_reaction(emoji)
|
||||
self._logger.debug(
|
||||
__name__,
|
||||
f"Added reaction {rule.emoji_name} to message: {discord_message_id}",
|
||||
)
|
||||
except Exception as e:
|
||||
self._logger.error(
|
||||
__name__,
|
||||
f"Cannot add reaction {rule.emoji_name} to message: {discord_message_id}",
|
||||
e,
|
||||
)
|
||||
|
396
kdb-bot/src/bot_core/service/data_integrity_service.py
Normal file
396
kdb-bot/src/bot_core/service/data_integrity_service.py
Normal file
@@ -0,0 +1,396 @@
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Union
|
||||
|
||||
import discord
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.database.context import DatabaseContextABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
|
||||
from bot_core.logging.database_logger import DatabaseLogger
|
||||
from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
|
||||
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
||||
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
|
||||
from bot_data.abc.user_joined_game_server_repository_abc import UserJoinedGameServerRepositoryABC
|
||||
from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
|
||||
from bot_data.abc.user_joined_voice_channel_repository_abc import (
|
||||
UserJoinedVoiceChannelRepositoryABC,
|
||||
)
|
||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||
from bot_data.model.client import Client
|
||||
from bot_data.model.known_user import KnownUser
|
||||
from bot_data.model.server import Server
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from bot_data.model.user import User
|
||||
from bot_data.model.user_joined_server import UserJoinedServer
|
||||
from bot_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
|
||||
from bot_data.service.seeder_service import SeederService
|
||||
from bot_data.service.user_repository_service import ServerRepositoryABC
|
||||
from modules.achievements.achievement_service import AchievementService
|
||||
|
||||
|
||||
class DataIntegrityService:
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
logger: DatabaseLogger,
|
||||
seeder: SeederService,
|
||||
bot: DiscordBotServiceABC,
|
||||
db_context: DatabaseContextABC,
|
||||
server_repo: ServerRepositoryABC,
|
||||
user_repo: UserRepositoryABC,
|
||||
client_repo: ClientRepositoryABC,
|
||||
known_users: KnownUserRepositoryABC,
|
||||
user_joins: UserJoinedServerRepositoryABC,
|
||||
user_joins_vc: UserJoinedVoiceChannelRepositoryABC,
|
||||
user_joined_gs: UserJoinedGameServerRepositoryABC,
|
||||
achievement_service: AchievementService,
|
||||
dtp: DateTimeOffsetPipe,
|
||||
):
|
||||
self._config = config
|
||||
|
||||
self._logger = logger
|
||||
self._seeder = seeder
|
||||
self._bot = bot
|
||||
self._db_context = db_context
|
||||
self._servers = server_repo
|
||||
self._users = user_repo
|
||||
self._clients = client_repo
|
||||
self._known_users = known_users
|
||||
self._user_joins = user_joins
|
||||
self._user_joins_vc = user_joins_vc
|
||||
self._user_joined_gs = user_joined_gs
|
||||
self._achievements = achievement_service
|
||||
self._dtp = dtp
|
||||
|
||||
self._is_for_shutdown = False
|
||||
|
||||
def _check_known_users(self):
|
||||
self._logger.debug(__name__, f"Start checking KnownUsers table, {len(self._bot.users)}")
|
||||
for u in self._bot.users:
|
||||
u: discord.User = u
|
||||
try:
|
||||
if u.bot:
|
||||
self._logger.trace(__name__, f"User {u.id} is ignored, because its a bot")
|
||||
continue
|
||||
|
||||
user = self._known_users.find_user_by_discord_id(u.id)
|
||||
if user is not None:
|
||||
continue
|
||||
|
||||
self._logger.warn(__name__, f"Unknown user: {u.id}")
|
||||
self._logger.debug(__name__, f"Add user: {u.id}")
|
||||
self._known_users.add_user(KnownUser(u.id))
|
||||
self._db_context.save_changes()
|
||||
|
||||
user = self._known_users.find_user_by_discord_id(u.id)
|
||||
if user is None:
|
||||
self._logger.fatal(__name__, f"Cannot add user: {u.id}")
|
||||
|
||||
self._logger.debug(__name__, f"Added user: {u.id}")
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"Cannot get user", e)
|
||||
|
||||
def _check_servers(self):
|
||||
self._logger.debug(__name__, f"Start checking Servers table")
|
||||
for g in self._bot.guilds:
|
||||
g: discord.Guild = g
|
||||
try:
|
||||
server = self._servers.find_server_by_discord_id(g.id)
|
||||
if server is not None:
|
||||
continue
|
||||
|
||||
self._logger.warn(__name__, f"Server not found in database: {g.id}")
|
||||
self._logger.debug(__name__, f"Add server: {g.id}")
|
||||
self._servers.add_server(Server(g.id))
|
||||
self._db_context.save_changes()
|
||||
|
||||
server = self._servers.find_server_by_discord_id(g.id)
|
||||
if server is None:
|
||||
self._logger.fatal(__name__, f"Cannot add server: {g.id}")
|
||||
|
||||
self._logger.debug(__name__, f"Added server: {g.id}")
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"Cannot get server", e)
|
||||
|
||||
results = self._servers.get_servers()
|
||||
if results is None or len(results) == 0:
|
||||
self._logger.error(__name__, f"Table Servers is empty!")
|
||||
|
||||
def _check_clients(self):
|
||||
self._logger.debug(__name__, f"Start checking Clients table")
|
||||
for g in self._bot.guilds:
|
||||
g: discord.Guild = g
|
||||
try:
|
||||
server: Server = self._servers.find_server_by_discord_id(g.id)
|
||||
if server is None:
|
||||
self._logger.fatal(__name__, f"Server not found in database: {g.id}")
|
||||
|
||||
client = self._clients.find_client_by_server_id(server.id)
|
||||
if client is not None:
|
||||
continue
|
||||
|
||||
self._logger.warn(
|
||||
__name__,
|
||||
f"Client for server {g.id} not found in database: {self._bot.user.id}",
|
||||
)
|
||||
self._logger.debug(__name__, f"Add client: {self._bot.user.id}")
|
||||
self._clients.add_client(Client(self._bot.user.id, 0, 0, 0, 0, 0, server))
|
||||
self._db_context.save_changes()
|
||||
|
||||
client = self._clients.find_client_by_server_id(server.id)
|
||||
if client is None:
|
||||
self._logger.fatal(
|
||||
__name__,
|
||||
f"Cannot add client {self._bot.user.id} for server {g.id}",
|
||||
)
|
||||
|
||||
self._logger.debug(__name__, f"Added client: {g.id}")
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"Cannot get client", e)
|
||||
|
||||
results = self._servers.get_servers()
|
||||
if results is None or len(results) == 0:
|
||||
self._logger.error(__name__, f"Table Servers is empty!")
|
||||
|
||||
def _check_users(self):
|
||||
self._logger.debug(__name__, f"Start checking Users table")
|
||||
for g in self._bot.guilds:
|
||||
g: discord.Guild = g
|
||||
|
||||
try:
|
||||
server = self._servers.find_server_by_discord_id(g.id)
|
||||
if server is None:
|
||||
self._logger.fatal(__name__, f"Server not found in database: {g.id}")
|
||||
|
||||
for u in g.members:
|
||||
u: Union[discord.Member, discord.User] = u
|
||||
if u.bot:
|
||||
self._logger.trace(__name__, f"User {u.id} is ignored, because its a bot")
|
||||
continue
|
||||
|
||||
user = self._users.find_user_by_discord_id_and_server_id(u.id, server.id)
|
||||
if user is not None:
|
||||
continue
|
||||
|
||||
self._logger.warn(__name__, f"User not found in database: {u.id}")
|
||||
self._logger.debug(__name__, f"Add user: {u.id}")
|
||||
self._users.add_user(User(u.id, 0, 0, 0, server))
|
||||
self._db_context.save_changes()
|
||||
|
||||
self._logger.debug(__name__, f"Added User: {u.id}")
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"Cannot get User", e)
|
||||
|
||||
results = self._users.get_users()
|
||||
if results is None or len(results) == 0:
|
||||
self._logger.error(__name__, f"Table Users is empty!")
|
||||
|
||||
def _check_user_joins(self):
|
||||
self._logger.debug(__name__, f"Start checking UserJoinedServers table")
|
||||
for guild in self._bot.guilds:
|
||||
guild: discord.Guild = guild
|
||||
|
||||
server = self._servers.find_server_by_discord_id(guild.id)
|
||||
if server is None:
|
||||
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
|
||||
|
||||
try:
|
||||
for u in guild.members:
|
||||
u: discord.User = u
|
||||
if u.bot:
|
||||
self._logger.trace(__name__, f"User {u.id} is ignored, because its a bot")
|
||||
continue
|
||||
|
||||
user = self._users.find_user_by_discord_id_and_server_id(u.id, server.id)
|
||||
if user is None:
|
||||
self._logger.fatal(__name__, f"User not found in database: {u.id}")
|
||||
|
||||
join = self._user_joins.find_active_user_joined_server_by_user_id(user.id)
|
||||
if join is not None:
|
||||
continue
|
||||
|
||||
m: discord.Member = u
|
||||
self._logger.warn(
|
||||
__name__,
|
||||
f"Active UserJoinedServer not found in database: {guild.id}:{u.id}@{m.joined_at}",
|
||||
)
|
||||
self._logger.debug(
|
||||
__name__,
|
||||
f"Add UserJoinedServer: {guild.id}:{u.id}@{m.joined_at}",
|
||||
)
|
||||
self._user_joins.add_user_joined_server(
|
||||
UserJoinedServer(user, self._dtp.transform(m.joined_at), None)
|
||||
)
|
||||
self._db_context.save_changes()
|
||||
|
||||
self._logger.debug(__name__, f"Added UserJoinedServer: {u.id}")
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"Cannot get UserJoinedServer", e)
|
||||
|
||||
results = self._users.get_users()
|
||||
if results is None or len(results) == 0:
|
||||
self._logger.error(__name__, f"Table Users is empty!")
|
||||
|
||||
joins = self._user_joins.get_user_joined_servers()
|
||||
for join in joins:
|
||||
join: UserJoinedServer = join
|
||||
if join.user.server.discord_id != guild.id:
|
||||
continue
|
||||
|
||||
if join.leaved_on is not None:
|
||||
continue
|
||||
|
||||
dc_user = guild.get_member(join.user.discord_id)
|
||||
if dc_user is None:
|
||||
self._logger.warn(
|
||||
__name__,
|
||||
f"User {join.user.discord_id} already left the server.",
|
||||
)
|
||||
join.leaved_on = datetime.now()
|
||||
self._user_joins.update_user_joined_server(join)
|
||||
|
||||
self._db_context.save_changes()
|
||||
|
||||
def _check_user_joins_vc(self):
|
||||
self._logger.debug(__name__, f"Start checking UserJoinedVoiceChannel table")
|
||||
for guild in self._bot.guilds:
|
||||
guild: discord.Guild = guild
|
||||
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{guild.id}")
|
||||
|
||||
server = self._servers.find_server_by_discord_id(guild.id)
|
||||
if server is None:
|
||||
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
|
||||
|
||||
try:
|
||||
# close open voice states
|
||||
for member in guild.members:
|
||||
if member.bot:
|
||||
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
|
||||
continue
|
||||
|
||||
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
|
||||
if user is None:
|
||||
self._logger.fatal(__name__, f"User not found in database: {member.id}")
|
||||
|
||||
joins = self._user_joins_vc.find_active_user_joined_voice_channels_by_user_id(user.id)
|
||||
if joins is None or len(joins) == 0:
|
||||
continue
|
||||
|
||||
for join in joins:
|
||||
self._logger.warn(
|
||||
__name__,
|
||||
f"Active UserJoinedVoiceChannel found in database: {guild.id}:{member.id}@{join.joined_on}",
|
||||
)
|
||||
join.leaved_on = datetime.now()
|
||||
|
||||
if (
|
||||
(join.leaved_on - join.joined_on).total_seconds() / 60 / 60
|
||||
) > settings.max_voice_state_hours:
|
||||
join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours)
|
||||
|
||||
self._user_joins_vc.update_user_joined_voice_channel(join)
|
||||
|
||||
if self._is_for_shutdown:
|
||||
user.xp = round(join.time * settings.xp_per_ontime_hour)
|
||||
self._users.update_user(user)
|
||||
|
||||
self._db_context.save_changes()
|
||||
if self._is_for_shutdown:
|
||||
return
|
||||
|
||||
# add open voice states
|
||||
for member in guild.members:
|
||||
if member.bot:
|
||||
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
|
||||
continue
|
||||
|
||||
if member.voice is None or member.voice.channel.id in settings.afk_channel_ids:
|
||||
continue
|
||||
|
||||
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
|
||||
if user is None:
|
||||
self._logger.fatal(__name__, f"User not found in database: {member.id}")
|
||||
|
||||
join = UserJoinedVoiceChannel(user, member.voice.channel.id, datetime.now())
|
||||
self._user_joins_vc.add_user_joined_voice_channel(join)
|
||||
self._db_context.save_changes()
|
||||
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"Cannot get UserJoinedVoiceChannel", e)
|
||||
|
||||
def _check_user_joined_gs(self):
|
||||
self._logger.debug(__name__, f"Start checking UserJoinedGameServer table")
|
||||
for guild in self._bot.guilds:
|
||||
guild: discord.Guild = guild
|
||||
|
||||
server = self._servers.find_server_by_discord_id(guild.id)
|
||||
if server is None:
|
||||
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
|
||||
|
||||
try:
|
||||
for member in guild.members:
|
||||
if member.bot:
|
||||
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
|
||||
continue
|
||||
|
||||
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
|
||||
if user is None:
|
||||
self._logger.fatal(__name__, f"User not found in database: {member.id}")
|
||||
|
||||
joins = self._user_joined_gs.find_active_user_joined_game_servers_by_user_id(user.id)
|
||||
if joins is None or len(joins) == 0:
|
||||
continue
|
||||
|
||||
for join in joins:
|
||||
self._logger.warn(
|
||||
__name__,
|
||||
f"Active UserJoinedGameServer found in database: {guild.id}:{member.id}@{join.joined_on}",
|
||||
)
|
||||
join.leaved_on = datetime.now()
|
||||
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{guild.id}")
|
||||
|
||||
if (
|
||||
(join.leaved_on - join.joined_on).total_seconds() / 60 / 60
|
||||
) > settings.max_voice_state_hours:
|
||||
join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours)
|
||||
|
||||
self._user_joined_gs.update_user_joined_game_server(join)
|
||||
if self._is_for_shutdown:
|
||||
user.xp = round(join.time * settings.xp_per_ontime_hour)
|
||||
self._users.update_user(user)
|
||||
|
||||
self._db_context.save_changes()
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"Cannot get UserJoinedGameServer", e)
|
||||
|
||||
def _check_for_user_achievements(self):
|
||||
self._logger.debug(__name__, f"Start checking UserGotAchievement table")
|
||||
|
||||
for guild in self._bot.guilds:
|
||||
server = self._servers.find_server_by_discord_id(guild.id)
|
||||
if server is None:
|
||||
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
|
||||
|
||||
for member in guild.members:
|
||||
if member.bot:
|
||||
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
|
||||
continue
|
||||
|
||||
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
|
||||
if user is None:
|
||||
self._logger.fatal(__name__, f"User not found in database: {member.id}")
|
||||
|
||||
self._bot.loop.create_task(self._achievements.validate_achievements_for_user(user))
|
||||
|
||||
def check_data_integrity(self, is_for_shutdown=False):
|
||||
if is_for_shutdown != self._is_for_shutdown:
|
||||
self._is_for_shutdown = is_for_shutdown
|
||||
|
||||
self._check_known_users()
|
||||
self._check_servers()
|
||||
self._check_clients()
|
||||
self._check_users()
|
||||
self._check_user_joins()
|
||||
self._check_user_joins_vc()
|
||||
self._check_user_joined_gs()
|
||||
self._check_for_user_achievements()
|
@@ -10,10 +10,10 @@ from discord import Interaction
|
||||
from discord.ext.commands import Context
|
||||
|
||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||
from bot_core.configuration.server_settings import ServerSettings
|
||||
from bot_core.helper.log_message_helper import LogMessageHelper
|
||||
from bot_core.logging.message_logger import MessageLogger
|
||||
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
|
||||
|
||||
class MessageService(MessageServiceABC):
|
||||
@@ -33,7 +33,7 @@ class MessageService(MessageServiceABC):
|
||||
|
||||
async def delete_messages(self, messages: List[discord.Message], guild_id: int, without_tracking=False):
|
||||
self._logger.debug(__name__, f"Try to delete {messages.count()} messages")
|
||||
server_st: ServerSettings = self._config.get_configuration(f"ServerSettings_{guild_id}")
|
||||
server_st: ServerConfig = self._config.get_configuration(f"ServerConfig_{guild_id}")
|
||||
await asyncio.sleep(server_st.message_delete_timer)
|
||||
for message in messages:
|
||||
await self.delete_message(message, mass_delete=True, without_tracking=without_tracking)
|
||||
@@ -50,7 +50,7 @@ class MessageService(MessageServiceABC):
|
||||
else None
|
||||
)
|
||||
|
||||
server_st: ServerSettings = self._config.get_configuration(f"ServerSettings_{guild_id}")
|
||||
server_st: ServerConfig = self._config.get_configuration(f"ServerConfig_{guild_id}")
|
||||
if not mass_delete:
|
||||
await asyncio.sleep(server_st.message_delete_timer)
|
||||
self._logger.debug(
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_data"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
@@ -15,7 +15,7 @@ __title__ = "bot_data.abc"
|
||||
__author__ = "Sven Heidemann"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "1.0.7"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -23,4 +23,4 @@ from collections import namedtuple
|
||||
# imports
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
|
||||
version_info = VersionInfo(major="0", minor="3", micro="1")
|
||||
version_info = VersionInfo(major="1", minor="0", micro="7")
|
||||
|
52
kdb-bot/src/bot_data/abc/achievement_repository_abc.py
Normal file
52
kdb-bot/src/bot_data/abc/achievement_repository_abc.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_data.model.achievement import Achievement
|
||||
from bot_data.model.user_got_achievement import UserGotAchievement
|
||||
|
||||
|
||||
class AchievementRepositoryABC(ABC):
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_achievements(self) -> List[Achievement]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_achievement_by_id(self, id: int) -> Achievement:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_achievements_by_server_id(self, server_id: int) -> List[Achievement]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_achievements_by_user_id(self, user_id: int) -> List[Achievement]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_got_achievements_by_achievement_id(self, achievement_id: int) -> List[Achievement]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_achievement(self, achievement: Achievement):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_achievement(self, achievement: Achievement):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_achievement(self, achievement: Achievement):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_user_got_achievement(self, join: UserGotAchievement):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_user_got_achievement(self, join: UserGotAchievement):
|
||||
pass
|
39
kdb-bot/src/bot_data/abc/api_key_repository_abc.py
Normal file
39
kdb-bot/src/bot_data/abc/api_key_repository_abc.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_data.model.api_key import ApiKey
|
||||
|
||||
|
||||
class ApiKeyRepositoryABC(ABC):
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_api_keys(self) -> List[ApiKey]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_api_key(self, identifier: str, key: str) -> ApiKey:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_api_key_by_id(self, id: int) -> ApiKey:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_api_key_by_key(self, key: str) -> ApiKey:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_api_key(self, api_key: ApiKey):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_api_key(self, api_key: ApiKey):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_api_key(self, api_key: ApiKey):
|
||||
pass
|
@@ -2,6 +2,7 @@ from abc import ABC, abstractmethod
|
||||
from typing import Optional
|
||||
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_data.model.client import Client
|
||||
|
||||
|
||||
@@ -22,6 +23,10 @@ class ClientRepositoryABC(ABC):
|
||||
def get_client_by_discord_id(self, discord_id: int) -> Client:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_clients_by_server_id(self, server_id: int) -> List[Client]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def find_client_by_discord_id(self, discord_id: int) -> Optional[Client]:
|
||||
pass
|
||||
|
@@ -7,5 +7,5 @@ class DataSeederABC(ABC):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def seed(self):
|
||||
async def seed(self):
|
||||
pass
|
||||
|
39
kdb-bot/src/bot_data/abc/game_server_repository_abc.py
Normal file
39
kdb-bot/src/bot_data/abc/game_server_repository_abc.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_data.model.game_server import GameServer
|
||||
|
||||
|
||||
class GameServerRepositoryABC(ABC):
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_game_servers(self) -> List[GameServer]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_game_server_by_id(self, id: int) -> GameServer:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_game_servers_by_server_id(self, id: int) -> List[GameServer]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_game_server_by_api_key_id(self, id: int) -> GameServer:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_game_server(self, game_server: GameServer):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_game_server(self, game_server: GameServer):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_game_server(self, game_server: GameServer):
|
||||
pass
|
27
kdb-bot/src/bot_data/abc/history_table_abc.py
Normal file
27
kdb-bot/src/bot_data/abc/history_table_abc.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class HistoryTableABC(ABC):
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
self._id = 0
|
||||
self._deleted = False
|
||||
self._date_from = datetime.now().isoformat()
|
||||
self._date_to = datetime.now().isoformat()
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def deleted(self) -> bool:
|
||||
return self._deleted
|
||||
|
||||
@property
|
||||
def date_from(self) -> str:
|
||||
return self._date_from
|
||||
|
||||
@property
|
||||
def date_to(self) -> str:
|
||||
return self._date_to
|
@@ -3,6 +3,7 @@ from abc import ABC, abstractmethod
|
||||
|
||||
class MigrationABC(ABC):
|
||||
name = None
|
||||
prio = 0
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
|
59
kdb-bot/src/bot_data/abc/server_config_repository_abc.py
Normal file
59
kdb-bot/src/bot_data/abc/server_config_repository_abc.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from bot_data.model.server_afk_channel_ids_config import ServerAFKChannelIdsConfig
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from bot_data.model.server_team_role_ids_config import ServerTeamRoleIdsConfig
|
||||
|
||||
|
||||
class ServerConfigRepositoryABC(ABC):
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def does_server_config_exists(self, server_id: int) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_server_config_by_server(self, server_id: int) -> ServerConfig:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_server_config_by_id(self, config_id: int) -> ServerConfig:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_server_config(self, server_config: ServerConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_server_config(self, server_config: ServerConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_server_config(self, server_config: ServerConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_server_team_role_id_config(self, server_team_role_id: ServerTeamRoleIdsConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_server_team_role_id_config(self, server_team_role_id: ServerTeamRoleIdsConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_server_team_role_id_config(self, server_team_role_id: ServerTeamRoleIdsConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_server_afk_channel_config(self, server_afk_channel: ServerAFKChannelIdsConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_server_afk_channel_config(self, server_afk_channel: ServerAFKChannelIdsConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_server_afk_channel_config(self, server_afk_channel: ServerAFKChannelIdsConfig):
|
||||
pass
|
@@ -1,44 +0,0 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Optional
|
||||
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_data.model.statistic import Statistic
|
||||
|
||||
|
||||
class StatisticRepositoryABC(ABC):
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_statistics(self) -> List[Statistic]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_statistics_by_server_id(self, server_id: int) -> List[Statistic]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_statistic_by_id(self, id: int) -> Statistic:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_statistic_by_name(self, name: str, server_id: int) -> Statistic:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def find_statistic_by_name(self, name: str, server_id: int) -> Optional[Statistic]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_statistic(self, statistic: Statistic):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_statistic(self, statistic: Statistic):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_statistic(self, statistic: Statistic):
|
||||
pass
|
15
kdb-bot/src/bot_data/abc/table_with_id_abc.py
Normal file
15
kdb-bot/src/bot_data/abc/table_with_id_abc.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from abc import abstractmethod
|
||||
|
||||
from cpl_core.database import TableABC
|
||||
|
||||
|
||||
class TableWithIdABC(TableABC):
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
self.__init__()
|
||||
|
||||
self._id = 0
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
return self._id
|
55
kdb-bot/src/bot_data/abc/technician_config_repository_abc.py
Normal file
55
kdb-bot/src/bot_data/abc/technician_config_repository_abc.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from bot_data.model.technician_config import TechnicianConfig
|
||||
from bot_data.model.technician_id_config import TechnicianIdConfig
|
||||
from bot_data.model.technician_ping_url_config import TechnicianPingUrlConfig
|
||||
|
||||
|
||||
class TechnicianConfigRepositoryABC(ABC):
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def does_technician_config_exists(self) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_technician_config(self) -> TechnicianConfig:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_technician_config(self, technician_config: TechnicianConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_technician_config(self, technician_config: TechnicianConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_technician_config(self, technician_config: TechnicianConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_technician_id_config(self, technician_id: TechnicianIdConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_technician_id_config(self, technician_id: TechnicianIdConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_technician_id_config(self, technician_id: TechnicianIdConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_technician_ping_url_config(self, technician_ping_url: TechnicianPingUrlConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_technician_ping_url_config(self, technician_ping_url: TechnicianPingUrlConfig):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_technician_ping_url_config(self, technician_ping_url: TechnicianPingUrlConfig):
|
||||
pass
|
47
kdb-bot/src/bot_data/abc/user_game_ident_repository_abc.py
Normal file
47
kdb-bot/src/bot_data/abc/user_game_ident_repository_abc.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_data.model.user_game_ident import UserGameIdent
|
||||
|
||||
|
||||
class UserGameIdentRepositoryABC(ABC):
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_game_idents(self) -> List[UserGameIdent]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_game_ident_by_id(self, id: int) -> UserGameIdent:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_game_ident_by_ident(self, ident: str) -> UserGameIdent:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def find_user_game_ident_by_ident(self, ident: str) -> UserGameIdent:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_game_idents_by_user_id(self, user_id: int) -> List[UserGameIdent]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_user_game_ident(self, user_game_ident: UserGameIdent):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_user_game_ident(self, user_game_ident: UserGameIdent):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_user_game_ident(self, user_game_ident: UserGameIdent):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_user_game_ident_by_user_id(self, user_id: int):
|
||||
pass
|
@@ -0,0 +1,52 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Optional
|
||||
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_data.model.user_joined_game_server import UserJoinedGameServer
|
||||
|
||||
|
||||
class UserJoinedGameServerRepositoryABC(ABC):
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_joined_game_servers(self) -> List[UserJoinedGameServer]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_joined_game_server_by_id(self, id: int) -> UserJoinedGameServer:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_joined_game_servers_by_user_id(self, user_id: int) -> List[UserJoinedGameServer]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_active_user_joined_game_server_by_user_id(self, user_id: int) -> UserJoinedGameServer:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def find_active_user_joined_game_server_by_user_id(self, user_id: int) -> Optional[UserJoinedGameServer]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def find_active_user_joined_game_servers_by_user_id(self, user_id: int) -> List[Optional[UserJoinedGameServer]]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_user_joined_game_server(self, user_joined_game_server: UserJoinedGameServer):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_user_joined_game_server(self, user_joined_game_server: UserJoinedGameServer):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_user_joined_game_server(self, user_joined_game_server: UserJoinedGameServer):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_user_joined_game_server_by_user_id(self, user_id: int):
|
||||
pass
|
@@ -2,6 +2,7 @@ from abc import ABC, abstractmethod
|
||||
from typing import Optional
|
||||
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_data.model.user_joined_server import UserJoinedServer
|
||||
|
||||
|
||||
@@ -18,6 +19,10 @@ class UserJoinedServerRepositoryABC(ABC):
|
||||
def get_user_joined_server_by_id(self, id: int) -> UserJoinedServer:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_joined_server_by_server_id(self, server_id: int) -> UserJoinedServer:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_joined_servers_by_user_id(self, user_id: int) -> list[UserJoinedServer]:
|
||||
pass
|
||||
|
@@ -27,6 +27,10 @@ class UserRepositoryABC(ABC):
|
||||
def get_users_by_discord_id(self, discord_id: int) -> List[User]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_users_by_server_id(self, server_id: int) -> List[User]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_by_discord_id_and_server_id(self, discord_id: int, server_id: int) -> User:
|
||||
pass
|
||||
|
35
kdb-bot/src/bot_data/abc/user_warnings_repository_abc.py
Normal file
35
kdb-bot/src/bot_data/abc/user_warnings_repository_abc.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_data.model.user_warnings import UserWarnings
|
||||
|
||||
|
||||
class UserWarningsRepositoryABC(ABC):
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_warnings(self) -> List[UserWarnings]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_warnings_by_id(self, id: int) -> UserWarnings:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_warnings_by_user_id(self, user_id: int) -> List[UserWarnings]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_user_warnings(self, user_warnings: UserWarnings):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_user_warnings(self, user_warnings: UserWarnings):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_user_warnings(self, user_warnings: UserWarnings):
|
||||
pass
|
@@ -2,9 +2,9 @@
|
||||
"ProjectSettings": {
|
||||
"Name": "bot-data",
|
||||
"Version": {
|
||||
"Major": "0",
|
||||
"Minor": "3",
|
||||
"Micro": "1"
|
||||
"Major": "1",
|
||||
"Minor": "0",
|
||||
"Micro": "7"
|
||||
},
|
||||
"Author": "Sven Heidemann",
|
||||
"AuthorEmail": "sven.heidemann@sh-edraft.de",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user