Compare commits

...

360 Commits

Author SHA1 Message Date
89ee16d1b5 Merge pull request '0.3' (#146) from 0.3 into master
Reviewed-on: sh-edraft.de/kd_discord_bot#146
Reviewed-by: edraft-dev <dev.sven.heidemann@sh-edraft.de>
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
2023-01-12 07:04:39 +01:00
4c577f6a7b Set config 2023-01-10 20:05:17 +01:00
f50a763539 Set docker 2023-01-10 20:05:03 +01:00
9ff9cc672e Improved docker stuff 2023-01-09 10:23:06 +01:00
9d4cf5a769 Set version for frontend 2023-01-09 08:31:31 +01:00
df1d62f569 Build version 0.3.0 2023-01-09 08:06:28 +01:00
4201510e9f Set version 0.3.0 2023-01-09 08:05:50 +01:00
394428a81a Updated config for build 2023-01-09 08:04:57 +01:00
4733f84ec6 Updated config for build 2023-01-09 08:04:45 +01:00
9c466733fb Reset config 2023-01-05 13:33:24 +01:00
bd62618fdf Build rc5 version 2023-01-04 17:20:26 +01:00
a78d5f0fcb Fixed #153 again 2023-01-04 17:19:36 +01:00
661630bb37 Build rc4 version 2023-01-04 17:07:53 +01:00
15f041a2da Set rc4 version 2023-01-04 17:07:30 +01:00
1ac5d982ed Fixed #152 2023-01-04 17:06:46 +01:00
1337ef35dd Fixed #153 2023-01-04 17:05:32 +01:00
986d7c4562 Merge remote-tracking branch 'origin/0.3' into 0.3 2023-01-04 17:03:33 +01:00
7fcb4084d2 Reactivated web api & set frontend version 2023-01-04 12:23:14 +01:00
fbac0d3d02 Reactivated web api & set frontend version 2023-01-04 12:21:31 +01:00
9626de2b27 Build new rc version 2023-01-04 12:14:39 +01:00
1d74f5e67c Set new rc version 2023-01-04 12:14:18 +01:00
6949db10f8 Merge pull request '/auto-role rule add failed (#151)' (#161) from #151 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#161
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #151
2023-01-04 12:09:14 +01:00
ba5d897662 Merge pull request 'Fixed autocompletes (#150)' (#160) from #150 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#160
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #150
2023-01-04 11:30:22 +01:00
47415af868 Merge pull request 'Fixed user autocompletes (#153)' (#159) from #153 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#159
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #153
2023-01-04 11:30:11 +01:00
6353c7ca86 Merge pull request 'Fixed user info command (#152)' (#158) from #152 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#158
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #152
2023-01-04 11:30:00 +01:00
440689653d Merge pull request 'Added logic to count moved users to mass move (#156)' (#157) from #156 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#157
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #156
2023-01-04 11:29:49 +01:00
844a818aa0 Fixed auto-role add #151 2022-12-30 13:05:49 +01:00
33fb973f21 Fixed autocompletes #150 2022-12-30 13:05:30 +01:00
7646335d03 Fixed autocompletes #150 2022-12-30 12:18:56 +01:00
04c905d287 Fixed user autocompletes #153 2022-12-30 11:45:41 +01:00
c7d8508173 Fixed user info command #152 2022-12-30 11:34:47 +01:00
f3eff97780 Added logic to count moved users to mass move #156 2022-12-30 11:26:29 +01:00
476db0ed33 Build rc2 2022-12-28 20:13:48 +01:00
9c369b911a Fixed user group 2022-12-28 20:10:20 +01:00
6dfd476bce Merge pull request 'Improved translations #64' (#149) from #64 into 0.3
closes #64
2022-12-28 19:48:49 +01:00
f669410b2a Improved translations #64 2022-12-28 19:45:50 +01:00
a46122243f Merge pull request 'Added logic to handle public and private messages #147' (#148) from #147 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#148
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #147
2022-12-28 18:59:47 +01:00
3b7345b404 Added logic to handle public and private messages #147 2022-12-27 19:02:59 +01:00
59d38f8f2a Merge pull request 'Build 0.3.0.rc1' (#145) from 0.3.0.rc1 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#145
Closes #145
2022-12-27 18:54:29 +01:00
612430d3e0 Fixed dockerfile for releases 2022-12-23 16:41:28 +01:00
e01290db9b Build 0.3.0.rc1 2022-12-23 16:12:35 +01:00
6273ce9cba Merge pull request 'Added user remove command #23' (#144) from #23 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#144
Reviewed-by: Sven Heidemann <sven.heidemann@sh-edraft.de>
Closes #23
2022-12-23 15:50:07 +01:00
5c923d8bd8 Merge branch '0.3' into #23 2022-12-23 15:48:46 +01:00
6c6169f7ee Merge pull request 'Added user set command #22' (#143) from #22 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#143
Reviewed-by: Sven Heidemann <sven.heidemann@sh-edraft.de>
Closes #22
2022-12-23 15:48:36 +01:00
ffd5105154 Removed error handling for database errors, replaced match-case-statements with if-else-statements and removed unused variables from the language file #23 2022-12-22 21:02:05 +01:00
9040ab6fca Improved error handling and changed attribute names from constants to variables which are located in the language file #23 2022-12-22 20:41:50 +01:00
9d89135b4c Added SQL command to delete all records by user id in "userjoinedvoicechannel"-table #23 2022-12-22 20:39:39 +01:00
71899346b2 Added translation for user remove command #23 2022-12-22 20:39:39 +01:00
d197a6e158 Added user remove command #23 2022-12-22 20:39:39 +01:00
40e53de3f2 Removed error handling for database errors and replaced match-case-statements with if-else-statements #22 2022-12-22 20:38:59 +01:00
1b9553e63b Improved error handling and changed attribute names from constants to variables which are located in the language file #22 2022-12-18 22:44:07 +01:00
5447d502cc Merge branch '0.3' into #22 2022-12-18 11:02:07 +01:00
5a4c2901f5 Fixed not checking level after new XP is assinged to user #22 2022-12-17 19:21:04 +01:00
bcf71a26f0 Fixed cpl query update 2022-12-17 16:17:14 +01:00
b25b75e382 Fixed frontend 2022-12-17 15:26:48 +01:00
f21b4f9881 Merge pull request 'Updated CPL to 2022.12.0 (#140)' (#141) from #140 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#141
Reviewed-by: Sven Heidemann <sven.heidemann@sh-edraft.de>
Closes #140
2022-12-12 08:13:14 +01:00
8705904882 Merge branch '0.3' into #140 2022-12-12 08:13:00 +01:00
cf610b770b Added translation for user set command 2022-12-11 21:19:08 +01:00
ec30069ff5 Added user set command 2022-12-11 21:18:51 +01:00
7026b3abac Merge pull request 'Added user get command #21' (#142) from #21 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#142
Reviewed-by: Sven Heidemann <sven.heidemann@sh-edraft.de>
Closes #21
2022-12-11 19:27:35 +01:00
31464df3f6 Fixed ontime rounding #21 2022-12-11 19:26:48 +01:00
eb9f5b83d5 Changed cpl-query to "2022.12.1.post1" in "kdb-bot/src/bot/bot.json" 2022-12-11 03:03:12 +01:00
fdd8357729 Added user get command #21 2022-12-11 00:22:34 +01:00
7c744f0e65 Updated CPL to 2022.12.0 #140 2022-12-04 18:38:58 +01:00
4a0f5c28c1 Merge pull request '0.3 - Bei message Member.name -> Member.mentions oder so (#100)' (#137) from #100 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#137
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #100
2022-11-22 18:16:38 +01:00
d2f99003ff Merge pull request '0.3 - Nachrichten sollen länger gezeigt werden (#135)' (#138) from #135 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#138
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #135
2022-11-22 18:16:21 +01:00
9dd3fd4b8e Updated configs #135 2022-11-21 20:35:55 +01:00
d18500b96c Changed .name -> .mention #100 2022-11-21 20:29:50 +01:00
91fdf34d32 Merge pull request 'Added mass-move command' (#136) from #20 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#136
Reviewed-by: Sven Heidemann <sven.heidemann@sh-edraft.de>
Closes #136
2022-11-21 19:00:34 +01:00
12369cdbe3 Removed unused code for mass-move #20 2022-11-21 18:20:23 +01:00
25c698273a Fixed sending message with translation pipe #20 2022-11-21 00:30:49 +01:00
2868b1afe2 Added messaging to mass-move #20 2022-11-20 23:27:22 +01:00
0d1c15b31d Added mass-move command #20 2022-11-20 19:18:17 +01:00
840da350e4 Merge pull request '0.3 - Login per Discord (#128)' (#129) from #128 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#129
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #128
2022-11-20 16:54:03 +01:00
bd94c42eae Added discord login & removed discord register #128 2022-11-20 16:09:20 +01:00
c7a925b997 Merge pull request 'Added presence command #18' (#126) from #18 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#126
Reviewed-by: Sven Heidemann <sven.heidemann@sh-edraft.de>
Closes #126
2022-11-20 15:41:26 +01:00
7fb6d22c3f Added requested changes to presence command #18 2022-11-20 15:39:34 +01:00
c5b5297058 Added presence command #18 2022-11-20 06:21:51 +01:00
9ed66c2560 Merge branch '0.3' of https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot into 0.3
 Conflicts:
	kdb-bot/src/modules/technician/command/log_command.py
2022-11-18 15:39:36 +01:00
6e6157ccf2 Fixed log command 2022-11-18 15:34:25 +01:00
f136d6164e Fixed log command 2022-11-18 15:05:39 +01:00
9b5033b80e Fixed some on member join stuff 2022-11-18 14:33:54 +01:00
f5a71a8450 Fixed some on member join stuff 2022-11-18 14:14:01 +01:00
d3279eb7c7 Updated config 2022-11-18 10:23:40 +01:00
ec7aeb8712 Added icmplib 2022-11-18 10:16:59 +01:00
fd609eb923 Merge remote-tracking branch 'origin/0.3' into 0.3
# Conflicts:
#	kdb-bot/cpl-workspace.json
2022-11-18 09:58:28 +01:00
a7dbc75d2e Updated configs 2022-11-18 09:58:05 +01:00
b0459567f4 Fixed workspace 2022-11-18 09:52:27 +01:00
25b7b18013 Fixed workspace 2022-11-18 09:51:06 +01:00
87350cba1a Moved dockerfile 2022-11-18 09:50:06 +01:00
864d181de0 Fixed project files 2022-11-18 09:33:50 +01:00
90011be760 Updated api config ? 2022-11-18 09:30:44 +01:00
47dd6fdc2d Improved build version stuff 2022-11-18 09:30:29 +01:00
8445c23e7f Merge pull request '0.3 - Log Befehl (#44)' (#125) from #44 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#125
Reviewed-by: Sven Heidemann <sven.heidemann@sh-edraft.de>
Closes #44
2022-11-17 23:03:33 +01:00
e6fc41090a Refactored code #44 2022-11-17 23:02:27 +01:00
7c79c6f992 Merge branch '0.3' into #44
# Conflicts:
#	kdb-bot/src/bot/config
2022-11-17 22:54:01 +01:00
7b8dca64bf Finished log command #44 2022-11-17 22:45:10 +01:00
549b05087f Merge pull request '0.3 - /user info für alle (#119)' (#122) from #119 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#122
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #119
2022-11-17 20:40:55 +01:00
83d18da58f Merge pull request '0.3 - level check for all members on seed (#123)' (#124) from #123 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#124
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #123
2022-11-17 20:40:37 +01:00
18e4465b17 Merge branch '0.3' into #123 2022-11-17 20:01:44 +01:00
2e20bb12de Merge branch '0.3' into #119 2022-11-17 20:01:31 +01:00
4f4e80fb6b Merge pull request '0.3 - Xp für Reaction (#118)' (#121) from #118 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#121
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #121
2022-11-17 20:01:12 +01:00
fd1245fb4f Merge remote-tracking branch 'origin/#118' into #118 2022-11-17 19:59:01 +01:00
fdb358c45e Removed xp when remove reaction #118 2022-11-17 19:58:51 +01:00
c438a91b87 Added logic to add xp on reaction #118 2022-11-17 19:58:51 +01:00
a46fbcd9fc Removed xp when remove reaction #118 2022-11-17 19:57:28 +01:00
91285540c6 Merge pull request '0.3 - /ping pings to urls (#117)' (#120) from #117 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#120
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #117
2022-11-17 19:54:17 +01:00
ab2145d5df Check level for each member after changes #123 2022-11-17 19:31:57 +01:00
63fe566044 Improved /user info command #119 2022-11-17 16:49:33 +01:00
d45d787cea Added logic to add xp on reaction #118 2022-11-17 16:35:47 +01:00
442170eca9 Added pings to servers to ping command #117 2022-11-17 16:16:28 +01:00
2c7f4647af [WIP] Added log command #44 2022-11-16 21:04:07 +01:00
53604706c2 Added technician module #44 2022-11-14 22:29:43 +01:00
42d8a16d05 Merge pull request '0.3 - Nachricht an Moderatoren, wenn Hilfe-Channel betreten wird (#113)' (#116) from #113 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#116
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #113
2022-11-14 21:56:40 +01:00
d933cae73c Merge branch '0.3' into #113 2022-11-14 21:56:24 +01:00
ce73145dbb Merge pull request '0.3 - Checks in Befehlen als Decorators (#114)' (#115) from #114 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#115
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #114
2022-11-14 21:49:59 +01:00
ab7fdec499 Merge branch '0.3' into #114 2022-11-14 21:49:42 +01:00
d2968e0652 Merge pull request '0.3 - Admins können keine anderen Benutzer zu Admin machen (#88)' (#112) from #88 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#112
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #88
2022-11-14 21:10:35 +01:00
cebdc1b860 Merge branch '0.3' into #88 2022-11-14 21:09:30 +01:00
87435614db Fixed angular setup for windoof and linux 2022-11-14 20:10:44 +01:00
e9386633d8 Merge branch '0.3' into #88 2022-11-13 22:20:51 +01:00
49d9509255 Added logic to send mods a message when member joins help channel #113 2022-11-13 12:32:31 +01:00
905182931c Improved event checks #114 2022-11-13 12:15:53 +01:00
026d989789 Improved event checks #114 2022-11-13 12:11:01 +01:00
d38fa77757 Added checks to commands #114 2022-11-13 12:07:50 +01:00
5cdf2834cc Added is ready check to events #114 2022-11-13 12:01:34 +01:00
7173dee28d Added event checks #114 2022-11-13 11:58:09 +01:00
e754a10241 Added command checks #114 2022-11-13 11:56:42 +01:00
theim
8fa6458d6e Added my configs 2022-11-12 15:16:06 +01:00
e269442603 Fixed bot project 2022-11-12 14:29:50 +01:00
d36a29042e Fixed copy paste error in feature flags 2022-11-12 12:15:45 +01:00
c09841a3da Merge branch '0.3' into #88 2022-11-11 22:02:39 +01:00
e098416a29 Merge pull request '0.3 - /level edit (#103)' (#108) from #103 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#108
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #103
2022-11-11 22:02:26 +01:00
9017535bfb Merge branch '0.3' into #88 2022-11-11 10:19:25 +01:00
b2087042bc Added error notification to level edit #103 2022-11-11 07:33:24 +01:00
8fafc94118 Merge branch '0.3' into #103 2022-11-11 07:28:21 +01:00
c608b232b0 Merge pull request '0.3 - Ontime in user info (#97)' (#107) from #97 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#107
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #97
2022-11-11 07:26:44 +01:00
6ff53fb31c Merge branch '0.3' into #97 2022-11-11 07:26:34 +01:00
be96644e5c Merge pull request '0.3 - AutoRole Emoji zu nachricht nach Anlegen einer Regel hinzufügen (#63)' (#110) from #63 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#110
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #63
2022-11-11 07:26:28 +01:00
2646dccb91 Merge branch '0.3' into #63 2022-11-11 07:25:52 +01:00
1a5917ac6b Merge pull request '0.3 - Nachricht bei shutdown und restart wird nicht geschickt vor neustart (#62)' (#111) from #62 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#111
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #62
2022-11-11 07:21:34 +01:00
588a8e140f Merge branch '0.3' into #62 2022-11-11 07:21:21 +01:00
c70149e9c8 Added is admin check to level edit #103 2022-11-10 21:10:48 +01:00
50fbc3eb8c Merge branch '0.3' into #103 2022-11-10 21:09:52 +01:00
b4fce51b57 Added is admin check to level create 2022-11-10 20:56:45 +01:00
3c1f017e3a Fixed admins cannot assign users to admins #88 2022-11-10 20:26:29 +01:00
25cc98732d Fixed restart after message #62 2022-11-10 20:02:53 +01:00
ef41ce03d3 Added functionality to auto-role rule add to add reaction to message #63 2022-11-10 19:50:42 +01:00
44f22e6aee Added level edit command #103 2022-11-10 16:33:04 +01:00
10a502fa4b Merge branch '#97' of https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot into #97 2022-11-10 08:23:46 +01:00
2a4933f971 Added ontime to user info #97 2022-11-10 08:23:40 +01:00
b30d49f5d7 Updated my laptop config 2022-11-10 08:20:49 +01:00
7eca399b9d Merge remote-tracking branch 'origin/0.3' into 0.3 2022-11-10 08:17:58 +01:00
766e9b1235 Changed edrafts secrets 2022-11-10 08:17:44 +01:00
26f0938566 Changed prod pws 2022-11-10 08:15:50 +01:00
97fab6adca Changed stage pws 2022-11-10 08:12:43 +01:00
97279c2599 Changed dev pws 2022-11-10 08:03:12 +01:00
8fe38c451e Moved docker related files 2022-11-10 07:54:31 +01:00
b0b228eef6 Moved docker related files 2022-11-10 07:54:20 +01:00
7bb407f2d7 Added configs 2022-11-10 07:47:43 +01:00
bf4468bfa6 Merge branch '0.3' of https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot into 0.3 2022-11-10 07:34:12 +01:00
762e85d062 Removed configs 2022-11-10 07:34:03 +01:00
36a8d14720 Merge branch '0.3' into #97 2022-11-10 07:12:32 +01:00
2613fcc999 Merge pull request '0.3 - received command in allen neuen Befehlen (#105)' (#106) from #105 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#106
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #105
2022-11-10 07:12:26 +01:00
356dc1848c Added ontime to user info #97 2022-11-09 22:34:25 +01:00
55c43efbdc Merge branch '0.3' into #105 2022-11-09 22:23:08 +01:00
e47318d8e9 Added received command to new commands #105 2022-11-09 22:21:32 +01:00
f551fdf87b Merge pull request '0.3 - auto-role list - möglicherweise nicht pro Server sondern allgemein (#93)' (#104) from #93 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#104
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #93
2022-11-09 22:06:32 +01:00
6f3877700e Fixed auto-role output by server #93 2022-11-09 21:40:04 +01:00
2483faef01 Merge pull request '0.3 - Statistiken (#46)' (#102) from #46 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#102
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #46
2022-11-09 20:55:05 +01:00
82365a24ba Fixed stats group #46 2022-11-09 20:52:58 +01:00
a29e33a3f9 Readded debug log to level seeder #26 2022-11-09 20:07:37 +01:00
273548411b Removed tests #26 2022-11-09 19:57:16 +01:00
a8f481ff4a Merge branch '#46' of https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot into #46
 Conflicts:
	kdb-bot/src/modules/level/level_seeder.py
2022-11-09 19:54:40 +01:00
7fe0f19adf Added db to stats #46 2022-11-09 19:53:10 +01:00
b52cdf0f34 Added stats repo #46 2022-11-09 19:53:10 +01:00
1c9c265ba8 Added stats table #46 2022-11-09 19:53:10 +01:00
b5080d8c04 Added stats migration #46 2022-11-09 19:53:10 +01:00
bf107f9a18 Added stats remove command #46 2022-11-09 19:53:10 +01:00
8cd67cd68c Added stats edit command #46 2022-11-09 19:53:10 +01:00
5c7db72723 Fixed level seeder #46 2022-11-09 19:53:10 +01:00
86433e841b Fixed typo #46 2022-11-09 19:51:46 +01:00
61b2432d0b Added logic to handle custom statistics #46 2022-11-09 19:51:46 +01:00
ddb9d0e647 Removed old code #46 2022-11-09 19:51:46 +01:00
a57c8da72a Added logic to call statistics #46 2022-11-09 19:51:46 +01:00
c6a5d49942 Added logic to call statistics #46 2022-11-09 19:51:46 +01:00
27ccdbd980 Merge pull request '0.3 - level set (#26)' (#101) from #26 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#101
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #26
2022-11-09 19:51:22 +01:00
a5ef2551e8 Improved error translation #26 2022-11-09 19:50:57 +01:00
c632ad51d4 Fixed stuff caused by merges #26 2022-11-09 19:33:45 +01:00
4f433c3840 Merge branch '#26' of https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot into #26 2022-11-09 19:26:47 +01:00
455c1e7023 Fixed translation #26 2022-11-09 19:26:41 +01:00
9ade299be7 Merge branch '0.3' into #26 2022-11-09 19:24:12 +01:00
09dcc8a9d3 Merge pull request '0.3 - level up (#27)' (#99) from #27 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#99
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #27
2022-11-09 19:24:01 +01:00
bd79831892 Added db to stats #46 2022-11-09 19:23:10 +01:00
c7967c6904 Added stats repo #46 2022-11-09 18:49:11 +01:00
a43676e9bf Added stats table #46 2022-11-09 18:36:48 +01:00
fa7e41469b Added stats migration #46 2022-11-09 18:22:27 +01:00
c9ce81701f Added stats remove command #46 2022-11-09 18:01:14 +01:00
c407c59c1a Added stats edit command #46 2022-11-09 17:59:55 +01:00
7e5706137e Fixed level seeder #46 2022-11-09 17:18:14 +01:00
144c1d7e79 Merge branch '0.3' into #27
# Conflicts:
#	kdb-bot/src/bot/translation/de.json
2022-11-09 10:16:06 +01:00
054266bfa0 Merge pull request '0.3 - level down (#28)' (#98) from #28 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#98
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #28
2022-11-09 10:03:21 +01:00
eaae058754 Fixed problems since merge #28 2022-11-09 08:51:08 +01:00
95a64732f3 Fixed typo #46 2022-11-08 22:06:36 +01:00
57d59e91ac Merge branch '0.3' into #28
# Conflicts:
#	kdb-bot/src/bot/translation/de.json
#	kdb-bot/src/modules/level/command/level_group.py
2022-11-08 22:04:14 +01:00
e3d3d200d6 Added logic to handle custom statistics #46 2022-11-08 21:54:33 +01:00
7da60e6f0a Merge pull request '0.3 - level remove Befehl (#91)' (#96) from #91 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#96
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #91
2022-11-08 21:47:46 +01:00
95e33109fe Removed old code #46 2022-11-08 20:36:31 +01:00
9e937f17b7 Fixed typo in translation... bruh #91 2022-11-08 20:33:55 +01:00
5dca2e5fed Added logic to call statistics #46 2022-11-08 20:28:44 +01:00
f24fd5e880 Added logic to call statistics #46 2022-11-08 20:28:38 +01:00
cfd96126df Merge branch '0.3' into #91 2022-11-08 18:59:41 +01:00
9099ebe4f3 Moved admin & moderator commands to base module 2022-11-08 18:59:24 +01:00
c666ceb51e Added level set command #26 2022-11-08 18:49:18 +01:00
e5eb50a3cb Fixed level seeder #26 2022-11-08 18:49:10 +01:00
f0f23163e4 Added level down command #27 2022-11-08 18:01:04 +01:00
faaadb0009 Fixed level seeder #28 2022-11-08 17:49:42 +01:00
fe32604a14 Added level down command #28 2022-11-08 17:49:32 +01:00
9b39d9baa5 Merge branch '#91' of https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot into #91 2022-11-08 09:36:41 +01:00
7f2cdc5b1c Added remove command #91 2022-11-08 09:36:15 +01:00
4ffbbd5b89 Merge pull request '0.3 - level create Befehl (#90)' (#95) from #90 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#95
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #90
2022-11-08 09:35:29 +01:00
898b24c8ee Changed color names #90 2022-11-08 08:02:35 +01:00
ccbe60b747 Merge branch '0.3' into #90 2022-11-07 22:33:26 +01:00
22456946b8 Merge pull request '0.3 - level list Befehl (#29)' (#94) from #29 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#94
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #29
2022-11-07 22:29:36 +01:00
e4fcc7931e Merge branch '0.3' into #91 2022-11-07 22:16:32 +01:00
e0af7421a1 Merge branch '0.3' into #90 2022-11-07 22:16:22 +01:00
c2ed8b9bc5 Merge branch '0.3' into #29 2022-11-07 22:16:01 +01:00
e27d2ae682 Merge pull request '0.3 - Levelsystem (#25)' (#92) from #25 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#92
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #25
2022-11-07 22:15:37 +01:00
b8fcaa48a5 Added remove command #91 2022-11-07 20:54:27 +01:00
6a18b15447 Fixed level stuff #90 2022-11-07 20:35:24 +01:00
b2397fcc2f Added create command #90 2022-11-07 20:35:12 +01:00
7ed30c40be Added list command #29 2022-11-07 19:04:41 +01:00
63000636a8 Updated version of level project #25 2022-11-06 22:46:15 +01:00
3d27295b14 Added translation to level service #25 2022-11-06 22:43:42 +01:00
1b587b049a Build files #25 2022-11-06 22:40:30 +01:00
dc90258a28 "Repaired" workspace file #25 2022-11-06 22:30:57 +01:00
23fde793db Fixed my config #25 2022-11-06 22:19:41 +01:00
6640d70440 Added logic to send message after level up #25 2022-11-06 22:17:27 +01:00
6e39154c75 Fixed level assignment #25 2022-11-06 21:54:21 +01:00
164671a07c Added logic to handle level by xp #25 2022-11-06 21:34:58 +01:00
8aee72856c Added level service #25 2022-11-06 19:51:50 +01:00
8118d4edc3 Improved logic to create roles for levels by default #25 2022-11-06 19:36:15 +01:00
861a847088 Improved logic to create roles for levels by default #25 2022-11-06 19:18:11 +01:00
666c527730 Added logic to handle default levels #25 2022-11-06 16:26:15 +01:00
e6e26b77f9 Added level repo #25 2022-11-06 14:46:11 +01:00
5a3eb57c0b Added level model #25 2022-11-06 14:35:28 +01:00
e1dbab3f4f Added level module and migration #25 2022-11-06 14:26:41 +01:00
3516a164da Merge pull request 'Added flask support #70 #75' (#71) from #70 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#71
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Reviewed-by: edraft-dev <dev.sven.heidemann@sh-edraft.de>
Closes #70 #72 #75 #83 #85 #86
2022-11-05 13:55:41 +01:00
e1304cc602 Added comment #70 2022-11-05 13:49:01 +01:00
88f00c6046 Fixed typing #70 2022-11-05 12:42:22 +01:00
09a6062992 Fixed typing #70 2022-11-05 12:40:21 +01:00
c92403f274 Removed unused deps #70 2022-11-05 12:39:49 +01:00
422c9bbb25 Fixed log level #70 2022-11-05 12:03:22 +01:00
e45d156e74 Changed config #70 2022-11-05 11:52:31 +01:00
8e32362333 Changed config #70 2022-11-05 11:51:58 +01:00
801d4bf16b Merge pull request 'Logging erweitern um IP-Adressen #70-4 (#85)' (#87) from #85 into #70
Reviewed-on: sh-edraft.de/kd_discord_bot#87
Closes #85
2022-10-25 21:24:27 +02:00
f7fd15b4bd Merge branch '#70' into #85 2022-10-25 21:24:11 +02:00
ac5271de6d Fixed update user #85 2022-10-25 21:15:40 +02:00
1f2087f50f Fixed update user #85 2022-10-25 21:11:55 +02:00
1c5b776efb Fixed change password autocomplete #70 2022-10-25 20:44:50 +02:00
368a00434b Fixed socket connect error #85 2022-10-25 20:27:59 +02:00
242af637f7 Improved api logging #85 2022-10-25 20:27:39 +02:00
6d8aa26883 Improved api logging #85 2022-10-25 20:19:05 +02:00
bf2a412dec Improved user confirmation #70 2022-10-25 08:31:08 +02:00
811e9991d0 Fixed user confirmation :/ #70 2022-10-25 08:07:15 +02:00
5cbd6ec00b Fixed user confirmation 2022-10-25 08:00:57 +02:00
b9c793ebb7 Merge pull request 'Set secured passwords #70-3' (#84) from #70-3 into #70
Reviewed-on: sh-edraft.de/kd_discord_bot#84
Closes #83
2022-10-25 07:50:58 +02:00
76c14a79ed Set secured passwords #70-3 2022-10-25 07:48:53 +02:00
877efe086b Fixed AuthUserTransformer #70 2022-10-25 07:41:13 +02:00
3b2ab6c8a0 Potentially fixed docker deployment #70 2022-10-23 22:41:18 +02:00
7c0f30ff95 Fixed nginx #70 2022-10-23 18:24:32 +02:00
8719452dad Fixed nginx #70 2022-10-23 18:24:13 +02:00
24a3a48478 Fixed socket service #70 2022-10-23 17:49:31 +02:00
ea026b351e Fixed docker dev env #70 2022-10-23 16:38:48 +02:00
109d3f28a2 Fixed revoke jwt #70 2022-10-23 16:35:24 +02:00
af5b9a2341 Improved dev stack #70 2022-10-23 15:37:40 +02:00
25a6758c40 Improved dev stack #70 2022-10-23 15:32:03 +02:00
a685ab9e06 Fixed docker cfg #70 2022-10-23 15:11:05 +02:00
7b8f42ad59 Added dev stack #70 2022-10-23 15:05:01 +02:00
a691808068 Fixed multiple send mails error #70 2022-10-23 14:37:42 +02:00
ecd648a9b2 Fixed confirmation id None on discord registration #70 2022-10-23 14:24:23 +02:00
f891587ce3 Improved docker support for deployment #70 2022-10-23 14:11:15 +02:00
ffe7b5e109 Repaired register by discord #70 2022-10-23 12:44:51 +02:00
602b1f3f98 Fixed docker env #70 2022-10-22 08:17:54 +02:00
17a14cedb6 Improved config #70 2022-10-22 07:37:47 +02:00
e31c5472af [WIP] Changed some stuff for docker #70 2022-10-21 23:01:09 +02:00
46ed616560 Added get version stuff to build docker #70 2022-10-21 19:25:17 +02:00
47f294a982 Improved set version for frontend #70 2022-10-21 13:50:11 +02:00
0fcf2c7b45 Set version correctly #70 2022-10-21 13:45:37 +02:00
fd2d30ee7f Added set version tool #70 2022-10-21 12:45:46 +02:00
e9b74140b5 Removed gitkeep #70 2022-10-20 21:19:24 +02:00
27442fe7c7 Merge pull request 'Bissl docker kram zum laufen gebracht #70-1_docker_and_build' (#76) from #70-1_docker_and_build into #70
Reviewed-on: sh-edraft.de/kd_discord_bot#76
2022-10-20 20:49:38 +02:00
b748435f98 Build tools project #70-1 2022-10-20 20:20:01 +02:00
d60baa0dce Added project information #70-1 2022-10-20 20:18:16 +02:00
48507962f8 Improved docker #70-1 2022-10-20 17:50:50 +02:00
7d4f3e9541 Added requirements.txt generator #70-1 2022-10-20 16:48:06 +02:00
3b9ef0048e Remove unnecessary configs #70-1 2022-10-20 16:32:05 +02:00
523e019aa0 Added post-build project #70-1 2022-10-20 15:46:08 +02:00
d0d053152d Improved docker compose #70-1 2022-10-20 15:45:52 +02:00
8231d20e3b Moved deps #70 2022-10-20 12:57:36 +02:00
f35dd0b15d Fixed auth user and user relation #70 2022-10-20 12:57:02 +02:00
d778bd2719 Added logic to register by discord #70 2022-10-20 09:47:23 +02:00
0c42c6554c Added logic to register by discord #70 2022-10-19 22:42:53 +02:00
fbc7b58780 Put send mail in thread #70 2022-10-19 18:42:20 +02:00
840193d5a8 Fixed send mails #70 2022-10-19 18:01:11 +02:00
4869039503 Fixed auto-role migration #70 2022-10-19 16:57:03 +02:00
d0ded956cb [WIP] Fixed forgot password #70 2022-10-18 21:00:23 +02:00
47a73a4298 Fixed password handling #70 2022-10-18 19:50:13 +02:00
a082b879ca Secured password handling #70 2022-10-18 18:33:03 +02:00
a51efa641d Improved auth views and imrpoved default settings handling #70 2022-10-18 18:04:53 +02:00
f553779797 Merge pull request '0.3-#70 - Im Web Interface Server auswählen - (#72)' (#73) from #72 into #70
Reviewed-on: sh-edraft.de/kd_discord_bot#73
Closes #72
2022-10-18 16:37:04 +02:00
dee8e4fe74 Fixed themes #72 2022-10-18 16:36:24 +02:00
7760ee5725 Update menu when server is selected #72 2022-10-18 16:23:40 +02:00
1055d5c2e1 Improved design of menu to handle servers #72 2022-10-18 13:44:13 +02:00
c094a3efae Improved get server logic #72 2022-10-18 12:41:42 +02:00
2a97438417 [WIP] Added server dashboard #72 2022-10-17 19:44:51 +02:00
a69c223a33 Added server list to dashboard #72 2022-10-17 18:12:43 +02:00
1baa8cee60 Added logic to get servers to dashboard #72 2022-10-17 16:50:09 +02:00
3d17bb7703 Added get filtered servers #72 2022-10-17 16:22:09 +02:00
d7a0706e0c Improved get server logic #72 2022-10-17 16:07:33 +02:00
dfcc516389 Added role check to authorization #72 2022-10-17 13:53:37 +02:00
1857473ccc Added logic to get discord servers #72 2022-10-17 12:19:50 +02:00
90bfee23b4 Added logic to load api after bot #70 2022-10-16 21:36:08 +02:00
f634ad552e Fixed settings dto #70 2022-10-16 21:29:58 +02:00
29fa35dffe Fixed update user #70 2022-10-16 21:16:04 +02:00
c5f371e0d5 Fixed update user #70 2022-10-16 21:10:20 +02:00
f319e89473 Fixed login state problems #70 2022-10-16 16:01:37 +02:00
d5ad5ded88 Fixed header styling #70 2022-10-16 14:49:46 +02:00
dbbd2b54c4 Fixed load menu #70 2022-10-16 13:09:26 +02:00
1a3126dfc5 Removed themeService from templates #70 2022-10-16 12:57:27 +02:00
ba881aefa8 Added verify-login #70 2022-10-16 12:06:18 +02:00
3fe8e1503c Added authorize check to controller #70 2022-10-16 10:11:21 +02:00
651482a1b9 Added api connection check #70 2022-10-16 01:55:37 +02:00
8c3cd1fae7 Added angular frontend #70 2022-10-16 00:13:03 +02:00
ee49bde961 Added waitress dep #70 2022-10-15 23:48:38 +02:00
2b08c1d71e Updated bot stuff #70 2022-10-15 23:38:38 +02:00
ead3f69a69 Moved bot to kdb-bot #70 2022-10-15 23:17:45 +02:00
029b46d7de Build #70 2022-10-15 17:34:16 +02:00
9da95f4dfb Fixed update user #70 2022-10-15 17:25:49 +02:00
8e56ff6a8e Set log level #70 2022-10-15 17:07:46 +02:00
21fcfaaa7f Fixed some random stuff #70 2022-10-15 17:07:22 +02:00
119f4e9d04 Improved api #70 2022-10-15 12:54:10 +02:00
5cd91d8341 Fixed error and dto handling #70 2022-10-15 09:32:41 +02:00
e0844a7f92 [WIP] Improved basics of api #70 2022-10-15 03:04:17 +02:00
6f95d0a055 Added auth service stuff with jwt #70 2022-10-15 00:42:55 +02:00
1090e502c2 [WIP] Added auth service stuff without jwt #70 2022-10-14 23:32:36 +02:00
1defe29406 Added auth user controller #70 2022-10-14 15:37:52 +02:00
126637306d [WIP] Added auth user service #70 2022-10-14 13:17:25 +02:00
2457107c63 Added auth user repository #70 2022-10-14 13:05:53 +02:00
411e44a681 [WIP] Added auth controller & updated pakages #70 2022-10-14 10:35:58 +02:00
91b054fdca Added auth service abc #70 2022-10-14 07:51:30 +02:00
e8c491a478 Made api async #70 2022-10-14 07:16:12 +02:00
aab3d62365 Added api settings #70 2022-10-14 07:04:56 +02:00
0927288bb5 Added api calls #70 2022-10-13 20:57:47 +02:00
0019f868ad Added flask support #70 2022-10-13 19:57:56 +02:00
d05dec3605 Updated my config 2022-10-13 16:34:04 +02:00
30dbce3f4b Merge pull request '0.3 - user-info zu /user info konvertieren #61' (#68) from Ebola-Chan/kd_discord_bot:#61 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#68
Reviewed-by: Sven Heidemann <sven.heidemann@sh-edraft.de>
Closes #61
2022-10-13 16:33:17 +02:00
56db9f42ad Merge pull request '0.3 - Techniker in PermissionService aufnehmen #60' (#69) from Ebola-Chan/kd_discord_bot:#60 into 0.3
Reviewed-on: sh-edraft.de/kd_discord_bot#69
Reviewed-by: Sven Heidemann <sven.heidemann@sh-edraft.de>
Closes #60
2022-10-13 16:32:44 +02:00
85f5717624 Addad technician to PermissionService #60 2022-10-12 21:27:55 +02:00
0c71e4934e Renamed user-info and added it to user group #61 2022-10-12 20:50:26 +02:00
481 changed files with 38614 additions and 1149 deletions

9
.gitmodules vendored Normal file
View File

@ -0,0 +1,9 @@
[submodule "kdb-bot/src/bot/config"]
path = kdb-bot/src/bot/config
url = https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot.config.git
[submodule "kdb-bot/src/bot_api/config"]
path = kdb-bot/src/bot_api/config
url = https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot.api.config.git
[submodule "kdb-bot/docker"]
path = kdb-bot/docker
url = https://git.sh-edraft.de/sh-edraft.de/kd_discord_bot.docker.git

View File

@ -1,26 +0,0 @@
{
"WorkspaceSettings": {
"DefaultProject": "bot",
"Projects": {
"bot": "src/bot/bot.json",
"bot-core": "src/bot_core/bot-core.json",
"bot-data": "src/bot_data/bot-data.json",
"admin": "src/modules/admin/admin.json",
"auto-role": "src/modules/auto_role/auto-role.json",
"base": "src/modules/base/base.json",
"boot-log": "src/modules/boot_log/boot-log.json",
"database": "src/modules/database/database.json",
"moderator": "src/modules/moderator/moderator.json",
"permission": "src/modules/permission/permission.json"
},
"Scripts": {
"prod": "export KDB_ENVIRONMENT=production; export KDB_NAME=KDB-Prod; cpl start;",
"stage": "export KDB_ENVIRONMENT=staging; export KDB_NAME=KDB-Stage; cpl start;",
"dev": "export KDB_ENVIRONMENT=development; export KDB_NAME=KDB-Dev; cpl start;",
"build-docker": "cpl b; docker-compose down; docker build -t kdb .",
"compose": "docker-compose up -d",
"docker": "cpl build-docker; cpl compose;"
}
}
}

View File

@ -1,64 +0,0 @@
version: "3.9"
volumes:
kdb_prod_1:
kdb_staging_1:
kdb_db_1:
kdb_db_2:
services:
kdb_prod_1:
image: kdb/kdb:0.2.1
container_name: kdb_prod_1
depends_on:
- kdb_db_1
volumes:
- kdb_prod_1:/app
environment:
KDB_ENVIRONMENT: "production"
KDB_TOKEN: ""
KDB_PREFIX: "!k "
restart: 'no'
kdb_staging_1:
image: kdb/kdb:0.2.1
container_name: kdb_staging_1
depends_on:
- kdb_db_1
volumes:
- kdb_staging_1:/app
environment:
KDB_ENVIRONMENT: "staging"
KDB_TOKEN: ""
KDB_PREFIX: "!kt "
restart: 'no'
kdb_db_1:
image: mysql:latest
container_name: kdb_db_1
command: mysqld --default-authentication-plugin=mysql_native_password
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: "kd_kdb"
MYSQL_USER: "kd_kdb"
MYSQL_PASSWORD: "kd_kdb"
MYSQL_DATABASE: "kd_kdb"
ports:
- "3307:3306"
volumes:
- kdb_db_1:/var/lib/mysql
kdb_db_2:
image: mysql:latest
container_name: kdb_db_2
command: mysqld --default-authentication-plugin=mysql_native_password
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: "kd_kdb"
MYSQL_USER: "kd_kdb"
MYSQL_PASSWORD: "kd_kdb"
MYSQL_DATABASE: "kd_kdb"
ports:
- "3308:3306"
volumes:
- kdb_db_2:/var/lib/mysql

View File

@ -1,18 +0,0 @@
# syntax=docker/dockerfile:1
FROM python:3.10.7-bullseye
WORKDIR /app
COPY ./dist/bot/build/ .
RUN pip install cpl-core --extra-index-url https://pip.sh-edraft.de
RUN pip install cpl-discord --extra-index-url https://pip.sh-edraft.de
RUN pip install cpl-query --extra-index-url https://pip.sh-edraft.de
RUN pip install cpl-translation --extra-index-url https://pip.sh-edraft.de
RUN apt-get update -y
RUN apt-get install nano -y
ENV KDB_TOKEN=""
ENV KDB_PREFIX="!kdb "
ENV KDB_ENVIRONMENT="production"
CMD [ "bash", "/app/bot/bot"]

9
kdb-bot/LICENSE Normal file
View File

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

2
kdb-bot/README.md Normal file
View File

@ -0,0 +1,2 @@
# kd_discord_bot

View File

@ -0,0 +1,46 @@
{
"WorkspaceSettings": {
"DefaultProject": "bot",
"Projects": {
"bot": "src/bot/bot.json",
"bot-api": "src/bot_api/bot-api.json",
"bot-core": "src/bot_core/bot-core.json",
"bot-data": "src/bot_data/bot-data.json",
"auto-role": "src/modules/auto_role/auto-role.json",
"base": "src/modules/base/base.json",
"boot-log": "src/modules/boot_log/boot-log.json",
"database": "src/modules/database/database.json",
"level": "src/modules/level/level.json",
"permission": "src/modules/permission/permission.json",
"stats": "src/modules/stats/stats.json",
"technician": "src/modules/technician/technician.json",
"get-version": "tools/get_version/get-version.json",
"post-build": "tools/post_build/post-build.json",
"set-version": "tools/set_version/set-version.json"
},
"Scripts": {
"sv": "cpl set-version $ARGS",
"set-version": "cpl run set-version $ARGS --dev; echo '';",
"gv": "cpl get-version",
"get-version": "export VERSION=$(cpl run get-version --dev); echo $VERSION;",
"pre-build": "cpl set-version $ARGS",
"post-build": "cpl run post-build --dev",
"pre-prod": "cpl build",
"prod": "export KDB_ENVIRONMENT=production; export KDB_NAME=KDB-Prod; cpl start;",
"pre-stage": "cpl build",
"stage": "export KDB_ENVIRONMENT=staging; export KDB_NAME=KDB-Stage; cpl start;",
"pre-dev": "cpl build",
"dev": "export KDB_ENVIRONMENT=development; export KDB_NAME=KDB-Dev; cpl start;",
"docker-build": "cpl build $ARGS; docker build -t kdb-bot/kdb-bot:$(cpl gv) .;",
"dc-up": "docker-compose up -d",
"dc-down": "docker-compose down",
"docker": "cpl dc-down; cpl docker-build; cpl dc-up;"
}
}
}

1
kdb-bot/docker Submodule

@ -0,0 +1 @@
Subproject commit 48c2683965611c9a96ebbb908f8dcb4d0d7d71f2

18
kdb-bot/dockerfile Normal file
View File

@ -0,0 +1,18 @@
# syntax=docker/dockerfile:1
FROM python:3.10.6-alpine
WORKDIR /app
COPY ./dist/bot/build/kdb-bot/ .
COPY ./dist/bot/build/requirements.txt .
RUN python -m pip install --upgrade pip
RUN apk update
RUN apk add --update alpine-sdk linux-headers
RUN apk add bash
RUN apk add nano
RUN pip install -r requirements.txt --extra-index-url https://pip.sh-edraft.de
RUN pip install flask[async]
CMD [ "bash", "/app/bot/bot"]

View File

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

View File

@ -7,6 +7,10 @@ from cpl_discord.configuration import DiscordBotSettings
from cpl_discord.service import DiscordBotServiceABC, DiscordBotService from cpl_discord.service import DiscordBotServiceABC, DiscordBotService
from cpl_translation import TranslatePipe, TranslationServiceABC, TranslationSettings from cpl_translation import TranslatePipe, TranslationServiceABC, TranslationSettings
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
class Application(DiscordBotApplicationABC): class Application(DiscordBotApplicationABC):
@ -14,6 +18,7 @@ class Application(DiscordBotApplicationABC):
DiscordBotApplicationABC.__init__(self, config, services) DiscordBotApplicationABC.__init__(self, config, services)
self._services = services self._services = services
self._config = config
# cpl-core # cpl-core
self._logger: LoggerABC = services.get_service(LoggerABC) self._logger: LoggerABC = services.get_service(LoggerABC)
@ -24,6 +29,12 @@ class Application(DiscordBotApplicationABC):
self._translation: TranslationServiceABC = services.get_service(TranslationServiceABC) self._translation: TranslationServiceABC = services.get_service(TranslationServiceABC)
self._t: TranslatePipe = services.get_service(TranslatePipe) self._t: TranslatePipe = services.get_service(TranslatePipe)
self._feature_flags: FeatureFlagsSettings = config.get_configuration(FeatureFlagsSettings)
# api
if self._feature_flags.get_flag(FeatureFlagsEnum.api_module):
self._api: ApiThread = services.get_service(ApiThread)
self._is_stopping = False self._is_stopping = False
async def configure(self): async def configure(self):
@ -32,6 +43,12 @@ class Application(DiscordBotApplicationABC):
async def main(self): async def main(self):
try: try:
self._logger.debug(__name__, f'Starting...') self._logger.debug(__name__, f'Starting...')
if self._feature_flags.get_flag(FeatureFlagsEnum.api_module) and self._feature_flags.get_flag(FeatureFlagsEnum.api_only) and self._environment.environment_name == 'development':
self._api.start()
self._api.join()
return
self._logger.trace(__name__, f'Try to start {DiscordBotService.__name__}') self._logger.trace(__name__, f'Try to start {DiscordBotService.__name__}')
await self._bot.start_async() await self._bot.start_async()
await self._bot.stop_async() await self._bot.stop_async()
@ -53,4 +70,4 @@ class Application(DiscordBotApplicationABC):
Console.write_line() Console.write_line()
def is_restart(self): 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 #

View File

@ -14,9 +14,6 @@ elif [[ $1 == "-stage" ]]; then
elif [[ $1 == "-prod" ]]; then elif [[ $1 == "-prod" ]]; then
export KDB_ENVIRONMENT=production export KDB_ENVIRONMENT=production
export KDB_NAME=KDB export KDB_NAME=KDB
else
export KDB_ENVIRONMENT=production
export KDB_NAME=KDB-prod
fi fi
export PYTHONPATH=./:$PYTHONPATH export PYTHONPATH=./:$PYTHONPATH

View File

@ -3,8 +3,8 @@
"Name": "bot", "Name": "bot",
"Version": { "Version": {
"Major": "0", "Major": "0",
"Minor": "2", "Minor": "3",
"Micro": "3" "Micro": "0"
}, },
"Author": "Sven Heidemann", "Author": "Sven Heidemann",
"AuthorEmail": "sven.heidemann@sh-edraft.de", "AuthorEmail": "sven.heidemann@sh-edraft.de",
@ -16,18 +16,25 @@
"LicenseName": "MIT", "LicenseName": "MIT",
"LicenseDescription": "MIT, see LICENSE for more details.", "LicenseDescription": "MIT, see LICENSE for more details.",
"Dependencies": [ "Dependencies": [
"cpl-core==2022.10.0.post6", "cpl-core==2022.12.0",
"cpl-translation==2022.10.0", "cpl-translation==2022.10.0.post2",
"cpl-query==2022.10.0", "cpl-query==2022.12.2",
"cpl-discord==2022.10.0.post5" "cpl-discord==2022.12.0",
"Flask==2.2.2",
"Flask-Classful==0.14.2",
"Flask-Cors==3.0.10",
"PyJWT==2.6.0",
"waitress==2.1.2",
"Flask-SocketIO==5.3.2",
"eventlet==0.33.2",
"requests-oauthlib==1.3.1",
"icmplib==3.0.3"
], ],
"DevDependencies": [ "DevDependencies": [
"cpl-cli==2022.10.0" "cpl-cli==2022.12.0"
], ],
"PythonVersion": ">=3.10.4", "PythonVersion": ">=3.10.4",
"PythonPath": { "PythonPath": {},
"linux": ""
},
"Classifiers": [] "Classifiers": []
}, },
"BuildSettings": { "BuildSettings": {
@ -45,16 +52,17 @@
], ],
"PackageData": {}, "PackageData": {},
"ProjectReferences": [ "ProjectReferences": [
"../bot_api/bot-api.json",
"../bot_core/bot-core.json", "../bot_core/bot-core.json",
"../bot_data/bot-data.json", "../bot_data/bot-data.json",
"../modules/base/base.json",
"../modules/admin/admin.json",
"../modules/auto_role/auto-role.json", "../modules/auto_role/auto-role.json",
"../modules/base/base.json", "../modules/base/base.json",
"../modules/boot_log/boot-log.json", "../modules/boot_log/boot-log.json",
"../modules/database/database.json", "../modules/database/database.json",
"../modules/moderator/moderator.json", "../modules/level/level.json",
"../modules/permission/permission.json" "../modules/permission/permission.json",
"../modules/stats/stats.json",
"../modules/technician/technician.json"
] ]
} }
} }

@ -0,0 +1 @@
Subproject commit e6faabbd8b9fe0dbd00533ea1647e7094ea8b19e

View File

@ -11,6 +11,8 @@ from bot.startup_discord_extension import StartupDiscordExtension
from bot.startup_migration_extension import StartupMigrationExtension from bot.startup_migration_extension import StartupMigrationExtension
from bot.startup_module_extension import StartupModuleExtension from bot.startup_module_extension import StartupModuleExtension
from bot.startup_settings_extension import StartupSettingsExtension 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.boot_log.boot_log_extension import BootLogExtension
from modules.database.database_extension import DatabaseExtension from modules.database.database_extension import DatabaseExtension
@ -29,6 +31,8 @@ class Program:
.use_extension(StartupMigrationExtension) \ .use_extension(StartupMigrationExtension) \
.use_extension(BootLogExtension) \ .use_extension(BootLogExtension) \
.use_extension(DatabaseExtension) \ .use_extension(DatabaseExtension) \
.use_extension(AppApiExtension) \
.use_extension(CoreExtension) \
.use_startup(Startup) .use_startup(Startup)
self.app: Application = await app_builder.build_async() self.app: Application = await app_builder.build_async()
await self.app.run_async() await self.app.run_async()

View File

@ -1,15 +1,17 @@
from cpl_query.extension import List from cpl_query.extension import List
from bot_api.api_module import ApiModule
from bot_core.core_extension.core_extension_module import CoreExtensionModule from bot_core.core_extension.core_extension_module import CoreExtensionModule
from bot_core.core_module import CoreModule from bot_core.core_module import CoreModule
from bot_data.data_module import DataModule from bot_data.data_module import DataModule
from modules.admin.admin_module import AdminModule
from modules.auto_role.auto_role_module import AutoRoleModule from modules.auto_role.auto_role_module import AutoRoleModule
from modules.base.base_module import BaseModule from modules.base.base_module import BaseModule
from modules.boot_log.boot_log_module import BootLogModule from modules.boot_log.boot_log_module import BootLogModule
from modules.database.database_module import DatabaseModule from modules.database.database_module import DatabaseModule
from modules.moderator.moderator_module import ModeratorModule from modules.level.level_module import LevelModule
from modules.permission.permission_module import PermissionModule from modules.permission.permission_module import PermissionModule
from modules.stats.stats_module import StatsModule
from modules.technician.technician_module import TechnicianModule
class ModuleList: class ModuleList:
@ -20,12 +22,14 @@ class ModuleList:
return List(type, [ return List(type, [
CoreModule, # has to be first! CoreModule, # has to be first!
DataModule, DataModule,
AdminModule, PermissionModule,
DatabaseModule,
AutoRoleModule, AutoRoleModule,
BaseModule, BaseModule,
DatabaseModule, LevelModule,
ModeratorModule, ApiModule,
PermissionModule, StatsModule,
TechnicianModule,
# has to be last! # has to be last!
BootLogModule, BootLogModule,
CoreExtensionModule, CoreExtensionModule,

View File

@ -9,6 +9,7 @@ from cpl_core.dependency_injection import ServiceProviderABC
from cpl_core.environment import ApplicationEnvironment from cpl_core.environment import ApplicationEnvironment
from cpl_core.logging import LoggerABC from cpl_core.logging import LoggerABC
from bot_api.logging.api_logger import ApiLogger
from bot_core.abc.custom_file_logger_abc import CustomFileLoggerABC from bot_core.abc.custom_file_logger_abc import CustomFileLoggerABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
@ -40,6 +41,9 @@ class Startup(StartupABC):
services.add_singleton(CustomFileLoggerABC, DatabaseLogger) services.add_singleton(CustomFileLoggerABC, DatabaseLogger)
services.add_singleton(CustomFileLoggerABC, MessageLogger) services.add_singleton(CustomFileLoggerABC, MessageLogger)
if self._feature_flags.get_flag(FeatureFlagsEnum.api_module):
services.add_singleton(CustomFileLoggerABC, ApiLogger)
services.add_translation() services.add_translation()
services.add_db_context(DBContext, self._config.get_configuration(DatabaseSettings)) services.add_db_context(DBContext, self._config.get_configuration(DatabaseSettings))

View File

@ -4,8 +4,12 @@ from cpl_core.dependency_injection import ServiceCollectionABC
from cpl_core.environment import ApplicationEnvironmentABC from cpl_core.environment import ApplicationEnvironmentABC
from bot_data.abc.migration_abc import MigrationABC from bot_data.abc.migration_abc import MigrationABC
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.auto_role_migration import AutoRoleMigration
from bot_data.migration.initial_migration import InitialMigration from bot_data.migration.initial_migration import InitialMigration
from bot_data.migration.level_migration import LevelMigration
from bot_data.migration.stats_migration import StatsMigration
from bot_data.service.migration_service import MigrationService from bot_data.service.migration_service import MigrationService
@ -21,3 +25,7 @@ class StartupMigrationExtension(StartupExtensionABC):
services.add_transient(MigrationService) services.add_transient(MigrationService)
services.add_transient(MigrationABC, InitialMigration) services.add_transient(MigrationABC, InitialMigration)
services.add_transient(MigrationABC, AutoRoleMigration) # 03.10.2022 #54 - 0.2.2 services.add_transient(MigrationABC, AutoRoleMigration) # 03.10.2022 #54 - 0.2.2
services.add_transient(MigrationABC, ApiMigration) # 15.10.2022 #70 - 0.3.0
services.add_transient(MigrationABC, LevelMigration) # 06.11.2022 #25 - 0.3.0
services.add_transient(MigrationABC, StatsMigration) # 09.11.2022 #46 - 0.3.0
services.add_transient(MigrationABC, AutoRoleFix1Migration) # 30.12.2022 #151 - 0.3.0

View File

@ -11,6 +11,7 @@ from bot_core.configuration.bot_logging_settings import BotLoggingSettings
from bot_core.configuration.bot_settings import BotSettings from bot_core.configuration.bot_settings import BotSettings
from modules.base.configuration.base_settings import BaseSettings from modules.base.configuration.base_settings import BaseSettings
from modules.boot_log.configuration.boot_log_settings import BootLogSettings 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 from modules.permission.configuration.permission_settings import PermissionSettings
@ -35,6 +36,7 @@ class StartupSettingsExtension(StartupExtensionABC):
self._configure_settings_with_sub_settings(configuration, BotSettings, lambda x: x.servers, lambda x: x.id) 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, 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, 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, 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) self._configure_settings_with_sub_settings(configuration, BotLoggingSettings, lambda x: x.files, lambda x: x.key)

View File

@ -6,7 +6,7 @@
"not_implemented_yet": "Ey Alter, das kann ich noch nicht...", "not_implemented_yet": "Ey Alter, das kann ich noch nicht...",
"presence": { "presence": {
"booting": "{} Ich fahre gerade hoch...", "booting": "{} Ich fahre gerade hoch...",
"running": "{} Behalte Ruhe und iss Kekse :D", "running": "{} Ich esse Kekse :D",
"restart": "{} Muss neue Kekse holen...", "restart": "{} Muss neue Kekse holen...",
"shutdown": "{} Ich werde bestimmt wieder kommen..." "shutdown": "{} Ich werde bestimmt wieder kommen..."
}, },
@ -45,14 +45,33 @@
"no_entry_point_error": "Fehler: Kein Eintrittspunkt!", "no_entry_point_error": "Fehler: Kein Eintrittspunkt!",
"extension_failed": "Fehler: Erweiterung ist fehlgeschlagen!", "extension_failed": "Fehler: Erweiterung ist fehlgeschlagen!",
"bot_not_ready_yet": "Ey Alter! Gedulde dich doch mal! ..." "bot_not_ready_yet": "Ey Alter! Gedulde dich doch mal! ..."
},
"colors": {
"blue": "Blau",
"dark_blue": "Dunkelblau",
"dark_gold": "Dunkelgold",
"dark_gray": "Dunkelgrau",
"dark_green": "Dunkelgrün",
"dark_grey": "Dunkelgrau",
"dark_magenta": "Dunkelmagenta",
"dark_orange": "Dunkelorange",
"dark_purple": "Dunkelviolett",
"dark_red": "Dunkelrot",
"dark_teal": "Dunkelblaugrün",
"default": "Standard",
"gold": "Gold",
"green": "Grün",
"greyple": "Graugrün",
"light_grey": "Hellgrau",
"magenta": "Magenta",
"orange": "Orange",
"purple": "Violett",
"red": "Rot",
"teal": "Blaugrün",
"yellow": "Gelb"
} }
}, },
"modules": { "modules": {
"admin": {
"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 :)",
"deploy_message": "Der neue Stand wurde hochgeladen."
},
"auto_role": { "auto_role": {
"list": { "list": {
"title": "Beobachtete Nachrichten:", "title": "Beobachtete Nachrichten:",
@ -89,7 +108,7 @@
"error": { "error": {
"not_found": "Regel für auto-role {} nicht gefunden!", "not_found": "Regel für auto-role {} nicht gefunden!",
"emoji_not_found": "Emoji {} für auto-role Regel {} nicht gefunden!", "emoji_not_found": "Emoji {} für auto-role Regel {} nicht gefunden!",
"rule_not_found": "Rolle {} 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!" "already_exists": "Regel für auto-role {} existiert bereits!"
} }
}, },
@ -108,16 +127,17 @@
"purge_message": "Na gut..., ich lösche alle Nachrichten wenns sein muss." "purge_message": "Na gut..., ich lösche alle Nachrichten wenns sein muss."
}, },
"base": { "base": {
"technician_error_message": "Es gab ein Fehler mit dem Event: {}\nDatum und Zeit: {}\nSchau bitte ins log für Details.UUID: {}", "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.UUID: {}", "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": "Hello There!\nIch heiße dich bei {} herzlichst Willkommen!",
"welcome_message_for_team": "{} hat gerade das Irrenhaus betreten.", "welcome_message_for_team": "{} hat gerade das Irrenhaus betreten.",
"goodbye_message": "Schade das du uns so schnell verlässt :(", "goodbye_message": "Schade, dass du uns so schnell verlässt :(",
"afk_command_channel_missing_message": "Zu unfähig einem Sprachkanal beizutreten?", "afk_command_channel_missing_message": "Zu unfähig einem Sprachkanal beizutreten?",
"afk_command_move_message": "Ich verschiebe dich ja schon... (◔_◔)", "afk_command_move_message": "Ich verschiebe dich ja schon... (◔_◔)",
"member_joined_help_voice_channel": "{} braucht hilfe, bitte kümmer dich drum :D",
"pong": "Pong", "pong": "Pong",
"info": { "info": {
"title": "Gismo", "title": "Krümmelmonster",
"description": "Informationen über mich", "description": "Informationen über mich",
"fields": { "fields": {
"version": "Version", "version": "Version",
@ -131,26 +151,154 @@
}, },
"footer": "" "footer": ""
}, },
"user_info": { "mass_move": {
"fields": { "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", "id": "Id",
"name": "Name", "name": "Name",
"discord_join": "Discord beigetreten am", "discord_join": "Discord beigetreten am",
"last_join": "Server beigetreten am", "last_join": "Server beigetreten am",
"xp": "XP", "xp": "XP",
"ontime": "Ontime",
"roles": "Rollen", "roles": "Rollen",
"joins": "Beitritte", "joins": "Beitritte",
"lefts": "Abgänge", "lefts": "Abgänge",
"warnings": "Verwarnungen" "warnings": "Verwarnungen"
}, },
"footer": "" "info": {
"footer": ""
},
"get": {
"xp": "{} hat {} xp",
"ontime": "{} war insgesamt {} Stunden aktiv in einem Sprachkanal"
},
"set": {
"xp": "{} hat nun {} xp",
"error": {
"value_type_not_numeric": "Der angegebende Wert ist keine Ganzzahl! :(",
"type_error": "Der angegebene Wert ist keine Zahl! :("
}
},
"remove": {
"xp": "Die {} von {} wurden entfernt",
"ontime": "Die {} von {} wurden entfernt"
},
"error": {
"atr_not_found": "Das Attribut {} konnte nicht gefunden werden :("
}
} }
}, },
"boot_log": { "boot_log": {
"login_message": "Ich bin on the line :D\nDer Scheiß hat {} Sekunden gedauert" "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 :("
},
"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 :("
}
},
"database": {}, "database": {},
"permission": { "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"
}
},
"technician": {
"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/{}"
}
} }
} }
} }

View File

@ -11,11 +11,11 @@ Discord bot for the Keksdose discord Server
""" """
__title__ = 'modules.admin' __title__ = 'bot_api'
__author__ = 'Sven Heidemann' __author__ = 'Sven Heidemann'
__license__ = 'MIT' __license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de' __copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.2.3' __version__ = '0.3.0'
from collections import namedtuple from collections import namedtuple
@ -23,4 +23,4 @@ from collections import namedtuple
# imports: # imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='3') version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.abc'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,92 @@
from abc import ABC, abstractmethod
from typing import Optional
from cpl_query.extension import List
from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria
from bot_api.model.auth_user_dto import AuthUserDTO
from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO
from bot_api.model.email_string_dto import EMailStringDTO
from bot_api.model.o_auth_dto import OAuthDTO
from bot_api.model.reset_password_dto import ResetPasswordDTO
from bot_api.model.token_dto import TokenDTO
from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO
from bot_data.model.auth_user import AuthUser
class AuthServiceABC(ABC):
@abstractmethod
def __init__(self): pass
@abstractmethod
def generate_token(self, user: AuthUser) -> str: pass
@abstractmethod
def decode_token(self, token: str) -> dict: pass
@abstractmethod
def get_decoded_token_from_request(self) -> dict: pass
@abstractmethod
def find_decoded_token_from_request(self) -> Optional[dict]: pass
@abstractmethod
async def get_all_auth_users_async(self) -> List[AuthUserDTO]: pass
@abstractmethod
async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO: pass
@abstractmethod
async def get_auth_user_by_email_async(self, email: str, with_password: bool = False) -> AuthUserDTO: pass
@abstractmethod
async def find_auth_user_by_email_async(self, email: str) -> AuthUserDTO: pass
@abstractmethod
async def add_auth_user_async(self, user_dto: AuthUserDTO): pass
@abstractmethod
async def add_auth_user_by_oauth_async(self, dto: OAuthDTO): pass
@abstractmethod
async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO, dc_id: int) -> OAuthDTO: pass
@abstractmethod
async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): pass
@abstractmethod
async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO): pass
@abstractmethod
async def delete_auth_user_by_email_async(self, email: str): pass
@abstractmethod
async def delete_auth_user_async(self, user_dto: AuthUserDTO): pass
@abstractmethod
async def verify_login(self, token_str: str) -> bool: pass
@abstractmethod
async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: pass
@abstractmethod
async def login_discord_async(self, oauth_dto: AuthUserDTO) -> TokenDTO: pass
@abstractmethod
async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO: pass
@abstractmethod
async def revoke_async(self, token_dto: TokenDTO): pass
@abstractmethod
async def confirm_email_async(self, id: str) -> bool: pass
@abstractmethod
async def forgot_password_async(self, email: str): pass
@abstractmethod
async def confirm_forgot_password_async(self, id: str) -> EMailStringDTO: pass
@abstractmethod
async def reset_password_async(self, rp_dto: ResetPasswordDTO): pass

View File

@ -0,0 +1,13 @@
from abc import ABC, abstractmethod
class DtoABC(ABC):
@abstractmethod
def __init__(self): pass
@abstractmethod
def from_dict(self, values: dict): pass
@abstractmethod
def to_dict(self) -> dict: pass

View File

@ -0,0 +1,17 @@
from abc import ABC, abstractmethod
class SelectCriteriaABC(ABC):
@abstractmethod
def __init__(
self,
page_index: int,
page_size: int,
sort_direction: str,
sort_column: str
):
self.page_index = page_index
self.page_size = page_size
self.sort_direction = sort_direction
self.sort_column = sort_column

View File

@ -0,0 +1,16 @@
from abc import abstractmethod
from cpl_core.database import TableABC
from bot_api.abc.dto_abc import DtoABC
class TransformerABC:
@staticmethod
@abstractmethod
def to_db(dto: DtoABC) -> TableABC: pass
@staticmethod
@abstractmethod
def to_dto(db: TableABC) -> DtoABC: pass

156
kdb-bot/src/bot_api/api.py Normal file
View File

@ -0,0 +1,156 @@
import re
import sys
import textwrap
import uuid
from functools import partial
from typing import Union
import eventlet
from cpl_core.dependency_injection import ServiceProviderABC
from cpl_core.utils import CredentialManager
from eventlet import wsgi
from flask import Flask, request, jsonify, Response
from flask_cors import CORS
from flask_socketio import SocketIO
from werkzeug.exceptions import NotFound
from bot_api.configuration.api_settings import ApiSettings
from bot_api.configuration.authentication_settings import AuthenticationSettings
from bot_api.configuration.frontend_settings import FrontendSettings
from bot_api.exception.service_error_code_enum import ServiceErrorCode
from bot_api.exception.service_exception import ServiceException
from bot_api.logging.api_logger import ApiLogger
from bot_api.model.error_dto import ErrorDTO
from bot_api.route.route import Route
class Api(Flask):
def __init__(
self,
logger: ApiLogger,
services: ServiceProviderABC,
api_settings: ApiSettings,
frontend_settings: FrontendSettings,
auth_settings: AuthenticationSettings,
*args, **kwargs
):
if not args:
kwargs.setdefault('import_name', __name__)
Flask.__init__(self, *args, **kwargs)
self._logger = logger
self._services = services
self._api_settings = api_settings
self._auth_settings = auth_settings
self._cors = CORS(self, support_credentials=True)
# register hooks
self.before_request(self.before_request_hook)
self.after_request(self.after_request_hook)
# register error handler
exc_class, code = self._get_exc_class_and_code(Exception)
self.register_error_handler(exc_class, self.handle_exception)
# websockets
self._socketio = SocketIO(self, cors_allowed_origins='*', path='/api/socket.io')
self._socketio.on_event('connect', self.on_connect)
self._socketio.on_event('disconnect', self.on_disconnect)
self._requests = {}
@staticmethod
def _get_methods_from_registered_route() -> Union[list[str], str]:
methods = ['Unknown']
if request.path in Route.registered_routes and len(Route.registered_routes[request.path]) >= 1 and 'methods' in Route.registered_routes[request.path][1]:
methods = Route.registered_routes[request.path][1]['methods']
if len(methods) == 1:
return methods[0]
return methods
def _register_routes(self):
for path, f in Route.registered_routes.items():
route = f[0]
kwargs = f[1]
cls = None
qual_name_split = route.__qualname__.split('.')
if len(qual_name_split) > 0:
cls_type = vars(sys.modules[route.__module__])[qual_name_split[0]]
cls = self._services.get_service(cls_type)
partial_f = partial(route, self if cls is None else cls)
partial_f.__name__ = route.__name__
self.route(path, **kwargs)(partial_f)
def handle_exception(self, e: Exception):
self._logger.error(__name__, f'Caught error', e)
if isinstance(e, ServiceException):
ex: ServiceException = e
self._logger.error(__name__, ex.get_detailed_message())
error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 500
elif isinstance(e, NotFound):
self._logger.error(__name__, e.description)
error = ErrorDTO(ServiceErrorCode.NotFound, e.description)
return jsonify(error.to_dict()), 404
else:
tracking_id = uuid.uuid4()
user_message = f'Tracking Id: {tracking_id}'
self._logger.error(__name__, user_message, e)
error = ErrorDTO(None, user_message)
return jsonify(error.to_dict()), 400
def before_request_hook(self):
request_id = uuid.uuid4()
self._requests[request] = request_id
method = request.access_control_request_method
self._logger.info(__name__, f'Received {request_id} @ {self._get_methods_from_registered_route() if method is None else method} {request.url} from {request.remote_addr}')
headers = str(request.headers).replace('\n', '\n\t\t')
data = request.get_data()
data = '' if len(data) == 0 else str(data.decode(encoding="utf-8"))
text = textwrap.dedent(f'Request: {request_id}:\n\tHeader:\n\t\t{headers}\n\tUser-Agent: {request.user_agent.string}\n\tBody: {data}')
self._logger.trace(__name__, text)
def after_request_hook(self, response: Response):
method = request.access_control_request_method
request_id = f'{self._get_methods_from_registered_route() if method is None else method} {request.url} from {request.remote_addr}'
if request in self._requests:
request_id = self._requests[request]
self._logger.info(__name__, f'Answered {request_id}')
headers = str(request.headers).replace('\n', '\n\t\t')
data = request.get_data()
data = '' if len(data) == 0 else str(data.decode(encoding="utf-8"))
text = textwrap.dedent(f'Request: {request_id}:\n\tHeader:\n\t\t{headers}\n\tResponse: {data}')
self._logger.trace(__name__, text)
return response
def start(self):
self._logger.info(__name__, f'Starting API {self._api_settings.host}:{self._api_settings.port}')
self._register_routes()
self.secret_key = CredentialManager.decrypt(self._auth_settings.secret_key)
# from waitress import serve
# https://docs.pylonsproject.org/projects/waitress/en/stable/arguments.html
# serve(self, host=self._apt_settings.host, port=self._apt_settings.port, threads=10, connection_limit=1000, channel_timeout=10)
wsgi.server(
eventlet.listen((self._api_settings.host, self._api_settings.port)),
self,
log_output=False
)
def on_connect(self):
self._logger.info(__name__, f'Client connected')
def on_disconnect(self):
self._logger.info(__name__, f'Client disconnected')

View File

@ -0,0 +1,52 @@
import os
from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceCollectionABC
from cpl_core.environment import ApplicationEnvironmentABC
from cpl_core.mailing import EMailClientABC, EMailClient
from cpl_discord.discord_event_types_enum import DiscordEventTypesEnum
from cpl_discord.service.discord_collection_abc import DiscordCollectionABC
from flask import Flask
from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_api.api import Api
from bot_api.api_thread import ApiThread
from bot_api.controller.auth_controller import AuthController
from bot_api.controller.auth_discord_controller import AuthDiscordController
from bot_api.controller.discord.server_controller import ServerController
from bot_api.controller.gui_controller import GuiController
from bot_api.event.bot_api_on_ready_event import BotApiOnReadyEvent
from bot_api.service.auth_service import AuthService
from bot_api.service.discord_service import DiscordService
from bot_core.abc.module_abc import ModuleABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
class ApiModule(ModuleABC):
def __init__(self, dc: DiscordCollectionABC):
ModuleABC.__init__(self, dc, FeatureFlagsEnum.api_module)
def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
cwd = env.working_directory
env.set_working_directory(os.path.dirname(os.path.realpath(__file__)))
config.add_json_file(f'config/apisettings.json', optional=False)
config.add_json_file(f'config/apisettings.{env.environment_name}.json', optional=True)
config.add_json_file(f'config/apisettings.{env.host_name}.json', optional=True)
env.set_working_directory(cwd)
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
services.add_singleton(EMailClientABC, EMailClient)
services.add_singleton(ApiThread)
services.add_singleton(Flask, Api)
services.add_transient(AuthServiceABC, AuthService)
services.add_transient(AuthController)
services.add_transient(AuthDiscordController)
services.add_transient(GuiController)
services.add_transient(DiscordService)
services.add_transient(ServerController)
# cpl-discord
self._dc.add_event(DiscordEventTypesEnum.on_ready.value, BotApiOnReadyEvent)

View File

@ -0,0 +1,24 @@
import threading
from bot_api.api import Api
from bot_api.logging.api_logger import ApiLogger
class ApiThread(threading.Thread):
def __init__(
self,
logger: ApiLogger,
api: Api
):
threading.Thread.__init__(self, daemon=True)
self._logger = logger
self._api = api
def run(self) -> None:
try:
self._logger.trace(__name__, f'Try to start {type(self._api).__name__}')
self._api.start()
except Exception as e:
self._logger.error(__name__, 'Start failed', e)

View File

@ -0,0 +1,26 @@
from cpl_core.application import ApplicationExtensionABC
from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceProviderABC
from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_api.configuration.authentication_settings import AuthenticationSettings
from bot_api.route.route import Route
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
class AppApiExtension(ApplicationExtensionABC):
def __init__(self):
ApplicationExtensionABC.__init__(self)
async def run(self, config: ConfigurationABC, services: ServiceProviderABC):
feature_flags: FeatureFlagsSettings = config.get_configuration(FeatureFlagsSettings)
if not feature_flags.get_flag(FeatureFlagsEnum.api_module):
return
auth_settings: AuthenticationSettings = config.get_configuration(AuthenticationSettings)
auth_users: AuthUserRepositoryABC = services.get_service(AuthUserRepositoryABC)
auth: AuthServiceABC = services.get_service(AuthServiceABC)
Route.init_authorize(auth_users, auth)

View File

@ -1,9 +1,9 @@
{ {
"ProjectSettings": { "ProjectSettings": {
"Name": "admin", "Name": "bot-api",
"Version": { "Version": {
"Major": "0", "Major": "0",
"Minor": "0", "Minor": "3",
"Micro": "0" "Micro": "0"
}, },
"Author": "", "Author": "",
@ -16,23 +16,21 @@
"LicenseName": "", "LicenseName": "",
"LicenseDescription": "", "LicenseDescription": "",
"Dependencies": [ "Dependencies": [
"cpl-core>=2022.10.0.post5" "cpl-core==2022.12.0"
], ],
"DevDependencies": [ "DevDependencies": [
"cpl-cli>=2022.10.0" "cpl-cli==2022.12.0"
], ],
"PythonVersion": ">=3.10.4", "PythonVersion": ">=3.10.4",
"PythonPath": { "PythonPath": {},
"linux": ""
},
"Classifiers": [] "Classifiers": []
}, },
"BuildSettings": { "BuildSettings": {
"ProjectType": "library", "ProjectType": "library",
"SourcePath": "", "SourcePath": "",
"OutputPath": "../../dist", "OutputPath": "../../dist",
"Main": "admin.main", "Main": "bot_api.main",
"EntryPoint": "admin", "EntryPoint": "bot-api",
"IncludePackageData": false, "IncludePackageData": false,
"Included": [], "Included": [],
"Excluded": [ "Excluded": [

@ -0,0 +1 @@
Subproject commit e6046881b562982008583afa973b39ff08b6a3c7

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.configuration'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,35 @@
import traceback
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.console import Console
class ApiSettings(ConfigurationModelABC):
def __init__(self):
ConfigurationModelABC.__init__(self)
self._port = 80
self._host = ''
self._redirect_to_https = False
@property
def port(self) -> int:
return self._port
@property
def host(self) -> str:
return self._host
@property
def redirect_to_https(self) -> bool:
return self._redirect_to_https
def from_dict(self, settings: dict):
try:
self._port = int(settings['Port'])
self._host = settings['Host']
self._redirect_to_https = bool(settings['RedirectToHTTPS'])
except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings')
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')

View File

@ -0,0 +1,48 @@
import traceback
from datetime import datetime
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.console import Console
class AuthenticationSettings(ConfigurationModelABC):
def __init__(self):
ConfigurationModelABC.__init__(self)
self._secret_key = ''
self._issuer = ''
self._audience = ''
self._token_expire_time = 0
self._refresh_token_expire_time = 0
@property
def secret_key(self) -> str:
return self._secret_key
@property
def issuer(self) -> str:
return self._issuer
@property
def audience(self) -> str:
return self._audience
@property
def token_expire_time(self) -> int:
return self._token_expire_time
@property
def refresh_token_expire_time(self) -> int:
return self._refresh_token_expire_time
def from_dict(self, settings: dict):
try:
self._secret_key = settings['SecretKey']
self._issuer = settings['Issuer']
self._audience = settings['Audience']
self._token_expire_time = int(settings['TokenExpireTime'])
self._refresh_token_expire_time = int(settings['RefreshTokenExpireTime'])
except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings')
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')

View File

@ -0,0 +1,48 @@
import traceback
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.console import Console
from cpl_query.extension import List
class DiscordAuthenticationSettings(ConfigurationModelABC):
def __init__(self):
ConfigurationModelABC.__init__(self)
self._client_secret = ''
self._redirect_url = ''
self._scope = List()
self._token_url = ''
self._auth_url = ''
@property
def client_secret(self) -> str:
return self._client_secret
@property
def redirect_url(self) -> str:
return self._redirect_url
@property
def scope(self) -> List[str]:
return self._scope
@property
def token_url(self) -> str:
return self._token_url
@property
def auth_url(self) -> str:
return self._auth_url
def from_dict(self, settings: dict):
try:
self._client_secret = settings['ClientSecret']
self._redirect_url = settings['RedirectURL']
self._scope = List(str, settings['Scope'])
self._token_url = settings['TokenURL']
self._auth_url = settings['AuthURL']
except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings')
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')

View File

@ -0,0 +1,23 @@
import traceback
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.console import Console
class FrontendSettings(ConfigurationModelABC):
def __init__(self):
ConfigurationModelABC.__init__(self)
self._url = ''
@property
def url(self) -> str:
return self._url
def from_dict(self, settings: dict):
try:
self._url = settings['URL']
except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings')
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')

View File

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

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.controller'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,155 @@
from cpl_core.configuration import ConfigurationABC
from cpl_core.environment import ApplicationEnvironmentABC
from cpl_core.mailing import EMailClientABC, EMailClientSettings
from cpl_translation import TranslatePipe
from flask import request, jsonify, Response
from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_api.api import Api
from bot_api.exception.service_error_code_enum import ServiceErrorCode
from bot_api.exception.service_exception import ServiceException
from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria
from bot_api.json_processor import JSONProcessor
from bot_api.logging.api_logger import ApiLogger
from bot_api.model.auth_user_dto import AuthUserDTO
from bot_api.model.reset_password_dto import ResetPasswordDTO
from bot_api.model.token_dto import TokenDTO
from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO
from bot_api.route.route import Route
from bot_data.model.auth_role_enum import AuthRoleEnum
class AuthController:
BasePath = '/api/auth'
def __init__(
self,
config: ConfigurationABC,
env: ApplicationEnvironmentABC,
logger: ApiLogger,
t: TranslatePipe,
api: Api,
mail_settings: EMailClientSettings,
mailer: EMailClientABC,
auth_service: AuthServiceABC
):
self._config = config
self._env = env
self._logger = logger
self._t = t
self._api = api
self._mail_settings = mail_settings
self._mailer = mailer
self._auth_service = auth_service
@Route.get(f'{BasePath}/users')
@Route.authorize(role=AuthRoleEnum.admin)
async def get_all_users(self) -> Response:
result = await self._auth_service.get_all_auth_users_async()
return jsonify(result.select(lambda x: x.to_dict()).to_list())
@Route.post(f'{BasePath}/users/get/filtered')
@Route.authorize(role=AuthRoleEnum.admin)
async def get_filtered_users(self) -> Response:
dto: AuthUserSelectCriteria = JSONProcessor.process(AuthUserSelectCriteria, request.get_json(force=True, silent=True))
result = await self._auth_service.get_filtered_auth_users_async(dto)
result.result = result.result.select(lambda x: x.to_dict()).to_list()
return jsonify(result.to_dict())
@Route.get(f'{BasePath}/users/get/<email>')
@Route.authorize
async def get_user_from_email(self, email: str) -> Response:
result = await self._auth_service.get_auth_user_by_email_async(email)
return jsonify(result.to_dict())
@Route.get(f'{BasePath}/users/find/<email>')
@Route.authorize
async def find_user_from_email(self, email: str) -> Response:
result = await self._auth_service.find_auth_user_by_email_async(email)
return jsonify(result.to_dict())
@Route.post(f'{BasePath}/register')
async def register(self):
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
await self._auth_service.add_auth_user_async(dto)
return '', 200
@Route.post(f'{BasePath}/register-by-id/<id>')
async def register_id(self, id: str):
result = await self._auth_service.confirm_email_async(id)
return jsonify(result)
@Route.post(f'{BasePath}/login')
async def login(self) -> Response:
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
result = await self._auth_service.login_async(dto)
return jsonify(result.to_dict())
@Route.get(f'{BasePath}/verify-login')
async def verify_login(self):
token = None
result = False
if 'Authorization' in request.headers:
bearer = request.headers.get('Authorization')
token = bearer.split()[1]
if token is not None:
result = self._auth_service.verify_login(token)
return jsonify(result)
@Route.post(f'{BasePath}/forgot-password/<email>')
async def forgot_password(self, email: str):
await self._auth_service.forgot_password_async(email)
return '', 200
@Route.post(f'{BasePath}/confirm-forgot-password/<id>')
async def confirm_forgot_password(self, id: str):
result = await self._auth_service.confirm_forgot_password_async(id)
return jsonify(result.to_dict())
@Route.post(f'{BasePath}/reset-password')
async def reset_password(self):
dto: ResetPasswordDTO = JSONProcessor.process(ResetPasswordDTO, request.get_json(force=True, silent=True))
await self._auth_service.reset_password_async(dto)
return '', 200
@Route.post(f'{BasePath}/update-user')
@Route.authorize
async def update_user(self):
dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True))
await self._auth_service.update_user_async(dto)
return '', 200
@Route.post(f'{BasePath}/update-user-as-admin')
@Route.authorize(role=AuthRoleEnum.admin)
async def update_user_as_admin(self):
dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True))
await self._auth_service.update_user_as_admin_async(dto)
return '', 200
@Route.post(f'{BasePath}/refresh')
@Route.authorize
async def refresh(self) -> Response:
dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True))
result = await self._auth_service.refresh_async(dto)
return jsonify(result.to_dict())
@Route.post(f'{BasePath}/revoke')
async def revoke(self):
dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True))
await self._auth_service.revoke_async(dto)
return '', 200
@Route.post(f'{BasePath}/delete-user')
@Route.authorize(role=AuthRoleEnum.admin)
async def delete_user(self):
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
await self._auth_service.delete_auth_user_async(dto)
return '', 200
@Route.post(f'{BasePath}/delete-user-by-mail/<email>')
@Route.authorize(role=AuthRoleEnum.admin)
async def delete_user_by_mail(self, email: str):
await self._auth_service.delete_auth_user_by_email_async(email)
return '', 200

View File

@ -0,0 +1,99 @@
import os
import uuid
from cpl_core.configuration import ConfigurationABC
from cpl_core.environment import ApplicationEnvironmentABC
from cpl_core.mailing import EMailClientABC, EMailClientSettings
from cpl_core.utils import CredentialManager
from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe
from flask import jsonify, Response
from flask import request, session
from requests_oauthlib import OAuth2Session
from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_api.api import Api
from bot_api.configuration.discord_authentication_settings import DiscordAuthenticationSettings
from bot_api.json_processor import JSONProcessor
from bot_api.logging.api_logger import ApiLogger
from bot_api.model.auth_user_dto import AuthUserDTO
from bot_api.model.o_auth_dto import OAuthDTO
from bot_api.route.route import Route
from bot_data.model.auth_role_enum import AuthRoleEnum
# Disable SSL requirement
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
class AuthDiscordController:
BasePath = '/api/auth/discord'
def __init__(
self,
auth_settings: DiscordAuthenticationSettings,
config: ConfigurationABC,
env: ApplicationEnvironmentABC,
logger: ApiLogger,
bot: DiscordBotServiceABC,
t: TranslatePipe,
api: Api,
mail_settings: EMailClientSettings,
mailer: EMailClientABC,
auth_service: AuthServiceABC
):
self._auth_settings = auth_settings
self._config = config
self._env = env
self._logger = logger
self._bot = bot
self._t = t
self._api = api
self._mail_settings = mail_settings
self._mailer = mailer
self._auth_service = auth_service
def _get_user_from_discord_response(self) -> dict:
discord = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, state=request.args.get('state'), scope=self._auth_settings.scope)
token = discord.fetch_token(
self._auth_settings.token_url,
client_secret=CredentialManager.decrypt(self._auth_settings.client_secret),
authorization_response=request.url,
)
discord = OAuth2Session(self._bot.user.id, token=token)
return discord.get('https://discordapp.com/api' + '/users/@me').json()
@Route.get(f'{BasePath}/get-url')
async def get_url(self):
oauth = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, scope=self._auth_settings.scope)
login_url, state = oauth.authorization_url(self._auth_settings.auth_url)
return jsonify({'loginUrl': login_url})
@Route.get(f'{BasePath}/create-user')
async def discord_create_user(self) -> Response:
response = self._get_user_from_discord_response()
result = await self._auth_service.add_auth_user_by_discord_async(AuthUserDTO(
0,
response['username'],
response['discriminator'],
response['email'],
str(uuid.uuid4()),
None,
AuthRoleEnum.normal
), response['id'])
return jsonify(result.to_dict())
@Route.get(f'{BasePath}/login')
async def discord_login(self) -> Response:
response = self._get_user_from_discord_response()
dto = AuthUserDTO(
0,
response['username'],
response['discriminator'],
response['email'],
str(uuid.uuid4()),
None,
AuthRoleEnum.normal
)
result = await self._auth_service.login_discord_async(dto)
return jsonify(result.to_dict())

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.controller.discord'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,65 @@
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())

View File

@ -0,0 +1,78 @@
import os
from cpl_core.configuration import ConfigurationABC
from cpl_core.environment import ApplicationEnvironmentABC
from cpl_core.mailing import EMail, EMailClientABC, EMailClientSettings
from cpl_translation import TranslatePipe
from flask import jsonify
from bot_api.api import Api
from bot_api.configuration.authentication_settings import AuthenticationSettings
from bot_api.logging.api_logger import ApiLogger
from bot_api.model.settings_dto import SettingsDTO
from bot_api.model.version_dto import VersionDTO
from bot_api.route.route import Route
class GuiController:
BasePath = f'/api/gui'
def __init__(
self,
config: ConfigurationABC,
env: ApplicationEnvironmentABC,
logger: ApiLogger,
t: TranslatePipe,
api: Api,
mail_settings: EMailClientSettings,
mailer: EMailClientABC,
auth_settings: AuthenticationSettings
):
self._config = config
self._env = env
self._logger = logger
self._t = t
self._api = api
self._mail_settings = mail_settings
self._mailer = mailer
self._auth_settings = auth_settings
@Route.get(f'{BasePath}/api-version')
async def api_version(self):
import bot_api
version = bot_api.version_info
return VersionDTO(version.major, version.minor, version.micro).to_dict()
@Route.get(f'{BasePath}/settings')
@Route.authorize
async def settings(self):
import bot_api
version = bot_api.version_info
return jsonify(SettingsDTO(
'',
VersionDTO(version.major, version.minor, version.micro),
os.path.abspath(os.path.join(self._env.working_directory, 'config')),
'/',
'/',
self._auth_settings.token_expire_time,
self._auth_settings.refresh_token_expire_time,
self._mail_settings.user_name,
self._mail_settings.port,
self._mail_settings.host,
self._mail_settings.user_name,
self._mail_settings.user_name,
).to_dict())
@Route.post(f'{BasePath}/send-test-mail/<email>')
@Route.authorize
async def send_test_mail(self, email: str):
mail = EMail()
mail.add_header('Mime-Version: 1.0')
mail.add_header('Content-Type: text/plain; charset=utf-8')
mail.add_header('Content-Transfer-Encoding: quoted-printable')
mail.add_receiver(email)
mail.subject = self._t.transform('api.api.test_mail.subject')
mail.body = self._t.transform('api.api.test_mail.message').format(self._env.host_name, self._env.environment_name)
self._mailer.send_mail(mail)
return '', 200

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.event'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,13 @@
from cpl_discord.events import OnReadyABC
from bot_api.api_thread import ApiThread
class BotApiOnReadyEvent(OnReadyABC):
def __init__(self, api: ApiThread):
OnReadyABC.__init__(self)
self._api = api
async def on_ready(self):
self._api.start()

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.exception'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,24 @@
from enum import Enum
from werkzeug.exceptions import Unauthorized
class ServiceErrorCode(Enum):
Unknown = 0
InvalidDependencies = 1
InvalidData = 2
NotFound = 3
DataAlreadyExists = 4
UnableToAdd = 5
UnableToDelete = 6
InvalidUser = 7
ConnectionFailed = 8
Timeout = 9
MailError = 10
Unauthorized = 11
Forbidden = 12

View File

@ -0,0 +1,13 @@
from bot_api.exception.service_error_code_enum import ServiceErrorCode
class ServiceException(Exception):
def __init__(self, error_code: ServiceErrorCode, message: str, *args):
Exception.__init__(self, *args)
self.error_code = error_code
self.message = message
def get_detailed_message(self) -> str:
return f'ServiceException - ErrorCode: {self.error_code} - ErrorMessage: {self.message}'

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.filter'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,23 @@
from bot_api.abc.select_criteria_abc import SelectCriteriaABC
class AuthUserSelectCriteria(SelectCriteriaABC):
def __init__(
self,
page_index: int,
page_size: int,
sort_direction: str,
sort_column: str,
first_name: str,
last_name: str,
email: str,
auth_role: int
):
SelectCriteriaABC.__init__(self, page_index, page_size, sort_direction, sort_column)
self.first_name = first_name
self.last_name = last_name
self.email = email
self.auth_role = auth_role

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.filter.discord'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,17 @@
from bot_api.abc.select_criteria_abc import SelectCriteriaABC
class ServerSelectCriteria(SelectCriteriaABC):
def __init__(
self,
page_index: int,
page_size: int,
sort_direction: str,
sort_column: str,
name: str,
):
SelectCriteriaABC.__init__(self, page_index, page_size, sort_direction, sort_column)
self.name = name

View File

@ -0,0 +1,43 @@
import enum
from inspect import signature, Parameter
from cpl_core.utils import String
class JSONProcessor:
@staticmethod
def process(_t: type, values: dict) -> object:
args = []
sig = signature(_t.__init__)
for param in sig.parameters.items():
parameter = param[1]
if parameter.name == 'self' or parameter.annotation == Parameter.empty:
continue
name = String.convert_to_camel_case(parameter.name)
name = name.replace('Dto', 'DTO')
name_first_lower = String.first_to_lower(name)
if name in values or name_first_lower in values:
value = ''
if name in values:
value = values[name]
else:
value = values[name_first_lower]
if isinstance(value, dict):
value = JSONProcessor.process(parameter.annotation, value)
if issubclass(parameter.annotation, enum.Enum):
value = parameter.annotation(value)
args.append(value)
elif parameter.default != Parameter.empty:
args.append(parameter.default)
else:
args.append(None)
return _t(*args)

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.logging'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,11 @@
from cpl_core.configuration import ConfigurationABC
from cpl_core.environment import ApplicationEnvironmentABC
from cpl_core.time import TimeFormatSettings
from bot_core.abc.custom_file_logger_abc import CustomFileLoggerABC
class ApiLogger(CustomFileLoggerABC):
def __init__(self, config: ConfigurationABC, time_format: TimeFormatSettings, env: ApplicationEnvironmentABC):
CustomFileLoggerABC.__init__(self, 'Api', config, time_format, env)

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.model'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,99 @@
from typing import Optional
from bot_api.abc.dto_abc import DtoABC
from bot_data.model.auth_role_enum import AuthRoleEnum
class AuthUserDTO(DtoABC):
def __init__(
self,
id: int = None,
first_name: str = None,
last_name: str = None,
email: str = None,
password: str = None,
confirmation_id: Optional[str] = None,
auth_role: AuthRoleEnum = None,
):
DtoABC.__init__(self)
self._id = id
self._first_name = first_name
self._last_name = last_name
self._email = email
self._password = password
self._is_confirmed = confirmation_id is None
self._auth_role = auth_role
@property
def id(self) -> int:
return self._id
@property
def first_name(self) -> str:
return self._first_name
@first_name.setter
def first_name(self, value: str):
self._first_name = value
@property
def last_name(self) -> str:
return self._last_name
@last_name.setter
def last_name(self, value: str):
self._last_name = value
@property
def email(self) -> str:
return self._email
@email.setter
def email(self, value: str):
self._email = value
@property
def password(self) -> str:
return self._password
@password.setter
def password(self, value: str):
self._password = value
@property
def is_confirmed(self) -> Optional[str]:
return self._is_confirmed
@is_confirmed.setter
def is_confirmed(self, value: Optional[str]):
self._is_confirmed = value
@property
def auth_role(self) -> AuthRoleEnum:
return self._auth_role
@auth_role.setter
def auth_role(self, value: AuthRoleEnum):
self._auth_role = value
def from_dict(self, values: dict):
self._id = values['id']
self._first_name = values['firstName']
self._last_name = values['lastName']
self._email = values['email']
self._password = values['password']
self._is_confirmed = values['isConfirmed']
self._auth_role = AuthRoleEnum(values['authRole'])
def to_dict(self) -> dict:
return {
'id': self._id,
'firstName': self._first_name,
'lastName': self._last_name,
'email': self._email,
'password': self._password,
'isConfirmed': self._is_confirmed,
'authRole': self._auth_role.value,
}

View File

@ -0,0 +1,21 @@
from cpl_query.extension import List
from bot_api.abc.dto_abc import DtoABC
from bot_data.filtered_result import FilteredResult
class AuthUserFilteredResultDTO(DtoABC, FilteredResult):
def __init__(self, result: List = None, total_count: int = 0):
DtoABC.__init__(self)
FilteredResult.__init__(self, result, total_count)
def from_dict(self, values: dict):
self._result = values['users']
self._total_count = values['totalCount']
def to_dict(self) -> dict:
return {
'users': self.result,
'totalCount': self.total_count
}

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.model.discord'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,58 @@
from typing import Optional
from bot_api.abc.dto_abc import DtoABC
class ServerDTO(DtoABC):
def __init__(
self,
server_id: int,
discord_id: int,
name: str,
member_count: int,
icon_url: Optional[str]
):
DtoABC.__init__(self)
self._server_id = server_id
self._discord_id = discord_id
self._name = name
self._member_count = member_count
self._icon_url = icon_url
@property
def server_id(self) -> int:
return self._server_id
@property
def discord_id(self) -> int:
return self._discord_id
@property
def name(self) -> str:
return self._name
@property
def member_count(self) -> int:
return self._member_count
@property
def icon_url(self) -> Optional[str]:
return self._icon_url
def from_dict(self, values: dict):
self._server_id = int(values['serverId'])
self._discord_id = int(values['discordId'])
self._name = values['name']
self._icon_url = values['iconURL']
def to_dict(self) -> dict:
return {
'serverId': self._server_id,
'discordId': self._discord_id,
'name': self._name,
'memberCount': self._member_count,
'iconURL': self._icon_url,
}

View File

@ -0,0 +1,21 @@
from cpl_query.extension import List
from bot_api.abc.dto_abc import DtoABC
from bot_data.filtered_result import FilteredResult
class ServerFilteredResultDTO(DtoABC, FilteredResult):
def __init__(self, result: List = None, total_count: int = 0):
DtoABC.__init__(self)
FilteredResult.__init__(self, result, total_count)
def from_dict(self, values: dict):
self._result = values['servers']
self._total_count = values['totalCount']
def to_dict(self) -> dict:
return {
'servers': self.result,
'totalCount': self.total_count
}

View File

@ -0,0 +1,21 @@
import traceback
from cpl_core.console import Console
from bot_api.abc.dto_abc import DtoABC
class EMailStringDTO(DtoABC):
def __init__(self, email: str):
DtoABC.__init__(self)
self._email = email
def from_dict(self, values: dict):
self._email = values['email']
def to_dict(self) -> dict:
return {
'email': self._email
}

View File

@ -0,0 +1,34 @@
import traceback
from typing import Optional
from cpl_core.console import Console
from bot_api.abc.dto_abc import DtoABC
from bot_api.exception.service_error_code_enum import ServiceErrorCode
class ErrorDTO(DtoABC):
def __init__(self, error_code: Optional[ServiceErrorCode], message: str):
DtoABC.__init__(self)
self._error_code = ServiceErrorCode.Unknown if error_code is None else error_code
self._message = message
@property
def error_code(self) -> ServiceErrorCode:
return self._error_code
@property
def message(self) -> str:
return self._message
def from_dict(self, values: dict):
self._error_code = values['ErrorCode']
self._message = values['Message']
def to_dict(self) -> dict:
return {
'errorCode': int(self._error_code.value),
'message': self._message
}

View File

@ -0,0 +1,44 @@
from typing import Optional
from bot_api.abc.dto_abc import DtoABC
from bot_api.model.auth_user_dto import AuthUserDTO
from bot_data.model.auth_role_enum import AuthRoleEnum
class OAuthDTO(DtoABC):
def __init__(
self,
user: AuthUserDTO,
o_auth_id: Optional[str],
):
DtoABC.__init__(self)
self._user = user
self._oauth_id = o_auth_id
@property
def user(self) -> AuthUserDTO:
return self._user
@user.setter
def user(self, value: AuthUserDTO):
self._user = value
@property
def oauth_id(self) -> Optional[str]:
return self._oauth_id
@oauth_id.setter
def oauth_id(self, value: Optional[str]):
self._oauth_id = value
def from_dict(self, values: dict):
self._user = AuthUserDTO().from_dict(values['user'])
self._oauth_id = values['oAuthId']
def to_dict(self) -> dict:
return {
'user': self._user.to_dict(),
'oAuthId': self._oauth_id
}

View File

@ -0,0 +1,32 @@
import traceback
from cpl_core.console import Console
from bot_api.abc.dto_abc import DtoABC
class ResetPasswordDTO(DtoABC):
def __init__(self, id: str, password: str):
DtoABC.__init__(self)
self._id = id
self._password = password
@property
def id(self) -> str:
return self._id
@property
def password(self) -> str:
return self._password
def from_dict(self, values: dict):
self._id = values['id']
self._password = values['password']
def to_dict(self) -> dict:
return {
'id': self._id,
'password': self._password
}

View File

@ -0,0 +1,67 @@
from bot_api.abc.dto_abc import DtoABC
from bot_api.model.version_dto import VersionDTO
class SettingsDTO(DtoABC):
def __init__(
self,
web_version: str,
api_version: VersionDTO,
config_path: str,
web_base_url: str,
api_base_url: str,
token_expire_time: int,
refresh_token_expire_time: int,
mail_user: str,
mail_port: int,
mail_host: str,
mail_transceiver: str,
mail_transceiver_address: str,
):
DtoABC.__init__(self)
self._web_version = web_version
self._api_version = api_version
self._config_path = config_path
self._web_base_url = web_base_url
self._api_base_url = api_base_url
self._token_expire_time = token_expire_time
self._refresh_token_expire_time = refresh_token_expire_time
self._mail_user = mail_user
self._mail_port = mail_port
self._mail_host = mail_host
self._mail_transceiver = mail_transceiver
self._mail_transceiver_address = mail_transceiver_address
def from_dict(self, values: dict):
self._web_version = values['webVersion']
self._api_version.from_dict(values['apiVersion'])
self._config_path = values['configPath']
self._web_base_url = values['webBaseURL']
self._api_base_url = values['apiBaseURL']
self._token_expire_time = values['tokenExpireTime']
self._refresh_token_expire_time = values['refreshTokenExpireTime']
self._mail_user = values['mailUser']
self._mail_port = values['mailPort']
self._mail_host = values['mailHost']
self._mail_transceiver = values['mailTransceiver']
self._mail_transceiver_address = values['mailTransceiverAddress']
def to_dict(self) -> dict:
return {
'webVersion': self._web_version,
'apiVersion': self._api_version.str,
'configPath': self._config_path,
'webBaseURL': self._web_base_url,
'apiBaseURL': self._api_base_url,
'tokenExpireTime': self._token_expire_time,
'refreshTokenExpireTime': self._refresh_token_expire_time,
'mailUser': self._mail_user,
'mailPort': self._mail_port,
'mailHost': self._mail_host,
'mailTransceiver': self._mail_transceiver,
'mailTransceiverAddress': self._mail_transceiver_address,
}

View File

@ -0,0 +1,32 @@
import traceback
from cpl_core.console import Console
from bot_api.abc.dto_abc import DtoABC
class TokenDTO(DtoABC):
def __init__(self, token: str, refresh_token: str):
DtoABC.__init__(self)
self._token = token
self._refresh_token = refresh_token
@property
def token(self) -> str:
return self._token
@property
def refresh_token(self) -> str:
return self._refresh_token
def from_dict(self, values: dict):
self._token = values['token']
self._refresh_token = values['refreshToken']
def to_dict(self) -> dict:
return {
'token': self._token,
'refreshToken': self._refresh_token
}

View File

@ -0,0 +1,45 @@
import traceback
from cpl_core.console import Console
from bot_api.abc.dto_abc import DtoABC
from bot_api.model.auth_user_dto import AuthUserDTO
class UpdateAuthUserDTO(DtoABC):
def __init__(
self,
auth_user_dto: AuthUserDTO,
new_auth_user_dto: AuthUserDTO,
change_password: bool = False
):
DtoABC.__init__(self)
self._auth_user = auth_user_dto
self._new_auth_user = new_auth_user_dto
self._change_password = change_password
@property
def auth_user(self) -> AuthUserDTO:
return self._auth_user
@property
def new_auth_user(self) -> AuthUserDTO:
return self._new_auth_user
@property
def change_password(self) -> bool:
return self._change_password
def from_dict(self, values: dict):
self._auth_user = AuthUserDTO().from_dict(values['authUser'])
self._new_auth_user = AuthUserDTO().from_dict(values['newAuthUser'])
self._change_password = False if 'changePassword' not in values else bool(values['changePassword'])
def to_dict(self) -> dict:
return {
'authUser': self._auth_user,
'newAuthUser': self._new_auth_user,
'changePassword': self._change_password
}

View File

@ -0,0 +1,43 @@
import traceback
from cpl_core.console import Console
from bot_api.abc.dto_abc import DtoABC
class VersionDTO(DtoABC):
def __init__(self, major: str = None, minor: str = None, micro: str = None):
DtoABC.__init__(self)
self._major = major
self._minor = minor
self._micro = micro
@property
def major(self) -> str:
return self._major
@property
def minor(self) -> str:
return self._minor
@property
def micro(self) -> str:
return self._micro
@property
def str(self) -> str:
return f'{self._major}.{self._minor}.{self._micro}'
def from_dict(self, values: dict):
self._major = values['major']
self._minor = values['minor']
self._micro = values['micro']
def to_dict(self) -> dict:
return {
'major': self._major,
'minor': self._minor,
'micro': self._micro,
}

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.route'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,103 @@
import functools
from functools import wraps
from typing import Optional, Callable
from flask import request, jsonify
from flask_cors import cross_origin
from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_api.exception.service_error_code_enum import ServiceErrorCode
from bot_api.exception.service_exception import ServiceException
from bot_api.model.error_dto import ErrorDTO
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
from bot_data.model.auth_role_enum import AuthRoleEnum
class Route:
registered_routes = {}
_auth_users: Optional[AuthUserRepositoryABC] = None
_auth: Optional[AuthServiceABC] = None
@classmethod
def init_authorize(cls, auth_users: AuthUserRepositoryABC, auth: AuthServiceABC):
cls._auth_users = auth_users
cls._auth = auth
@classmethod
def authorize(cls, f: Callable = None, role: AuthRoleEnum = None):
if f is None:
return functools.partial(cls.authorize, role=role)
@wraps(f)
async def decorator(*args, **kwargs):
token = None
if 'Authorization' in request.headers:
bearer = request.headers.get('Authorization')
token = bearer.split()[1]
if token is None:
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token not set')
error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 401
if cls._auth_users is None or cls._auth is None:
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Authorize is not initialized')
error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 401
if not cls._auth.verify_login(token):
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token expired')
error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 401
token = cls._auth.decode_token(token)
if token is None or 'email' not in token:
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token invalid')
error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 401
user = cls._auth_users.get_auth_user_by_email(token['email'])
if user is None:
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token invalid')
error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 401
if role is not None and user.auth_role.value < role.value:
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Role {role} required')
error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 403
return await f(*args, **kwargs)
return decorator
@classmethod
def route(cls, path=None, **kwargs):
# simple decorator for class based views
def inner(fn):
cross_origin(fn)
cls.registered_routes[path] = (fn, kwargs)
return fn
return inner
@classmethod
def get(cls, path=None, **kwargs):
return cls.route(path, methods=['GET'], **kwargs)
@classmethod
def post(cls, path=None, **kwargs):
return cls.route(path, methods=['POST'], **kwargs)
@classmethod
def head(cls, path=None, **kwargs):
return cls.route(path, methods=['HEAD'], **kwargs)
@classmethod
def put(cls, path=None, **kwargs):
return cls.route(path, methods=['PUT'], **kwargs)
@classmethod
def delete(cls, path=None, **kwargs):
return cls.route(path, methods=['DELETE'], **kwargs)

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.service'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,555 @@
import hashlib
import re
import textwrap
import uuid
from datetime import datetime, timedelta, timezone
from threading import Thread
from typing import Optional
import jwt
from cpl_core.database.context import DatabaseContextABC
from cpl_core.environment import ApplicationEnvironmentABC
from cpl_core.mailing import EMail, EMailClientABC
from cpl_core.utils import CredentialManager
from cpl_discord.service import DiscordBotServiceABC
from cpl_query.extension import List
from cpl_translation import TranslatePipe
from flask import request
from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_api.configuration.authentication_settings import AuthenticationSettings
from bot_api.configuration.frontend_settings import FrontendSettings
from bot_api.exception.service_error_code_enum import ServiceErrorCode
from bot_api.exception.service_exception import ServiceException
from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria
from bot_api.logging.api_logger import ApiLogger
from bot_api.model.auth_user_dto import AuthUserDTO
from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO
from bot_api.model.email_string_dto import EMailStringDTO
from bot_api.model.o_auth_dto import OAuthDTO
from bot_api.model.reset_password_dto import ResetPasswordDTO
from bot_api.model.token_dto import TokenDTO
from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO
from bot_api.transformer.auth_user_transformer import AuthUserTransformer as AUT
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.model.auth_role_enum import AuthRoleEnum
from bot_data.model.auth_user import AuthUser
from bot_data.model.auth_user_users_relation import AuthUserUsersRelation
_email_regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
class AuthService(AuthServiceABC):
def __init__(
self,
env: ApplicationEnvironmentABC,
logger: ApiLogger,
bot: DiscordBotServiceABC,
db: DatabaseContextABC,
auth_users: AuthUserRepositoryABC,
users: UserRepositoryABC,
servers: ServerRepositoryABC,
# mailer: MailThread,
mailer: EMailClientABC,
t: TranslatePipe,
auth_settings: AuthenticationSettings,
frontend_settings: FrontendSettings,
):
AuthServiceABC.__init__(self)
self._environment = env
self._logger = logger
self._bot = bot
self._db = db
self._auth_users = auth_users
self._users = users
self._servers = servers
self._mailer = mailer
self._t = t
self._auth_settings = auth_settings
self._frontend_settings = frontend_settings
@staticmethod
def _hash_sha256(password: str, salt: str) -> str:
return hashlib.sha256(f'{password}{salt}'.encode('utf-8')).hexdigest()
@staticmethod
def _is_email_valid(email: str) -> bool:
if re.fullmatch(_email_regex, email) is not None:
return True
return False
def generate_token(self, user: AuthUser) -> str:
token = jwt.encode(
payload={
'user_id': user.id,
'email': user.email,
'role': user.auth_role.value,
'exp': datetime.now(tz=timezone.utc) + timedelta(days=self._auth_settings.token_expire_time),
'iss': self._auth_settings.issuer,
'aud': self._auth_settings.audience
},
key=CredentialManager.decrypt(self._auth_settings.secret_key)
)
return token
def decode_token(self, token: str) -> dict:
return jwt.decode(
token,
key=CredentialManager.decrypt(self._auth_settings.secret_key),
issuer=self._auth_settings.issuer,
audience=self._auth_settings.audience,
algorithms=['HS256']
)
def get_decoded_token_from_request(self) -> dict:
token = None
if 'Authorization' in request.headers:
bearer = request.headers.get('Authorization')
token = bearer.split()[1]
if token is None:
raise ServiceException(ServiceErrorCode.Unauthorized, f'Token not set')
return jwt.decode(
token,
key=CredentialManager.decrypt(self._auth_settings.secret_key),
issuer=self._auth_settings.issuer,
audience=self._auth_settings.audience,
algorithms=['HS256']
)
def find_decoded_token_from_request(self) -> Optional[dict]:
token = None
if 'Authorization' in request.headers:
bearer = request.headers.get('Authorization')
token = bearer.split()[1]
return jwt.decode(
token,
key=CredentialManager.decrypt(self._auth_settings.secret_key),
issuer=self._auth_settings.issuer,
audience=self._auth_settings.audience,
algorithms=['HS256']
) if token is not None else None
def _create_and_save_refresh_token(self, user: AuthUser) -> str:
token = str(uuid.uuid4())
user.refresh_token = token
user.refresh_token_expire_time = datetime.now() + timedelta(days=self._auth_settings.refresh_token_expire_time)
self._auth_users.update_auth_user(user)
self._db.save_changes()
return token
def _send_link_mail(self, email: str, subject: str, message: str):
url = self._frontend_settings.url
if not url.endswith('/'):
url = f'{url}/'
self._mailer.connect()
mail = EMail()
mail.add_header('Mime-Version: 1.0')
mail.add_header('Content-Type: text/plain; charset=utf-8')
mail.add_header('Content-Transfer-Encoding: quoted-printable')
mail.add_receiver(str(email))
mail.subject = subject
mail.body = textwrap.dedent(f"""{message}
{self._t.transform('api.mail.automatic_mail').format(self._environment.application_name, self._environment.environment_name, self._environment.host_name)}
""")
thr = Thread(target=self._mailer.send_mail, args=[mail])
thr.start()
def _send_confirmation_id_to_user(self, user: AuthUser):
url = self._frontend_settings.url
if not url.endswith('/'):
url = f'{url}/'
self._send_link_mail(
user.email,
self._t.transform('api.auth.confirmation.subject').format(user.first_name, user.last_name),
self._t.transform('api.auth.confirmation.message').format(url, user.confirmation_id)
)
def _send_forgot_password_id_to_user(self, user: AuthUser):
url = self._frontend_settings.url
if not url.endswith('/'):
url = f'{url}/'
self._send_link_mail(
user.email,
self._t.transform('api.auth.forgot_password.subject').format(user.first_name, user.last_name),
self._t.transform('api.auth.forgot_password.message').format(url, user.forgot_password_id)
)
async def get_all_auth_users_async(self) -> List[AuthUserDTO]:
result = self._auth_users.get_all_auth_users() \
.select(lambda x: AUT.to_dto(x))
return List(AuthUserDTO, result)
async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO:
users = self._auth_users.get_filtered_auth_users(criteria)
result = users.result.select(lambda x: AUT.to_dto(x))
return AuthUserFilteredResultDTO(
List(AuthUserDTO, result),
users.total_count
)
async def get_auth_user_by_email_async(self, email: str, with_password: bool = False) -> AuthUserDTO:
try:
# todo: check if logged in user is admin then send mail
user = self._auth_users.get_auth_user_by_email(email)
return AUT.to_dto(user, password=user.password if with_password else None)
except Exception as e:
self._logger.error(__name__, f'AuthUser not found', e)
raise ServiceException(ServiceErrorCode.InvalidData, f'User not found {email}')
async def find_auth_user_by_email_async(self, email: str) -> Optional[AuthUser]:
user = self._auth_users.find_auth_user_by_email(email)
return AUT.to_dto(user) if user is not None else None
async def add_auth_user_async(self, user_dto: AuthUserDTO):
db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
if db_user is not None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists')
user = AUT.to_db(user_dto)
if self._auth_users.get_all_auth_users().count() == 0:
user.auth_role = AuthRoleEnum.admin
user.password_salt = uuid.uuid4()
user.password = self._hash_sha256(user_dto.password, user.password_salt)
if not self._is_email_valid(user.email):
raise ServiceException(ServiceErrorCode.InvalidData, 'Invalid E-Mail address')
try:
user.confirmation_id = uuid.uuid4()
self._auth_users.add_auth_user(user)
self._send_confirmation_id_to_user(user)
self._db.save_changes()
self._logger.info(__name__, f'Added auth user with E-Mail: {user_dto.email}')
except Exception as e:
self._logger.error(__name__, f'Cannot add user with E-Mail {user_dto.email}', e)
raise ServiceException(ServiceErrorCode.UnableToAdd, "Invalid E-Mail")
async def add_auth_user_by_oauth_async(self, dto: OAuthDTO):
db_user = self._auth_users.find_auth_user_by_email(dto.user.email)
if db_user is None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found')
if db_user.oauth_id != dto.oauth_id:
raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong OAuthId')
try:
db_user.first_name = dto.user.first_name
db_user.last_name = dto.user.last_name
db_user.password_salt = uuid.uuid4()
db_user.password = self._hash_sha256(dto.user.password, db_user.password_salt)
db_user.oauth_id = None
db_user.confirmation_id = uuid.uuid4()
self._send_confirmation_id_to_user(db_user)
self._auth_users.update_auth_user(db_user)
self._logger.info(__name__, f'Added auth user with E-Mail: {dto.user.email}')
except Exception as e:
self._logger.error(__name__, f'Cannot add user with E-Mail {dto.user.email}', e)
raise ServiceException(ServiceErrorCode.UnableToAdd, "Invalid E-Mail")
self._db.save_changes()
async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO, dc_id: int) -> OAuthDTO:
db_auth_user = self._auth_users.find_auth_user_by_email(user_dto.email)
# user exists
if db_auth_user is not None and db_auth_user.users.count() > 0:
# raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists')
self._logger.debug(__name__, f'Discord user already exists')
return OAuthDTO(AUT.to_dto(db_auth_user), None)
# user exists but discord user id not set
elif db_auth_user is not None and db_auth_user.users.count() == 0:
self._logger.debug(__name__, f'Auth user exists but not linked with discord')
# users = self._users.get_users_by_discord_id(user_dto.user_id)
# add auth_user to user refs
db_auth_user.oauth_id = None
else:
# user does not exists
self._logger.debug(__name__, f'Auth user does not exist')
try:
user_dto.user_id = self._users.get_users_by_discord_id(user_dto.user_id).single().user_id
except Exception as e:
self._logger.error(__name__, f'User not found')
user_dto.user_id = None
await self.add_auth_user_async(user_dto)
db_auth_user = self._auth_users.get_auth_user_by_email(user_dto.email)
db_auth_user.oauth_id = uuid.uuid4()
for g in self._bot.guilds:
member = g.get_member(int(dc_id))
if member is None:
continue
server = self._servers.get_server_by_discord_id(g.id)
users = self._users.get_users_by_discord_id(dc_id)
for user in users:
if user.server.server_id != server.server_id:
continue
self._auth_users.add_auth_user_user_rel(AuthUserUsersRelation(db_auth_user, user))
self._auth_users.update_auth_user(db_auth_user)
self._db.save_changes()
return OAuthDTO(AUT.to_dto(db_auth_user), db_auth_user.oauth_id)
async def update_user_async(self, update_user_dto: UpdateAuthUserDTO):
if update_user_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'User is empty')
if update_user_dto.auth_user is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'Existing user is empty')
if update_user_dto.new_auth_user is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'New user is empty')
if not self._is_email_valid(update_user_dto.auth_user.email) or not self._is_email_valid(update_user_dto.new_auth_user.email):
raise ServiceException(ServiceErrorCode.InvalidData, f'Invalid E-Mail')
user = self._auth_users.find_auth_user_by_email(update_user_dto.auth_user.email)
if user is None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found')
if user.confirmation_id is not None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'E-Mail not confirmed')
# update first name
if update_user_dto.new_auth_user.first_name is not None and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name:
user.first_name = update_user_dto.new_auth_user.first_name
# update last name
if update_user_dto.new_auth_user.last_name is not None and update_user_dto.new_auth_user.last_name != '' and \
update_user_dto.auth_user.last_name != update_user_dto.new_auth_user.last_name:
user.last_name = update_user_dto.new_auth_user.last_name
# update E-Mail
if update_user_dto.new_auth_user.email is not None and update_user_dto.new_auth_user.email != '' and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email:
user_by_new_e_mail = self._auth_users.find_auth_user_by_email(update_user_dto.new_auth_user.email)
if user_by_new_e_mail is not None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists')
user.email = update_user_dto.new_auth_user.email
update_user_dto.auth_user.password = self._hash_sha256(update_user_dto.auth_user.password, user.password_salt)
if update_user_dto.auth_user.password != user.password:
raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password')
# update password
if update_user_dto.new_auth_user.password is not None and self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) != user.password:
user.password_salt = uuid.uuid4()
user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt)
self._auth_users.update_auth_user(user)
self._db.save_changes()
async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO):
if update_user_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'User is empty')
if update_user_dto.auth_user is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'Existing user is empty')
if update_user_dto.new_auth_user is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'New user is empty')
if not self._is_email_valid(update_user_dto.auth_user.email) or not self._is_email_valid(update_user_dto.new_auth_user.email):
raise ServiceException(ServiceErrorCode.InvalidData, f'Invalid E-Mail')
user = self._auth_users.find_auth_user_by_email(update_user_dto.auth_user.email)
if user is None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found')
if user.confirmation_id is not None and update_user_dto.new_auth_user.is_confirmed:
user.confirmation_id = None
elif user.confirmation_id is None and not update_user_dto.new_auth_user.is_confirmed:
user.confirmation_id = uuid.uuid4()
# else
# raise ServiceException(ServiceErrorCode.InvalidUser, 'E-Mail not confirmed')
# update first name
if update_user_dto.new_auth_user.first_name is not None and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name:
user.first_name = update_user_dto.new_auth_user.first_name
# update last name
if update_user_dto.new_auth_user.last_name is not None and update_user_dto.new_auth_user.last_name != '' and update_user_dto.auth_user.last_name != update_user_dto.new_auth_user.last_name:
user.last_name = update_user_dto.new_auth_user.last_name
# update E-Mail
if update_user_dto.new_auth_user.email is not None and update_user_dto.new_auth_user.email != '' and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email:
user_by_new_e_mail = self._auth_users.find_auth_user_by_email(update_user_dto.new_auth_user.email)
if user_by_new_e_mail is not None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists')
user.email = update_user_dto.new_auth_user.email
# update password
if update_user_dto.new_auth_user.password is not None and update_user_dto.change_password and user.password != self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt):
user.password_salt = uuid.uuid4()
user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt)
# update role
if user.auth_role == update_user_dto.auth_user.auth_role and user.auth_role != update_user_dto.new_auth_user.auth_role:
user.auth_role = update_user_dto.new_auth_user.auth_role
self._auth_users.update_auth_user(user)
self._db.save_changes()
async def delete_auth_user_by_email_async(self, email: str):
try:
user = self._auth_users.get_auth_user_by_email(email)
self._auth_users.delete_auth_user(user)
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Cannot delete user', e)
raise ServiceException(ServiceErrorCode.UnableToDelete, f'Cannot delete user by mail {email}')
async def delete_auth_user_async(self, user_dto: AuthUser):
try:
self._auth_users.delete_auth_user(AUT.to_db(user_dto))
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Cannot delete user', e)
raise ServiceException(ServiceErrorCode.UnableToDelete, f'Cannot delete user by mail {user_dto.email}')
def verify_login(self, token_str: str) -> bool:
try:
token = self.decode_token(token_str)
if token is None or 'email' not in token:
raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid')
user = self._auth_users.find_auth_user_by_email(token['email'])
if user is None:
raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired')
except Exception as e:
self._logger.error(__name__, f'Token invalid', e)
return False
return True
async def login_async(self, user_dto: AuthUser) -> TokenDTO:
if user_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, 'User not set')
db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
if db_user is None:
raise ServiceException(ServiceErrorCode.InvalidUser, f'User not found')
user_dto.password = self._hash_sha256(user_dto.password, db_user.password_salt)
if db_user.password != user_dto.password:
raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password')
token = self.generate_token(db_user)
refresh_token = self._create_and_save_refresh_token(db_user)
if db_user.forgot_password_id is not None:
db_user.forgot_password_id = None
self._db.save_changes()
return TokenDTO(token, refresh_token)
async def login_discord_async(self, user_dto: AuthUserDTO) -> TokenDTO:
if user_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, 'User not set')
db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
if db_user is None:
await self.add_auth_user_async(user_dto)
# raise ServiceException(ServiceErrorCode.InvalidUser, f'User not found')
db_user = self._auth_users.get_auth_user_by_email(user_dto.email)
token = self.generate_token(db_user)
refresh_token = self._create_and_save_refresh_token(db_user)
if db_user.forgot_password_id is not None:
db_user.forgot_password_id = None
self._db.save_changes()
return TokenDTO(token, refresh_token)
async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO:
if token_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'Token not set')
try:
token = self.decode_token(token_dto.token)
if token is None or 'email' not in token:
raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid')
user = self._auth_users.get_auth_user_by_email(token['email'])
if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now():
raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired')
return TokenDTO(self.generate_token(user), self._create_and_save_refresh_token(user))
except Exception as e:
self._logger.error(__name__, f'Refreshing token failed', e)
return TokenDTO('', '')
async def revoke_async(self, token_dto: TokenDTO):
if token_dto is None or token_dto.token is None or token_dto.refresh_token is None:
raise ServiceException(ServiceErrorCode.InvalidData, 'Token not set')
try:
token = self.decode_token(token_dto.token)
user = self._auth_users.get_auth_user_by_email(token['email'])
if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now():
raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired')
user.refresh_token = None
self._auth_users.update_auth_user(user)
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Refreshing token failed', e)
async def confirm_email_async(self, id: str) -> bool:
user = self._auth_users.find_auth_user_by_confirmation_id(id)
if user is None:
return False
user.confirmation_id = None
self._auth_users.update_auth_user(user)
self._db.save_changes()
return True
async def forgot_password_async(self, email: str):
user = self._auth_users.find_auth_user_by_email(email)
if user is None:
return
user.forgot_password_id = uuid.uuid4()
self._auth_users.update_auth_user(user)
self._send_forgot_password_id_to_user(user)
self._db.save_changes()
async def confirm_forgot_password_async(self, id: str) -> EMailStringDTO:
user = self._auth_users.find_auth_user_by_forgot_password_id(id)
return EMailStringDTO(user.email)
async def reset_password_async(self, rp_dto: ResetPasswordDTO):
user = self._auth_users.find_auth_user_by_forgot_password_id(rp_dto.id)
if user is None:
raise ServiceException(ServiceErrorCode.InvalidUser, f'User by forgot password id {rp_dto.id} not found')
if user.confirmation_id is not None:
raise ServiceException(ServiceErrorCode.InvalidUser, f'E-Mail not confirmed')
if user.password is None or rp_dto.password == '':
raise ServiceException(ServiceErrorCode.InvalidData, f'Password not set')
user.password_salt = uuid.uuid4()
user.password = self._hash_sha256(rp_dto.password, user.password_salt)
user.forgot_password_id = None
self._auth_users.update_auth_user(user)
self._db.save_changes()

View File

@ -0,0 +1,105 @@
from typing import Optional
from cpl_discord.service import DiscordBotServiceABC
from cpl_query.extension import List
from flask import jsonify
from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_api.exception.service_error_code_enum import ServiceErrorCode
from bot_api.exception.service_exception import ServiceException
from bot_api.filter.discord.server_select_criteria import ServerSelectCriteria
from bot_api.model.discord.server_dto import ServerDTO
from bot_api.model.discord.server_filtered_result_dto import ServerFilteredResultDTO
from bot_api.model.error_dto import ErrorDTO
from bot_api.transformer.server_transformer import ServerTransformer
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.model.auth_role_enum import AuthRoleEnum
from bot_data.model.server import Server
class DiscordService:
def __init__(
self,
bot: DiscordBotServiceABC,
servers: ServerRepositoryABC,
auth: AuthServiceABC,
auth_users: AuthUserRepositoryABC,
users: UserRepositoryABC,
):
self._bot = bot
self._servers = servers
self._auth = auth
self._auth_users = auth_users
self._users = users
def _to_dto(self, x: Server) -> Optional[ServerDTO]:
guild = self._bot.get_guild(x.discord_server_id)
if guild is None:
return ServerTransformer.to_dto(
x,
'',
0,
None
)
return ServerTransformer.to_dto(
x,
guild.name,
guild.member_count,
guild.icon
)
async def get_all_servers(self) -> List[ServerDTO]:
servers = List(ServerDTO, self._servers.get_servers())
return servers.select(self._to_dto).where(lambda x: x.name != '')
async def get_all_servers_by_user(self) -> List[ServerDTO]:
token = self._auth.get_decoded_token_from_request()
if token is None or 'email' not in token or 'role' not in token:
raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid')
role = AuthRoleEnum(token['role'])
servers = self._servers.get_servers()
if role != AuthRoleEnum.admin:
auth_user = self._auth_users.find_auth_user_by_email(token['email'])
if auth_user is not None:
user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.server_id)
servers = servers.where(lambda x: x.server_id in user_ids)
servers = List(ServerDTO, servers)
return servers.select(self._to_dto).where(lambda x: x.name != '')
async def get_filtered_servers_async(self, criteria: ServerSelectCriteria) -> ServerFilteredResultDTO:
token = self._auth.get_decoded_token_from_request()
if token is None or 'email' not in token or 'role' not in token:
raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid')
role = AuthRoleEnum(token['role'])
filtered_result = self._servers.get_filtered_servers(criteria)
# filter out servers, where the user not exists
if role != AuthRoleEnum.admin:
auth_user = self._auth_users.find_auth_user_by_email(token['email'])
if auth_user is not None:
user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.server_id)
filtered_result.result = filtered_result.result.where(lambda x: x.server_id in user_ids)
servers: List = filtered_result.result.select(self._to_dto).where(lambda x: x.name != '')
result = List(ServerDTO, servers)
if criteria.name is not None and criteria.name != '':
result = result.where(lambda x: criteria.name.lower() in x.name.lower() or x.name.lower() == criteria.name.lower())
return ServerFilteredResultDTO(
List(ServerDTO, result),
servers.count()
)
async def get_server_by_id_async(self, id: int) -> ServerDTO:
server = self._servers.get_server_by_id(id)
guild = self._bot.get_guild(server.discord_server_id)
server_dto = ServerTransformer.to_dto(server, guild.name, guild.member_count, guild.icon)
return server_dto

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'bot_api.transformer'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,38 @@
from datetime import datetime, timezone
from bot_api.abc.transformer_abc import TransformerABC
from bot_api.model.auth_user_dto import AuthUserDTO
from bot_data.model.auth_role_enum import AuthRoleEnum
from bot_data.model.auth_user import AuthUser
class AuthUserTransformer(TransformerABC):
@staticmethod
def to_db(dto: AuthUserDTO) -> AuthUser:
return AuthUser(
dto.first_name,
dto.last_name,
dto.email,
dto.password,
None,
None,
None,
None,
None,
datetime.now(),
AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role),
auth_user_id=0 if dto.id is None else dto.id
)
@staticmethod
def to_dto(db: AuthUser, password: str = None) -> AuthUserDTO:
return AuthUserDTO(
db.id,
db.first_name,
db.last_name,
db.email,
'' if password is None else password,
db.confirmation_id,
db.auth_role
)

View File

@ -0,0 +1,24 @@
from typing import Optional
import discord
from bot_api.abc.transformer_abc import TransformerABC
from bot_api.model.discord.server_dto import ServerDTO
from bot_data.model.server import Server
class ServerTransformer(TransformerABC):
@staticmethod
def to_db(dto: ServerDTO) -> Server:
return Server(dto.discord_id)
@staticmethod
def to_dto(db: Server, name: str, member_count: int, icon_url: Optional[discord.Asset]) -> ServerDTO:
return ServerDTO(
db.server_id,
db.discord_server_id,
name,
member_count,
icon_url.url if icon_url is not None else None,
)

View File

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

View File

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

View File

@ -1,5 +1,7 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Callable
from cpl_query.extension import List
from discord.ext.commands import Context from discord.ext.commands import Context
@ -14,11 +16,20 @@ class ClientUtilsServiceABC(ABC):
@abstractmethod @abstractmethod
def moved_user(self, guild_id: int): pass def moved_user(self, guild_id: int): pass
@abstractmethod
def moved_users(self, guild_id: int, count: int): pass
@abstractmethod @abstractmethod
def get_client(self, dc_ic: int, guild_id: int): pass def get_client(self, dc_ic: int, guild_id: int): pass
@abstractmethod
async def check_if_bot_is_ready_yet(self) -> bool: pass
@abstractmethod @abstractmethod
async def check_if_bot_is_ready_yet_and_respond(self, ctx: Context) -> bool: pass async def check_if_bot_is_ready_yet_and_respond(self, ctx: Context) -> bool: pass
@abstractmethod @abstractmethod
async def presence_game(self, t_key: str): pass async def presence_game(self, t_key: str): pass
@abstractmethod
def get_auto_complete_list(self, _l: List, current: str, select: Callable = None) -> List: pass

View File

@ -13,10 +13,14 @@ class CustomFileLoggerABC(Logger, ABC):
@abstractmethod @abstractmethod
def __init__(self, key: str, config: ConfigurationABC, time_format: TimeFormatSettings, env: ApplicationEnvironmentABC): def __init__(self, key: str, config: ConfigurationABC, time_format: TimeFormatSettings, env: ApplicationEnvironmentABC):
self._key = key self._key = key
settings: LoggingSettings = config.get_configuration(f'{FileLoggingSettings.__name__}_{key}') self._settings: LoggingSettings = config.get_configuration(f'{FileLoggingSettings.__name__}_{key}')
Logger.__init__(self, settings, time_format, env) Logger.__init__(self, self._settings, time_format, env)
self._begin_log() self._begin_log()
@property
def settings(self) -> LoggingSettings:
return self._settings
def _begin_log(self): def _begin_log(self):
console_level = self._console.value console_level = self._console.value
self._console = LoggingLevelEnum.OFF self._console = LoggingLevelEnum.OFF

View File

@ -3,6 +3,7 @@ from typing import Union
import discord import discord
from cpl_query.extension import List from cpl_query.extension import List
from discord import Interaction
from discord.ext.commands import Context from discord.ext.commands import Context
@ -10,18 +11,21 @@ class MessageServiceABC(ABC):
@abstractmethod @abstractmethod
def __init__(self): pass def __init__(self): pass
@abstractmethod @abstractmethod
async def delete_messages(self, messages: List[discord.Message], guild_id: int, without_tracking=False): pass async def delete_messages(self, messages: List[discord.Message], guild_id: int, without_tracking=False): pass
@abstractmethod @abstractmethod
async def delete_message(self, message: discord.Message, without_tracking=False): pass async def delete_message(self, message: discord.Message, without_tracking=False): pass
@abstractmethod @abstractmethod
async def send_channel_message(self, channel: discord.TextChannel, message: Union[str, discord.Embed], without_tracking=True): pass async def send_channel_message(self, channel: discord.TextChannel, message: Union[str, discord.Embed], without_tracking=True): pass
@abstractmethod @abstractmethod
async def send_dm_message(self, message: Union[str, discord.Embed], receiver: Union[discord.User, discord.Member], without_tracking=False): pass async def send_dm_message(self, message: Union[str, discord.Embed], receiver: Union[discord.User, discord.Member], without_tracking=False): pass
@abstractmethod @abstractmethod
async def send_ctx_msg(self, ctx: Context, message: Union[str, discord.Embed], file: discord.File = None, is_persistent: bool = False, wait_before_delete: int = None, without_tracking=True): pass async def send_ctx_msg(self, ctx: Context, message: Union[str, discord.Embed], file: discord.File = None, is_persistent: bool = False, is_public: bool = False, wait_before_delete: int = None, without_tracking=True): pass
@abstractmethod
async def send_interaction_msg(self, interaction: Interaction, message: Union[str, discord.Embed], is_persistent: bool = False, is_public: bool = False, wait_before_delete: int = None, without_tracking=True, **kwargs): pass

View File

@ -2,8 +2,8 @@
"ProjectSettings": { "ProjectSettings": {
"Name": "bot-core", "Name": "bot-core",
"Version": { "Version": {
"Major": "1", "Major": "0",
"Minor": "0", "Minor": "3",
"Micro": "0" "Micro": "0"
}, },
"Author": "Sven Heidemann", "Author": "Sven Heidemann",
@ -16,15 +16,13 @@
"LicenseName": "MIT", "LicenseName": "MIT",
"LicenseDescription": "MIT, see LICENSE for more details.", "LicenseDescription": "MIT, see LICENSE for more details.",
"Dependencies": [ "Dependencies": [
"cpl-core>=2022.10.0" "cpl-core==2022.12.0"
], ],
"DevDependencies": [ "DevDependencies": [
"cpl-cli>=2022.10.0" "cpl-cli==2022.12.0"
], ],
"PythonVersion": ">=3.10.4", "PythonVersion": ">=3.10.4",
"PythonPath": { "PythonPath": {},
"linux": ""
},
"Classifiers": [] "Classifiers": []
}, },
"BuildSettings": { "BuildSettings": {

View File

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

View File

@ -2,8 +2,8 @@ from enum import Enum
class FeatureFlagsEnum(Enum): class FeatureFlagsEnum(Enum):
# modules # modules
api_module = 'ApiModule'
admin_module = 'AdminModule' admin_module = 'AdminModule'
auto_role_module = 'AutoRoleModule' auto_role_module = 'AutoRoleModule'
base_module = 'BaseModule' base_module = 'BaseModule'
@ -12,7 +12,10 @@ class FeatureFlagsEnum(Enum):
core_extension_module = 'CoreExtensionModule' core_extension_module = 'CoreExtensionModule'
data_module = 'DataModule', data_module = 'DataModule',
database_module = 'DatabaseModule', database_module = 'DatabaseModule',
level_module = 'LevelModule'
moderator_module = 'ModeratorModule' moderator_module = 'ModeratorModule'
permission_module = 'PermissionModule' permission_module = 'PermissionModule'
stats_module = 'StatsModule'
# features # features
api_only = 'ApiOnly'
presence = 'Presence' presence = 'Presence'

View File

@ -14,6 +14,7 @@ class FeatureFlagsSettings(ConfigurationModelABC):
self._flags = { self._flags = {
# modules # modules
FeatureFlagsEnum.api_module.value: False, # 13.10.2022 #70
FeatureFlagsEnum.admin_module.value: False, # 02.10.2022 #48 FeatureFlagsEnum.admin_module.value: False, # 02.10.2022 #48
FeatureFlagsEnum.auto_role_module.value: True, # 03.10.2022 #54 FeatureFlagsEnum.auto_role_module.value: True, # 03.10.2022 #54
FeatureFlagsEnum.base_module.value: True, # 02.10.2022 #48 FeatureFlagsEnum.base_module.value: True, # 02.10.2022 #48
@ -24,7 +25,9 @@ class FeatureFlagsSettings(ConfigurationModelABC):
FeatureFlagsEnum.database_module.value: True, # 02.10.2022 #48 FeatureFlagsEnum.database_module.value: True, # 02.10.2022 #48
FeatureFlagsEnum.moderator_module.value: False, # 02.10.2022 #48 FeatureFlagsEnum.moderator_module.value: False, # 02.10.2022 #48
FeatureFlagsEnum.permission_module.value: True, # 02.10.2022 #48 FeatureFlagsEnum.permission_module.value: True, # 02.10.2022 #48
FeatureFlagsEnum.stats_module.value: True, # 08.11.2022 #46
# features # features
FeatureFlagsEnum.api_only.value: False, # 13.10.2022 #70
FeatureFlagsEnum.presence.value: True, # 03.10.2022 #56 FeatureFlagsEnum.presence.value: True, # 03.10.2022 #56
} }

View File

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

View File

@ -0,0 +1,30 @@
from cpl_core.application import ApplicationExtensionABC
from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceProviderABC
from cpl_translation import TranslatePipe
from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC
from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_core.helper.command_checks import CommandChecks
from bot_core.helper.event_checks import EventChecks
from modules.permission.abc.permission_service_abc import PermissionServiceABC
class CoreExtension(ApplicationExtensionABC):
def __init__(self):
ApplicationExtensionABC.__init__(self)
async def run(self, config: ConfigurationABC, services: ServiceProviderABC):
feature_flags: FeatureFlagsSettings = config.get_configuration(FeatureFlagsSettings)
if not feature_flags.get_flag(FeatureFlagsEnum.core_module):
return
permissions: PermissionServiceABC = services.get_service(PermissionServiceABC)
client_utils: ClientUtilsServiceABC = services.get_service(ClientUtilsServiceABC)
message_service: MessageServiceABC = services.get_service(MessageServiceABC)
t: TranslatePipe = services.get_service(TranslatePipe)
CommandChecks.init(permissions, client_utils, message_service, t)
EventChecks.init(client_utils)

View File

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

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