207 Commits

Author SHA1 Message Date
a127e43dc0 Version upped 2017-09-15 22:22:03 +02:00
9cff3b59c1 clubapps and clubbans now have ok color line 2017-09-15 22:19:31 +02:00
4841418cff Added .clubadmin, .autoboobs and .autobutts, cleaned up SongBuffer. 2017-09-15 22:17:31 +02:00
16fd835d4b Caching anime and manga seraches. Club disband error message fixed. 2017-09-15 02:42:51 +02:00
25258a0c61 Possible fix for redis on linux. Setgame/SetStream and rotating statuses will now properly work across shards. 2017-09-14 19:37:41 +02:00
37412e4e73 Fixed shop role name. Fixed .xpglb (it will now show usernames and discriminators) 2017-09-13 21:15:49 +02:00
0a52676042 possible fix for null migration error 2017-09-13 08:12:07 +02:00
48adfc19af Fixed slow .xp and .xpglb 2017-09-13 05:10:26 +02:00
067297478e Removed leftover logs 2017-09-13 03:18:33 +02:00
a2c4695557 Global custom reactions now use redis pub/sub 2017-09-13 03:12:40 +02:00
438f68cde7 global nadeko won't cache nsfw images 2017-09-12 23:49:37 +02:00
46f9de01d6 Using redis to cache avatar images, reduced xp image size. 2017-09-12 22:27:51 +02:00
90b698f18e Fixed .clubapply help string 2017-09-12 08:14:58 +02:00
d51c28b73c .xpglb should be faster now. 2017-09-12 05:00:14 +02:00
f08fd3bdb1 1.8.4 2017-09-11 23:39:44 +02:00
ea0ca1471f Xp system fixes 2017-09-11 23:39:28 +02:00
4c591a69b1 Fixes to .xprr, leveling system 2017-09-11 22:43:32 +02:00
d658fe7414 Updated discord.net 2017-09-11 20:25:06 +02:00
81a7c6f398 Added .nsfwcc command to prevent memory leaks if nsfw is spammed a lot. 2017-09-11 19:30:02 +02:00
cdf15d6c01 Fixed club leaderboard 2017-09-11 19:20:18 +02:00
1a85825049 Fixed trivia, closes #1578 2017-09-11 19:12:49 +02:00
62c016c7cf 1.8.2 2017-09-11 01:49:51 +02:00
6c3025ecf1 Potential xp null error fix 2017-09-11 01:42:39 +02:00
927e98514a Fixed exclusion list after restarts, closes #1571 2017-09-11 00:21:14 +02:00
3de9a40ffd Fixed catfact thanks to twindragon, closes #1547 2017-09-11 00:01:31 +02:00
1af4679d9e When you guess a letter in hangman, updated message will now correctly show previous guesses. closes #1541 2017-09-10 23:48:34 +02:00
4adf85a9eb Possible fix for #1523, im not testing that though :D 2017-09-10 23:44:24 +02:00
531633b018 Possible trivia weirdness fix, #1522 2017-09-10 23:15:58 +02:00
76249c5b29 Made numbers 3 and 7 smaller in slot image because they were overflowing 2017-09-10 23:08:46 +02:00
771e0df064 closes #1500, #1433 2017-09-10 23:01:26 +02:00
2ab4274c22 Don't lose ignored channels if updating .antiraid #1402 2017-09-10 22:44:23 +02:00
6f12ad1478 Docs updates, closes #1570 2017-09-10 22:32:29 +02:00
b9f22df756 Fixed .xpex command help, .xpex channel will now default to current channel 2017-09-10 19:14:29 +02:00
6b896d8091 Merge branch '1.4' of https://github.com/Kwoth/NadekoBot into 1.4 2017-09-10 17:58:41 +02:00
268f9b0448 fixed .xpglb help string. Version upped to 1.8.1 2017-09-10 17:58:32 +02:00
5403105062 Merge pull request #1566 from shivaco/patch-2
Some mistypes
2017-09-10 17:25:44 +02:00
192667aa35 Merge branch '1.4' of https://github.com/Kwoth/NadekoBot into 1.4 2017-09-10 17:04:42 +02:00
af334a0b5c fixed club creation bug 2017-09-10 17:04:32 +02:00
14490024ea FIx of some mistypes 2017-09-10 16:20:55 +06:00
88833bd5fc Merge pull request #1565 from numbermaniac/1.4
fix spelling of "client" in JSON Explanations.md
2017-09-10 06:30:55 +02:00
9531fb7717 fix spelling of "client" in JSON Explanations 2017-09-10 14:16:11 +10:00
cd2a86c624 Updated commandlist 2017-09-10 04:00:56 +02:00
35176465b1 Merge branch '1.4' of https://github.com/Kwoth/NadekoBot into 1.4 2017-09-10 03:54:17 +02:00
306ff3a918 Merge branch 'xp-system' into 1.4 2017-09-10 03:53:56 +02:00
96d792f63b Xp and clubs finished. Need a lot of testing. Version upped to 1.8-beta 2017-09-10 03:52:34 +02:00
f61123ef92 Merge pull request #1545 from Deivedux/1.4
Fixed command prefixes in Permissions System doc
2017-08-30 20:15:17 +02:00
2aca71cd8a Update Permissions System.md 2017-08-30 20:56:44 +03:00
20fb253eb3 Removed .rrc because it's prohibited 2017-08-25 22:48:39 +02:00
5362821843 Version upped 2017-08-22 05:50:03 +02:00
19d710cdd4 Merge branch '1.4' of https://github.com/Kwoth/NadekoBot into 1.4 2017-08-22 05:49:04 +02:00
088d95340f Started work on the xp system 2017-08-22 05:48:45 +02:00
e5609a0708 .prefix bugfix, #1524 2017-08-22 05:47:57 +02:00
a612e50ea3 Merge pull request #1521 from alistairmackenzie/1.4
Fix typo in rategirl command.
2017-08-21 03:22:04 +02:00
658597db9f Fix typo in rategirl command. Solves #1517 2017-08-21 02:08:57 +01:00
919c81d385 Fixed .wheel example 2017-08-16 22:05:06 +02:00
f255ed26dd .sad enable/disable string was swapped 2017-08-16 11:51:41 +02:00
03a86b0be9 Antispam can now take an extra parameter at the end which is the time of the mute. It will be ignored if punishment type isn't mute 2017-08-16 01:12:18 +02:00
fe3770270e Added .songautodelete/.sad command. 2017-08-15 23:54:54 +02:00
e50e71014e Upped version 2017-08-15 22:59:48 +02:00
d74a23d215 You can now gift items to waifus with '.gift' command 2017-08-14 07:25:32 +02:00
7a1895bf31 possible fix for flowerreaction event on public nadeko 2017-08-14 05:19:37 +02:00
70906ed5cb Added betflip and betroll multiplier to .bce, closes #1498 2017-08-13 04:24:20 +02:00
a98be21181 small error fix 2017-08-11 22:53:31 +02:00
1552d2c892 Fixed extra space in %target%, closes #1483 2017-08-11 14:02:48 +02:00
6c5ea68032 .antispam should now update when you use it with new parameters. Use no parameters to disable it if it exists, or run it with default values if it doesn't 2017-08-06 18:01:10 +02:00
0bf6459e6a if .tesar is enabled, .iam will remove all other self assignable roles except only one. #1402 2017-08-06 17:43:15 +02:00
f02ac7cd78 renamed hitbox to smashcast 2017-08-06 17:34:52 +02:00
e2d7ed343c Beam renamed to mixer. Version upped. 2017-08-06 16:07:48 +02:00
57dd324f3e You can no longer give your max role to other users with .sr 2017-08-06 15:59:29 +02:00
464118f792 having .crca enabled with %target% will replace target with everything that comes after the trigger wherever it is in the triggering message 2017-08-06 14:31:28 +02:00
10fdd36e87 fixed sfi and sfw not ignoring server admin when message is edited. #1444 2017-08-06 12:02:13 +02:00
1358878773 Fixed index for .qn 2017-08-06 11:49:27 +02:00
540209706d Added .qn and fixed .hangman bugs 2017-08-05 12:38:53 +02:00
79d3fca7e4 Fixed incorrect usage for .ttt 2017-08-05 10:51:46 +02:00
d12d70df1b Fixed connect4 weird wins 2017-08-05 10:46:38 +02:00
ce602b5b35 Version upped 2017-08-05 10:13:05 +02:00
38125509e5 fixed .weather min/max temperature 2017-08-05 10:12:20 +02:00
958eca2935 Nunchi fix, shop fix 2017-08-05 09:52:32 +02:00
dea9a935a4 Small nunchi fix, global nadeko improvement 2017-08-04 19:43:25 +02:00
47125ed687 connect4 bugfixes 2017-08-04 18:12:26 +02:00
ec7f69f1c0 connect4 game added. 2017-08-04 14:36:07 +02:00
94e4c89564 Updated commandlist 2017-08-03 20:19:43 +02:00
d9a446d874 Nunchi is much more fair and forgiving now. There are 5 seconds delays between rounds, and only one player can fail per round (multiple users can still get booted if they're inactive) 2017-08-03 20:19:09 +02:00
f3984c824e Nunchi game added. A bit confusing now. Will be polished further tomorrow. 2017-08-03 00:29:38 +02:00
e0be610ec0 .wheel command added (wheel of fortune gambling) 2017-08-02 22:07:19 +02:00
82aac891dd animal racing rewritten to be isolated. Please hunt bugs. 2017-08-01 00:11:36 +02:00
3097ef88a7 Fixed hangman error 2017-07-31 08:50:04 +02:00
f06ee47516 cleanup 2017-07-28 12:38:08 +02:00
d5978a0d66 .hangman completely rewritten. Should work almost the same, with some minor improvements (such as showing the category, and you can now guess the whole word at once) 2017-07-28 12:28:08 +02:00
53661b3337 Removed old stuff 2017-07-27 18:44:45 +02:00
2fe812c4ac Merge branch '1.4' of https://github.com/Kwoth/NadekoBot into 1.4 2017-07-27 18:43:37 +02:00
fece28b66b Acrophobia completely rewritten. Works the same as before, only much more maintainable. It won't repost itself after 10 messages anymore though. 2017-07-27 18:43:15 +02:00
bf7585cd83 slight cleanup 2017-07-26 18:19:39 +02:00
f1e59d561d Update ResponseStrings.ru-RU.json (POEditor.com) 2017-07-26 18:09:29 +02:00
97b84ef469 Update ResponseStrings.ro-RO.json (POEditor.com) 2017-07-26 18:09:26 +02:00
a0496454bd Update ResponseStrings.pt-BR.json (POEditor.com) 2017-07-26 18:09:24 +02:00
ffd570511a Update ResponseStrings.pl-PL.json (POEditor.com) 2017-07-26 18:09:21 +02:00
ed623dd967 Update ResponseStrings.nb-NO.json (POEditor.com) 2017-07-26 18:09:19 +02:00
e10aee9c69 Update ResponseStrings.ko-KR.json (POEditor.com) 2017-07-26 18:09:16 +02:00
6294dc8679 Update ResponseStrings.ja-JP.json (POEditor.com) 2017-07-26 18:09:13 +02:00
89b810df54 Update ResponseStrings.it-IT.json (POEditor.com) 2017-07-26 18:09:11 +02:00
2d1b5dda96 Update ResponseStrings.id-ID.json (POEditor.com) 2017-07-26 18:09:08 +02:00
2a137004a5 Update ResponseStrings.he-IL.json (POEditor.com) 2017-07-26 18:09:05 +02:00
92bf9b88b4 Update ResponseStrings.de-DE.json (POEditor.com) 2017-07-26 18:09:03 +02:00
44b3223c1b Update ResponseStrings.fr-FR.json (POEditor.com) 2017-07-26 18:09:00 +02:00
81f0032262 Update ResponseStrings.nl-NL.json (POEditor.com) 2017-07-26 18:08:57 +02:00
d86c8ed41b Update ResponseStrings.da-DK.json (POEditor.com) 2017-07-26 18:08:55 +02:00
afda3e2046 Update ResponseStrings.cs-CZ.json (POEditor.com) 2017-07-26 18:08:52 +02:00
8e7935f893 Update ResponseStrings.zh-TW.json (POEditor.com) 2017-07-26 18:08:49 +02:00
5295704447 Update ResponseStrings.zh-CN.json (POEditor.com) 2017-07-26 18:08:47 +02:00
c738cb569e Update ResponseStrings.ar.json (POEditor.com) 2017-07-26 18:08:44 +02:00
263a95a6ad cleanup 2017-07-25 18:31:30 +02:00
e9cf57d46f .crdm was deleted by accident, it's back now 2017-07-23 09:52:45 +02:00
f773b0c6b6 .crca added. If you enable it on a custom reation, you can use the trigger word anywhere in the sentence in order to trigger that custom reaction. 2017-07-22 18:12:08 +02:00
1aa86937c8 small changes 2017-07-22 07:57:17 +02:00
f1b348406d Bugfixes 2017-07-21 07:10:17 +02:00
b9bb72f06d Streamrole is smarter, but possibly more expensive. It will rescan users when settings are changed. And when the bot is started. 2017-07-21 06:56:21 +02:00
d074444c26 commandlist updated 2017-07-21 03:05:13 +02:00
0d216ad78a .nsfwtbl added. You can now blacklist tags which are used in nsfw commands. 2017-07-21 03:04:44 +02:00
0131b7713e Make sure to assign new bot creds variable 2017-07-20 23:48:25 +02:00
613655eb95 You can now add CleverBotApiKey from cleverbot.com/api in order to use official cleverbot, instead of stupid program-o 2017-07-20 22:58:19 +02:00
cedaf73785 Sped up .streamrole initialization 5x, but it might error out if there are too many users streaming when the command is ran. 2017-07-20 20:03:11 +02:00
9163510eee .bce command added, you can now edit BotConfig without editing the database and restarting the bot. Cleanup 2017-07-20 05:10:39 +02:00
fe88611183 Fixed .shop pagination 2017-07-19 11:02:14 +02:00
4130317f40 .srkw, .srwl and .srbl commands added. 2017-07-19 10:38:14 +02:00
3f7f6cecbe Merge branch '1.4' of https://github.com/Kwoth/NadekoBot into 1.4 2017-07-19 09:31:10 +02:00
50236d71d5 Fixed multi-shard bots 2017-07-19 09:31:00 +02:00
8612dc852e Merge pull request #1423 from Deivedux/1.4
Updated windows guides
2017-07-18 21:07:39 +02:00
8dd24443c0 Update Windows Guide.md
Added missing installation part for music features.
2017-07-18 21:30:27 +03:00
86743250cf Update Upgrading Guide.md
Windows part of the upgrading guide is now more straightforward.
2017-07-18 21:29:08 +03:00
661d026973 Updated imagesharp 2017-07-18 18:26:55 +02:00
55b1c3945b Updated commandlist. Goodbye clash of clans 👋 closes #1420 2017-07-18 04:25:30 +02:00
c054543d98 Huge refactor is over 2017-07-17 21:42:36 +02:00
618968d2e4 More refactoring 2017-07-17 04:37:51 +02:00
4e11a6c8bc More refactoring 2017-07-15 18:34:34 +02:00
b3243eb0e9 More cleanup 2017-07-15 15:08:34 +02:00
028606b080 More cleanup 2017-07-15 05:54:36 +02:00
ac5e4e7540 Version upped 2017-07-15 05:33:23 +02:00
30bafa8a89 More cleanup 2017-07-15 05:23:46 +02:00
4eca5be1d4 Huge cleanup,
rewrite of the NadekoBot.cs, way services are loaded has changed. Updated discord.net.
2017-07-15 05:04:16 +02:00
f239c46e20 Words should get filtered in edited messages too. 2017-07-14 18:39:21 +02:00
1c72d2864a Merge pull request #1397 from samdivaio/1.5-music-changes
Stop no longer resets current song index 0, formatting changes. Use `.srm all` to get pre-update `.stop` behavior (clears the queue and stops the player)
2017-07-14 17:52:44 +02:00
45ee3042bb Merge branch '1.4' of https://github.com/Kwoth/NadekoBot into 1.4 2017-07-14 17:49:55 +02:00
17719dd8e2 finished .streamrole 2017-07-14 17:09:06 +02:00
11b533c3b7 Done as per Kwoth. 2017-07-14 09:45:31 +05:30
b8573f11b5 Added .streamrole, needs testing. 2017-07-14 05:00:30 +02:00
f26a7de704 Revert "Stop works as it used to before. Auto rpl disabled."
This reverts commit fd410bc856.
2017-07-14 00:54:23 +05:30
6124c3dce8 Merge pull request #1403 from hakufu/1.4
Add deny perm for addReactions on mute
2017-07-13 20:36:55 +02:00
390a637c08 Add deny perm for addReactions on mute
Added the permission for the channel override when muting to also include the denial of "addReactions."
2017-07-13 14:08:51 -04:00
202c5e98a5 Makeover to highlight the information.
Look is similar to early version of Nadeko.
2017-07-13 17:45:46 +05:30
fd410bc856 Stop works as it used to before. Auto rpl disabled.
Bot no longer repeats playlist on default.

Bot now clears the queued songs list (playlist)
- if `.stop` command is used.
- if the last song of the queue is playing and `.next` command is used.
- if the the last song of the queue finished playing.
2017-07-13 17:36:49 +05:30
c328ec68d3 Documents updated
macOS prerequisite info added
2017-07-13 17:34:28 +05:30
4dbdce7f5d Merge pull request #15 from Kwoth/1.4
ups
2017-07-13 17:14:29 +05:30
67f0cfb717 Version upped 2017-07-13 04:09:38 +02:00
ed40bc99b2 .movesong works more intuitively now, and current song's index is now updated after songs are moved 2017-07-13 04:09:21 +02:00
b85cc023f2 format 2017-07-12 15:38:34 +02:00
467b482ff9 Added some stuff to stats sending 2017-07-12 04:13:50 +02:00
c0012e296e Some stats stuff for science 2017-07-12 03:39:44 +02:00
8a75c28d73 Small doc fixes 2017-07-12 02:02:17 +02:00
4b9977e5d6 Upped version 2017-07-11 20:22:24 +02:00
c1cf85b338 Fixed error when logging something related to a user who has no avatar, closes #1381 2017-07-11 20:22:06 +02:00
5e230fad22 using .n when rpl is disabled will stop the queue 2017-07-11 20:11:36 +02:00
0e4728d9c9 Fixed .play when queue is stopped. .play X will now also unstop the player 2017-07-11 19:52:10 +02:00
8f90410e2d Small refactor 2017-07-11 03:16:56 +02:00
ec94459722 Fixed soundcloud song length, closes #1380 2017-07-11 01:23:37 +02:00
ab3ad4f2fb Upped version 2017-07-10 21:56:53 +02:00
dc0176365b Fixed .convert, closes #1377 2017-07-10 21:35:45 +02:00
34b56c6353 Fixed .srm, closes #1373 2017-07-10 21:31:47 +02:00
9a744172a9 Fixed a bug where spamming .n would crash the music player, closes #1372 2017-07-10 21:21:45 +02:00
70f0f6af44 Fixed some links queueing random songs. closes #1368 2017-07-10 21:08:11 +02:00
3119a47007 Upped version 2017-07-10 19:40:55 +02:00
5db254e8f3 Fixed .lolban, closes #1340 2017-07-10 19:40:34 +02:00
f396fc78db Fixed shard number bold in unresponsive shard 2017-07-09 19:26:17 +02:00
9d778de7f2 fixed .ropl with %queued% and %playing% 2017-07-09 12:43:14 +02:00
3966629263 Upped version 2017-07-09 01:40:54 +02:00
f1a4a88730 Fixed song time on songs shorter than 1 minute 2017-07-09 01:39:47 +02:00
fad0b908c8 fixed .autoplay 2017-07-09 01:37:17 +02:00
9eab7d949f Possibly fix youtube-dl certificate error 2017-07-09 00:56:12 +02:00
f58e7ed7ac Fixed .warnlogall, updated commandlist 2017-07-08 15:27:48 +02:00
27f925fa63 Fixed userpresence and game changes readded to userpresence 2017-07-08 14:54:19 +02:00
aa01314b3a Embed field names and values will be trimmed to their acceptable length to prevent errors. closes #1355 2017-07-08 14:20:06 +02:00
72e7b04319 Fixed 100% cpu usage on single threaded systems. Totally my bad. 2017-07-08 13:42:16 +02:00
568cdfbd3c Fixed .save 2017-07-08 13:27:53 +02:00
4132565948 Fixed footer icon urls 2017-07-08 00:05:11 +02:00
96ae60378b 1.54b 2017-07-07 23:23:10 +02:00
4de7e38277 fixed trivia, and some other things 2017-07-07 23:22:34 +02:00
ab99801a37 version upped 2017-07-07 16:07:57 +02:00
994457f9af Merge branch '1.4' of https://github.com/Kwoth/NadekoBot into 1.4 2017-07-07 15:52:38 +02:00
9e9f21d525 Update ResponseStrings.ro-RO.json (POEditor.com) 2017-07-07 15:48:42 +02:00
f3f934e05f Update ResponseStrings.pt-BR.json (POEditor.com) 2017-07-07 15:48:40 +02:00
bf860f9aa8 Update ResponseStrings.pl-PL.json (POEditor.com) 2017-07-07 15:48:37 +02:00
a49002a808 Update ResponseStrings.nb-NO.json (POEditor.com) 2017-07-07 15:48:35 +02:00
88e42e672b Update ResponseStrings.ko-KR.json (POEditor.com) 2017-07-07 15:48:32 +02:00
fcbf3a0918 Update ResponseStrings.ja-JP.json (POEditor.com) 2017-07-07 15:48:29 +02:00
cb04e987c3 Update ResponseStrings.it-IT.json (POEditor.com) 2017-07-07 15:48:27 +02:00
7f4970a5da Update ResponseStrings.id-ID.json (POEditor.com) 2017-07-07 15:48:24 +02:00
19246b9bf2 Update ResponseStrings.he-IL.json (POEditor.com) 2017-07-07 15:48:20 +02:00
b73e0d18e5 Update ResponseStrings.de-DE.json (POEditor.com) 2017-07-07 15:48:17 +02:00
d0c580f39a Update ResponseStrings.fr-FR.json (POEditor.com) 2017-07-07 15:48:14 +02:00
93b48ff3b0 Update ResponseStrings.nl-NL.json (POEditor.com) 2017-07-07 15:48:12 +02:00
b04e7cbd55 Update ResponseStrings.da-DK.json (POEditor.com) 2017-07-07 15:48:09 +02:00
fe175ecd43 Update ResponseStrings.cs-CZ.json (POEditor.com) 2017-07-07 15:48:06 +02:00
c7936335bf Update ResponseStrings.zh-TW.json (POEditor.com) 2017-07-07 15:48:04 +02:00
264e38c7a0 Update ResponseStrings.zh-CN.json (POEditor.com) 2017-07-07 15:48:01 +02:00
d782ceb9fa Update ResponseStrings.ar.json (POEditor.com) 2017-07-07 15:47:58 +02:00
e15045292f Fixed embeds 2017-07-07 15:45:21 +02:00
74ad7b32bd done testing 2017-07-07 13:40:17 +02:00
389 changed files with 30854 additions and 6875 deletions

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.12
VisualStudioVersion = 15.0.26730.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}"
EndProject
@ -33,4 +33,7 @@ Global
GlobalSection(NestedProjects) = preSolution
{45EC1473-C678-4857-A544-07DFE0D0B478} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5F3F555C-855F-4BE8-B526-D062D3E8ACA4}
EndGlobalSection
EndGlobal

View File

@ -3,7 +3,6 @@ You can support the project on patreon: <https://patreon.com/nadekobot> or paypa
##Table of contents
- [Help](#help)
- [Administration](#administration)
- [ClashOfClans](#clashofclans)
- [CustomReactions](#customreactions)
- [Gambling](#gambling)
- [Games](#games)
@ -13,6 +12,7 @@ You can support the project on patreon: <https://patreon.com/nadekobot> or paypa
- [Pokemon](#pokemon)
- [Searches](#searches)
- [Utility](#utility)
- [Xp](#xp)
### Administration
@ -90,7 +90,6 @@ Commands and aliases | Description | Usage
`.setgame` | Sets the bots game. **Bot owner only** | `.setgame with snakes`
`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot owner only** | `.setstream TWITCHLINK Hello`
`.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prefix the channel id with `c:` and the user id with `u:`. **Bot owner only** | `.send serverid|c:channelid message` or `.send serverid|u:userid message`
`.announce` | Sends a message to all servers' default channel that bot is connected to. **Bot owner only** | `.announce Useless spam`
`.reloadimages` | Reloads images bot is using. Safe to use even when bot is being used heavily. **Bot owner only** | `.reloadimages`
`.greetdel` `.grdel` | Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.greetdel 0` or `.greetdel 30`
`.greet` | Toggles anouncements on the current channel when someone joins the server. **Requires ManageServer server permission.** | `.greet`
@ -119,21 +118,6 @@ Commands and aliases | Description | Usage
###### [Back to ToC](#table-of-contents)
### ClashOfClans
Commands and aliases | Description | Usage
----------------|--------------|-------
`.createwar` `.cw` | Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. **Requires ManageMessages server permission.** | `.cw 15 The Enemy Clan`
`.startwar` `.sw` | Starts a war with a given number. | `.sw 15`
`.listwar` `.lw` | Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | `.lw [war_number]` or `.lw`
`.basecall` | Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. | `.basecall [war_number] [base_number] [optional_other_name]`
`.callfinish1` `.cf1` | Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. | `.cf1 1` or `.cf1 1 5`
`.callfinish2` `.cf2` | Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. | `.cf2 1` or `.cf2 1 5`
`.callfinish` `.cf` | Finish your claim with 3 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. | `.cf 1` or `.cf 1 5`
`.endwar` `.ew` | Ends the war with a given index. | `.ew [war_number]`
`.uncall` | Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | `.uc [war_number] [optional_other_name]`
###### [Back to ToC](#table-of-contents)
### CustomReactions
Commands and aliases | Description | Usage
----------------|--------------|-------
@ -142,6 +126,7 @@ Commands and aliases | Description | Usage
`.listcustreactg` `.lcrg` | Lists global or server custom reactions (20 commands per page) grouped by trigger, and show a number of responses for each. Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. | `.lcrg 1`
`.showcustreact` `.scr` | Shows a custom reaction's response on a given ID. | `.scr 1`
`.delcustreact` `.dcr` | Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration privileges and removes server custom reaction. | `.dcr 5`
`.crca` | Toggles whether the custom reaction will trigger if the triggering message contains the keyword (instead of only starting with it). | `.crca 44`
`.crdm` | Toggles whether the response message of the custom reaction will be sent as a direct message. | `.crdm 44`
`.crad` | Toggles whether the message triggering the custom reaction will be automatically deleted. | `.crad 59`
`.crstatsclear` | Resets the counters on `.crstats`. You can specify a trigger to clear stats only for that trigger. **Bot owner only** | `.crstatsclear` or `.crstatsclear rng`
@ -183,23 +168,27 @@ Commands and aliases | Description | Usage
`.affinity` | Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `.claim` on you by 20%. You can leave second argument empty to clear your affinity. 30 minutes cooldown. | `.affinity @MyHusband` or `.affinity`
`.waifus` `.waifulb` | Shows top 9 waifus. You can specify another page to show other waifus. | `.waifus` or `.waifulb 3`
`.waifuinfo` `.waifustats` | Shows waifu stats for a target person. Defaults to you if no user is provided. | `.waifuinfo @MyCrush` or `.waifuinfo`
`.waifugift` `.gift` `.gifts` | Gift an item to someone. This will increase their waifu value by 50% of the gifted item's value if they don't have affinity set towards you, or 100% if they do. Provide no arguments to see a list of items that you can gift. | `.gifts` or `.gift Rose @Himesama`
`.wheeloffortune` `.wheel` | Bets a certain amount of currency on the wheel of fortune. Wheel can stop on one of many different multipliers. Won amount is rounded down to the nearest whole number. | `.wheel 10`
###### [Back to ToC](#table-of-contents)
### Games
Commands and aliases | Description | Usage
----------------|--------------|-------
`.leet` | Converts a text to leetspeak with 6 (1-6) severity levels | `.leet 3 Hello`
`.choose` | Chooses a thing from a list of things | `.choose Get up;Sleep;Sleep more`
`.8ball` | Ask the 8ball a yes/no question. | `.8ball should I do something`
`.rps` | Play a game of Rocket-Paperclip-Scissors with Nadeko. | `.rps scissors`
`.rategirl` | Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart. | `.rategirl @SomeGurl`
`.linux` | Prints a customizable Linux interjection | `.linux Spyware Windows`
`.leet` | Converts a text to leetspeak with 6 (1-6) severity levels | `.leet 3 Hello`
`.acrophobia` `.acro` | Starts an Acrophobia game. Second argument is optional round length in seconds. (default is 60) | `.acro` or `.acro 30`
`.cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages server permission.** | `.cleverbot`
`.connect4` `.con4` | Creates or joins an existing connect4 game. 2 players are required for the game. Objective of the game is to get 4 of your pieces next to each other in a vertical, horizontal or diagonal line. | `.connect4`
`.hangmanlist` | Shows a list of hangman term types. | `.hangmanlist`
`.hangman` | Starts a game of hangman in the channel. Use `.hangmanlist` to see a list of available term types. Defaults to 'all'. | `.hangman` or `.hangman movies`
`.hangmanstop` | Stops the active hangman game on this channel if it exists. | `.hangmanstop`
`.nunchi` | Creates or joins an existing nunchi game. Users have to count up by 1 from the starting number shown by the bot. If someone makes a mistake (types an incorrent number, or repeats the same number) they are out of the game and a new round starts without them. Minimum 3 users required. | `.nunchi`
`.pick` | Picks the currency planted in this channel. 60 seconds cooldown. | `.pick`
`.plant` | Spend an amount of currency to plant it in this channel. Default is 1. (If bot is restarted or crashes, the currency will be lost) | `.plant` or `.plant 5`
`.gencurrency` `.gc` | Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) **Requires ManageMessages server permission.** | `.gc`
@ -211,7 +200,7 @@ Commands and aliases | Description | Usage
`.typeadd` | Adds a new article to the typing contest. **Bot owner only** | `.typeadd wordswords`
`.typelist` | Lists added typing articles with their IDs. 15 per page. | `.typelist` or `.typelist 3`
`.typedel` | Deletes a typing article given the ID. **Bot owner only** | `.typedel 3`
`.tictactoe` `.ttt` | Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. 15 seconds per move. | >ttt
`.tictactoe` `.ttt` | Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. 15 seconds per move. | .ttt
`.trivia` `.t` | Starts a game of trivia. You can add `nohint` to prevent hints. First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. | `.t` or `.t 5 nohint`
`.tl` | Shows a current trivia leaderboard. | `.tl`
`.tq` | Quits current trivia after current question. | `.tq`
@ -235,20 +224,22 @@ Commands and aliases | Description | Usage
----------------|--------------|-------
`.play` `.start` | If no arguments are specified, acts as `.next 1` command. If you specify a song number, it will jump to that song. If you specify a search query, acts as a `.q` command | `.play` or `.play 5` or `.play Dream Of Venice`
`.queue` `.q` `.yq` | Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**. | `.q Dream Of Venice`
`.queuenext` `.qn` | Works the same as `.queue` command, except it enqueues the new song after the current one. **You must be in a voice channel**. | `.qn Dream Of Venice`
`.queuesearch` `.qs` `.yqs` | Search for top 5 youtube song result using keywords, and type the index of the song to play that song. Bot will join your voice channel. **You must be in a voice channel**. | `.qs Dream Of Venice`
`.listqueue` `.lq` | Lists 15 currently queued songs per page. Default page is 1. | `.lq` or `.lq 2`
`.listqueue` `.lq` | Lists 10 currently queued songs per page. Default page is 1. | `.lq` or `.lq 2`
`.next` `.n` | Goes to the next song in the queue. You have to be in the same voice channel as the bot. You can skip multiple songs, but in that case songs will not be requeued if .rcs or .rpl is enabled. | `.n` or `.n 5`
`.stop` `.s` | Stops the music and clears the playlist. Stays in the channel. | `.s`
`.stop` `.s` | Stops the music and preserves the current song index. Stays in the channel. | `.s`
`.destroy` `.d` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) | `.d`
`.pause` `.p` | Pauses or Unpauses the song. | `.p`
`.volume` `.vol` | Sets the music playback volume (0-100%) | `.vol 50`
`.defvol` `.dv` | Sets the default music volume when music playback is started (0-100). Persists through restarts. | `.dv 80`
`.songremove` `.srm` | Remove a song by its # in the queue, or 'all' to remove all songs from the queue. | `.srm 5`
`.songremove` `.srm` | Remove a song by its # in the queue, or 'all' to remove all songs from the queue and reset the song index. | `.srm 5`
`.playlists` `.pls` | Lists all playlists. Paginated, 20 per page. Default page is 0. | `.pls 1`
`.deleteplaylist` `.delpls` | Deletes a saved playlist. Works only if you made it or if you are the bot owner. | `.delpls animu-5`
`.save` | Saves a playlist under a certain name. Playlist name must be no longer than 20 characters and must not contain dashes. | `.save classical1`
`.load` | Loads a saved playlist using its ID. Use `.pls` to list all saved playlists and `.save` to save new ones. | `.load 5`
`.fairplay` `.fp` | Toggles fairplay. While enabled, the bot will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue. | `.fp`
`.songautodelete` `.sad` | Toggles whether the song should be automatically removed from the music queue when it finishes playing. | `.sad`
`.soundcloudqueue` `.sq` | Queue a soundcloud song using keywords. Bot will join your voice channel. **You must be in a voice channel**. | `.sq Dream Of Venice`
`.soundcloudpl` `.scpl` | Queue a Soundcloud playlist using a link. | `.scpl soundcloudseturl`
`.nowplaying` `.np` | Shows the song that the bot is currently playing. | `.np`
@ -282,6 +273,8 @@ Commands and aliases | Description | Usage
`.gelbooru` | Shows a random hentai image from gelbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `.gelbooru yuri+kissing`
`.boobs` | Real adult content. | `.boobs`
`.butts` `.ass` `.butt` | Real adult content. | `.butts` or `.ass`
`.nsfwtagbl` `.nsfwtbl` | Toggles whether the tag is blacklisted or not in nsfw searches. Provide no parameters to see the list of blacklisted tags. | `.nsfwtbl poop`
`.nsfwcc` | Clears nsfw cache. **Bot owner only** | `.nsfwcc`
###### [Back to ToC](#table-of-contents)
@ -383,11 +376,11 @@ Commands and aliases | Description | Usage
`.place` | Shows a placeholder image of a given tag. Use `.placelist` to see all available tags. You can specify the width and height of the image as the last two optional arguments. | `.place Cage` or `.place steven 500 400`
`.pokemon` `.poke` | Searches for a pokemon. | `.poke Sylveon`
`.pokemonability` `.pokeab` | Searches for a pokemon ability. | `.pokeab overgrow`
`.hitbox` `.hb` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `.hitbox SomeStreamer`
`.smashcast` `.hb` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `.smashcast SomeStreamer`
`.twitch` `.tw` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `.twitch SomeStreamer`
`.beam` `.bm` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `.beam SomeStreamer`
`.mixer` `.bm` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `.mixer SomeStreamer`
`.liststreams` `.ls` | Lists all streams you are following on this server. | `.ls`
`.removestream` `.rms` | Removes notifications of a certain streamer from a certain platform on this channel. **Requires ManageMessages server permission.** | `.rms Twitch SomeGuy` or `.rms Beam SomeOtherGuy`
`.removestream` `.rms` | Removes notifications of a certain streamer from a certain platform on this channel. **Requires ManageMessages server permission.** | `.rms Twitch SomeGuy` or `.rms mixer SomeOtherGuy`
`.checkstream` `.cs` | Checks if a user is online on a certain streaming platform. | `.cs twitch MyFavStreamer`
`.translate` `.trans` | Translates from>to text. From the given language to the destination language. | `.trans en>fr Hello`
`.autotrans` `.at` | Starts automatic translation of all messages by users who set their `.atl` in this channel. You can set "del" argument to automatically delete all translated user messages. **Requires Administrator server permission.** **Bot owner only** | `.at` or `.at del`
@ -400,7 +393,6 @@ Commands and aliases | Description | Usage
### Utility
Commands and aliases | Description | Usage
----------------|--------------|-------
`.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Requires ManageRoles server permission.** **Bot owner only** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole`
`.togethertube` `.totube` | Creates a new room on <https://togethertube.com> and shows the link in the chat. | `.totube`
`.whosplaying` `.whpl` | Shows a list of users who are playing the specified game. | `.whpl Overwatch`
`.inrole` | Lists every person from the specified role on this server. You can use role ID, role name. | `.inrole Some Role`
@ -417,11 +409,12 @@ Commands and aliases | Description | Usage
`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot owner only** | `.listservers 3`
`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot owner only** | `.savechat 150`
`.ping` | Ping the bot to see if there are latency issues. | `.ping`
`.botconfigedit` `.bce` | Sets one of available bot config settings to a specified value. Use the command without any parameters to get a list of available settings. **Bot owner only** | `.bce CurrencyName b1nzy` or `.bce`
`.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1`
`.calcops` | Shows all available operations in the `.calc` command | `.calcops`
`.alias` `.cmdmap` | Create a custom alias for a certain Nadeko command. Provide no alias to remove the existing one. **Requires Administrator server permission.** | `.alias allin $bf 100 h` or `.alias "linux thingy" >loonix Spyware Windows`
`.aliaslist` `.cmdmaplist` `.aliases` | Shows the list of currently set aliases. Paginated. | `.aliaslist` or `.aliaslist 3`
`.serverinfo` `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | `.sinfo Some Server`
`.serverinfo` `.sinfo` | Shows info about the server the bot is on. If no server is supplied, it defaults to current one. | `.sinfo Some Server`
`.channelinfo` `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | `.cinfo #some-channel`
`.userinfo` `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | `.uinfo @SomeUser`
`.activity` | Checks for spammers. **Bot owner only** | `.activity`
@ -440,6 +433,39 @@ Commands and aliases | Description | Usage
`.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2`
`.repeat` | Repeat a message every `X` minutes in the current channel. You can instead specify time of day for the message to be repeated at daily (make sure you've set your server's timezone). You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` or `.repeat 17:30 tea time`
`.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist`
`.streamrole` | Sets a role which is monitored for streamers (FromRole), and a role to add if a user from 'FromRole' is streaming (AddRole). When a user from 'FromRole' starts streaming, they will receive an 'AddRole'. Provide no arguments to disable **Requires ManageRoles server permission.** | `.streamrole "Eligible Streamers" "Featured Streams"`
`.streamrolekw` `.srkw` | Sets keyword which is required in the stream's title in order for the streamrole to apply. Provide no keyword in order to reset. **Requires ManageRoles server permission.** | `.srkw` or `.srkw PUBG`
`.streamrolebl` `.srbl` | Adds or removes a blacklisted user. Blacklisted users will never receive the stream role. **Requires ManageRoles server permission.** | `.srbl add @b1nzy#1234` or `.srbl rem @b1nzy#1234`
`.streamrolewl` `.srwl` | Adds or removes a whitelisted user. Whitelisted users will receive the stream role even if they don't have the specified keyword in their stream title. **Requires ManageRoles server permission.** | `.srwl add @b1nzy#1234` or `.srwl rem @b1nzy#1234`
`.convertlist` | List of the convertible dimensions and currencies. | `.convertlist`
`.convert` | Convert quantities. Use `.convertlist` to see supported dimensions and currencies. | `.convert m km 1000`
`.verboseerror` `.ve` | Toggles whether the bot should print command errors when a command is incorrectly used. **Requires ManageMessages server permission.** | `.ve`
###### [Back to ToC](#table-of-contents)
### Xp
Commands and aliases | Description | Usage
----------------|--------------|-------
`.experience` `.xp` | Shows your xp stats. Specify the user to show that user's stats instead. | `.xp`
`.xprolerewards` `.xprrs` | Shows currently set role rewards. | `.xprrs`
`.xprolereward` `.xprr` | Sets a role reward on a specified level. Provide no role name in order to remove the role reward. **Requires ManageRoles server permission.** | `.xprr 3 Social`
`.xpnotify` `.xpn` | Sets how the bot should notify you when you get a `server` or `global` level. You can set `dm` (for the bot to send a direct message), `channel` (to get notified in the channel you sent the last message in) or `none` to disable. | `.xpn global dm` `.xpn server channel`
`.xpexclude` `.xpex` | Exclude a user or a role from the xp system, or whole current server. **Requires Administrator server permission.** | `.xpex Role Excluded-Role` `.xpex Server`
`.xpexclusionlist` `.xpexl` | Shows the roles and channels excluded from the XP system on this server, as well as whether the whole server is excluded. | `.xpexl`
`.xpleaderboard` `.xplb` | Shows current server's xp leaderboard. | `.xplb`
`.xpgleaderboard` `.xpglb` | Shows the global xp leaderboard. | `.xpglb`
`.xpadd` | Adds xp to a user on the server. This does not affect their global ranking. You can use negative values. **Requires Administrator server permission.** | `.xpadd 100 @b1nzy`
`.clubcreate` | Creates a club. You must be atleast level 5 and not be in the club already. | `.clubcreate b1nzy's friends`
`.clubicon` | Sets the club icon. | `.clubicon https://i.imgur.com/htfDMfU.png`
`.clubinfo` | Shows information about the club. | `.clubinfo b1nzy's friends#123`
`.clubbans` | Shows the list of users who have banned from your club. Paginated. You must be club owner to use this command. | `.clubbans 2`
`.clubapps` | Shows the list of users who have applied to your club. Paginated. You must be club owner to use this command. | `.clubapps 2`
`.clubapply` | Apply to join a club. You must meet that club's minimum level requirement, and not be on its ban list. | `.clubapply b1nzy's friends#123`
`.clubaccept` | Accept a user who applied to your club. | `.clubaccept b1nzy#1337`
`.clubleave` | Leaves the club you're currently in. | `.clubleave`
`.clubkick` | Kicks the user from the club. You must be the club owner. They will be able to apply again. | `.clubkick b1nzy#1337`
`.clubban` | Bans the user from the club. You must be the club owner. They will not be able to apply again. | `.clubban b1nzy#1337`
`.clubunban` | Unbans the previously banned user from the club. You must be the club owner. | `.clubunban b1nzy#1337`
`.clublevelreq` | Sets the club required level to apply to join the club. You must be club owner. You can't set this number below 5. | `.clublevelreq 7`
`.clubdisband` | Disbands the club you're the owner of. This action is irreversible. | `.clubdisband`
`.clublb` | Shows club rankings on the specified page. | `.clublb 2`

View File

@ -16,6 +16,7 @@ If you do not see `credentials.json` you will need to rename `credentials_exampl
"GoogleApiKey": "AIzaSyDSci1sdlWQOWNVj1vlXxxxxxbk0oWMEzM",
"MashapeKey": "4UrKpcWXc2mshS8RKi00000y8Kf5p1Q8kI6jsn32bmd8oVWiY7",
"OsuApiKey": "4c8c8fdff8e1234581725db27fd140a7d93320d6",
"CleverbotApiKey": "",
"PatreonAccessToken": "",
"PatreonCampaignId": "334038",
"Db": null,
@ -47,7 +48,7 @@ If you do not see `credentials.json` you will need to rename `credentials_exampl
- Replace the **`12345678`** in this link:
`https://discordapp.com/oauth2/authorize?client_id=`**`12345678`**`&scope=bot&permissions=66186303` with your `Client ID`.
- The link should now look like this:
`https://discordapp.com/oauth2/authorize?client_id=`**`YOUR_CLENT_ID_HERE`**`&scope=bot&permissions=66186303`
`https://discordapp.com/oauth2/authorize?client_id=`**`YOUR_CLIENT_ID_HERE`**`&scope=bot&permissions=66186303`
- Go to the newly created link and pick the server we created, and click `Authorize`.
- The bot should have been added to your server.
@ -148,12 +149,15 @@ It should look like:
- Required for Urban Disctionary, Hashtag search, and Hearthstone cards.
- You need to create an account on their [api marketplace](https://market.mashape.com/), after that go to `market.mashape.com/YOURNAMEHERE/applications/default-application` and press **Get the keys** in the top right corner.
- Copy the key and paste it into `credentials.json`
- **LOLAPIKey**
- **LoLApiKey**
- Required for all League of Legends commands.
- You can get this key [here](http://api.champion.gg/)
- **OsuAPIKey**
- You can get this key [here.](http://api.champion.gg/)
- **OsuApiKey**
- Required for Osu commands
- You can get this key [here.](https://osu.ppy.sh/p/api)
- **CleverbotApiKey**
- Required if you want to use official cleverobot, instead of program-o
- you can get this key [here.](http://www.cleverbot.com/api/)
- **PatreonAccessToken**
- For Patreon creators only.
- **PatreonCampaignId**
@ -185,6 +189,8 @@ in order to open the database file you will need [DB Browser for SQLite](http://
- click on **Apply**
- click on **Write Changes**
![nadekodb](https://cdn.discordapp.com/attachments/251504306010849280/254067055240806400/nadekodb.gif)
and that will save all the changes.
## Sharding your bot
@ -205,7 +211,6 @@ and that will save all the changes.
- Bot uses a random UDP port in [5000, 6000) range for communication between shards
![nadekodb](https://cdn.discordapp.com/attachments/251504306010849280/254067055240806400/nadekodb.gif)
[Google Console]: https://console.developers.google.com
[DiscordApp]: https://discordapp.com/developers/applications/me

View File

@ -49,11 +49,11 @@ To allow users to only see the current song and have a DJ role for queuing follo
* Disables music commands for everybody
2. `.sc !!nowplaying enable`
2. `.sc .nowplaying enable`
* Enables the "nowplaying" command for everyone
3. `.sc !!listqueue enable`
3. `.sc .listqueue enable`
* Enables the "listqueue" command for everyone

View File

@ -10,7 +10,7 @@ For this guide we will be using the folder /nadeko as our config root folder.
```bash
docker create --name=nadeko -v /nadeko/conf/:/root/nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.1/data uirel/nadeko:1.4
```
-If you are coming from a previous version of nadeko (the old docker) make sure your crednetials.json has been copied into this directory and is the only thing in this folder.
-If you are coming from a previous version of nadeko (the old docker) make sure your credentials.json has been copied into this directory and is the only thing in this folder.
-If you are making a fresh install, create your credentials.json from the following guide and place it in the /nadeko folder [Nadeko JSON Guide](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/)
@ -21,7 +21,7 @@ Next start the docker up with
The docker will start and the log file will start scrolling past. Depending on hardware the bot start can take up to 5 minutes on a small DigitalOcean droplet.
Once the log ends with "NadekoBot | Starting NadekoBot v1.0-rc2" the bot is ready and can be invited to your server. Ctrl+C at this point to stop viewing the logs.
After a few moments you should be able to invite Nadeko to your server. If you cannot check the log file for errors
After a few moments you should be able to invite Nadeko to your server. If you cannot check the log file for errors.
## Monitoring

View File

@ -24,6 +24,8 @@ brew install opusfile
brew install libffi
brew install libsodium
brew install tmux
brew install python
brew install youtube-dl
```
#### Installing .NET Core SDK

View File

@ -1,9 +1,9 @@
#### If you have NadekoBot 1.x on Windows
- Go to `NadekoBot\src\NadekoBot` and backup your `credentials.json` file; then go to `NadekoBot\src\NadekoBot\bin\Release\netcoreapp1.0` and backup your `data` folder.
- Follow the [Windows Guide](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/) and install the latest version of **NadekoBot**.
- Navigate to your **old** `Nadeko` folder and copy your `credentials.json` file and the `data` folder.
- Paste credentials into the **NadekoBot 1.4x+** `C:\Program Files\NadekoBot\system` folder.
- Paste your **old** `Nadeko` data folder into **NadekoBot 1.4x+** `C:\Program Files\NadekoBot\system` folder.
- Paste your `credentials.json` file into the `C:\Program Files\NadekoBot\system` folder.
- Paste your `data` folder into `C:\Program Files\NadekoBot\system` folder.
- If it asks you to overwrite files, it is fine to do so.
- Next launch your **new** Nadeko as the guide describes, if it is not already running.

View File

@ -7,7 +7,7 @@
#### Guide
- Download and run the [NadekoBot Updater.][Updater]
- Press **`Install ffmpeg`** button if you want music features.
- Press **`Install ffmpeg`** and **`Install youtube-dl`** if you want music features.
***NOTE:** RESTART YOUR PC IF YOU DO.*
- Press **`Update`** and go through the installation wizard.
***NOTE:** If you're upgrading from 1.3, DO NOT select your old nadekobot folder. Install it in a separate directory and read the [upgrading guide](http://nadekobot.readthedocs.io/en/latest/guides/Upgrading%20Guide/).*

View File

@ -2,7 +2,7 @@
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace NadekoBot.DataStructures
namespace NadekoBot.Common
{
public class AsyncLazy<T> : Lazy<Task<T>>
{

View File

@ -1,9 +1,9 @@
using Discord.Commands;
using NadekoBot.Services;
using System.Linq;
using System.Linq;
using System.Runtime.CompilerServices;
using Discord.Commands;
using NadekoBot.Services.Impl;
namespace NadekoBot.Attributes
namespace NadekoBot.Common.Attributes
{
public class Aliases : AliasAttribute
{

View File

@ -1,8 +1,8 @@
using Discord.Commands;
using NadekoBot.Services;
using System.Runtime.CompilerServices;
using System.Runtime.CompilerServices;
using Discord.Commands;
using NadekoBot.Services.Impl;
namespace NadekoBot.Attributes
namespace NadekoBot.Common.Attributes
{
public class Description : SummaryAttribute
{

View File

@ -1,8 +1,8 @@
using Discord.Commands;
using NadekoBot.Services;
using System.Runtime.CompilerServices;
using System.Runtime.CompilerServices;
using Discord.Commands;
using NadekoBot.Services.Impl;
namespace NadekoBot.Attributes
namespace NadekoBot.Common.Attributes
{
public class NadekoCommand : CommandAttribute
{

View File

@ -1,7 +1,7 @@
using Discord.Commands;
using System;
using System;
using Discord.Commands;
namespace NadekoBot.Attributes
namespace NadekoBot.Common.Attributes
{
[AttributeUsage(AttributeTargets.Class)]
sealed class NadekoModuleAttribute : GroupAttribute

View File

@ -1,9 +1,9 @@
using System.Threading.Tasks;
using System;
using System.Threading.Tasks;
using Discord.Commands;
using System;
using NadekoBot.Services;
namespace NadekoBot.Attributes
namespace NadekoBot.Common.Attributes
{
public class OwnerOnlyAttribute : PreconditionAttribute
{

View File

@ -1,8 +1,8 @@
using Discord.Commands;
using NadekoBot.Services;
using System.Runtime.CompilerServices;
using System.Runtime.CompilerServices;
using Discord.Commands;
using NadekoBot.Services.Impl;
namespace NadekoBot.Attributes
namespace NadekoBot.Common.Attributes
{
public class Usage : RemarksAttribute
{

View File

@ -0,0 +1,26 @@
namespace NadekoBot.Common
{
public enum BotConfigEditType
{
BetflipMultiplier,
Betroll100Multiplier,
Betroll67Multiplier,
Betroll91Multiplier,
CurrencyGenerationChance,
CurrencyGenerationCooldown,
CurrencyName,
CurrencyPluralName,
CurrencySign,
DmHelpString,
HelpString,
CurrencyDropAmount,
CurrencyDropAmountMax,
MinimumBetAmount,
TriviaCurrencyReward,
XpPerMessage,
XpMinutesTimeout,
//ErrorColor, //after i fix the nadekobot.cs static variables
//OkColor
}
}

View File

@ -1,8 +1,10 @@
using Discord;
using System;
using Discord;
using NadekoBot.Extensions;
using Newtonsoft.Json;
using NLog;
namespace NadekoBot.DataStructures
namespace NadekoBot.Common
{
public class CREmbed
{
@ -31,19 +33,31 @@ namespace NadekoBot.DataStructures
public EmbedBuilder ToEmbed()
{
var embed = new EmbedBuilder()
.WithTitle(Title)
.WithDescription(Description)
.WithColor(new Discord.Color(Color));
var embed = new EmbedBuilder();
if (!string.IsNullOrWhiteSpace(Title))
embed.WithTitle(Title);
if (!string.IsNullOrWhiteSpace(Description))
embed.WithDescription(Description);
embed.WithColor(new Discord.Color(Color));
if (Footer != null)
embed.WithFooter(efb => efb.WithIconUrl(Footer.IconUrl).WithText(Footer.Text));
embed.WithThumbnailUrl(Thumbnail)
.WithImageUrl(Image);
embed.WithFooter(efb =>
{
efb.WithText(Footer.Text);
if (Uri.IsWellFormedUriString(Footer.IconUrl, UriKind.Absolute))
efb.WithIconUrl(Footer.IconUrl);
});
if (Thumbnail != null && Uri.IsWellFormedUriString(Thumbnail, UriKind.Absolute))
embed.WithThumbnailUrl(Thumbnail);
if(Image != null && Uri.IsWellFormedUriString(Image, UriKind.Absolute))
embed.WithImageUrl(Image);
if (Fields != null)
foreach (var f in Fields)
{
embed.AddField(efb => efb.WithName(f.Name).WithValue(f.Value).WithIsInline(f.Inline));
if(!string.IsNullOrWhiteSpace(f.Name) && !string.IsNullOrWhiteSpace(f.Value))
embed.AddField(efb => efb.WithName(f.Name).WithValue(f.Value).WithIsInline(f.Inline));
}
return embed;
@ -59,6 +73,12 @@ namespace NadekoBot.DataStructures
{
var crembed = JsonConvert.DeserializeObject<CREmbed>(input);
if(crembed.Fields != null && crembed.Fields.Length > 0)
foreach (var f in crembed.Fields)
{
f.Name = f.Name.TrimTo(256);
f.Value = f.Value.TrimTo(1024);
}
if (!crembed.IsValid)
return false;

View File

@ -1,13 +1,14 @@
// License MIT
// Source: https://github.com/i3arnon/ConcurrentHashSet
using ConcurrentCollections;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace System.Collections.Concurrent
namespace NadekoBot.Common.Collections
{
/// <summary>
/// Represents a thread-safe hash-based unique collection.

View File

@ -2,9 +2,8 @@
using System.Collections;
using System.Collections.Generic;
namespace NadekoBot.DataStructures
namespace NadekoBot.Common.Collections
{
public static class DisposableReadOnlyListExtensions
{
public static IDisposableReadOnlyList<T> AsDisposable<T>(this IReadOnlyList<T> arr) where T : IDisposable

View File

@ -1,11 +1,11 @@
using NadekoBot.Services.Database.Models;
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NadekoBot.Services.Database.Models;
namespace NadekoBot.DataStructures
namespace NadekoBot.Common.Collections
{
public class IndexedCollection<T> : IList<T> where T : IIndexed
public class IndexedCollection<T> : IList<T> where T : class, IIndexed
{
public List<T> Source { get; }
private readonly object _locker = new object();

View File

@ -1,29 +1,19 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace NadekoBot.DataStructures
namespace NadekoBot.Common.Collections
{
public class PoopyRingBuffer : IDisposable
{
// readpos == writepos means empty
// writepos == readpos - 1 means full
private byte[] buffer;
private byte[] _buffer;
public int Capacity { get; }
private int _readPos = 0;
private int ReadPos
{
get => _readPos;
set => _readPos = value;
}
private int _writePos = 0;
private int WritePos
{
get => _writePos;
set => _writePos = value;
}
private int ReadPos { get; set; } = 0;
private int WritePos { get; set; } = 0;
public int Length => ReadPos <= WritePos
? WritePos - ReadPos
: Capacity - (ReadPos - WritePos);
@ -38,7 +28,7 @@ namespace NadekoBot.DataStructures
public PoopyRingBuffer(int capacity = 81920 * 100)
{
this.Capacity = capacity + 1;
this.buffer = new byte[this.Capacity];
this._buffer = new byte[this.Capacity];
}
public int Read(byte[] b, int offset, int toRead)
@ -51,7 +41,7 @@ namespace NadekoBot.DataStructures
if (WritePos > ReadPos)
{
Array.Copy(buffer, ReadPos, b, offset, toRead);
Array.Copy(_buffer, ReadPos, b, offset, toRead);
ReadPos += toRead;
}
else
@ -60,12 +50,12 @@ namespace NadekoBot.DataStructures
var firstRead = toRead > toEnd ?
toEnd :
toRead;
Array.Copy(buffer, ReadPos, b, offset, firstRead);
Array.Copy(_buffer, ReadPos, b, offset, firstRead);
ReadPos += firstRead;
var secondRead = toRead - firstRead;
if (secondRead > 0)
{
Array.Copy(buffer, 0, b, offset + firstRead, secondRead);
Array.Copy(_buffer, 0, b, offset + firstRead, secondRead);
ReadPos = secondRead;
}
}
@ -82,7 +72,7 @@ namespace NadekoBot.DataStructures
if (WritePos < ReadPos)
{
Array.Copy(b, offset, buffer, WritePos, toWrite);
Array.Copy(b, offset, _buffer, WritePos, toWrite);
WritePos += toWrite;
}
else
@ -91,11 +81,11 @@ namespace NadekoBot.DataStructures
var firstWrite = toWrite > toEnd ?
toEnd :
toWrite;
Array.Copy(b, offset, buffer, WritePos, firstWrite);
Array.Copy(b, offset, _buffer, WritePos, firstWrite);
var secondWrite = toWrite - firstWrite;
if (secondWrite > 0)
{
Array.Copy(b, offset + firstWrite, buffer, 0, secondWrite);
Array.Copy(b, offset + firstWrite, _buffer, 0, secondWrite);
WritePos = secondWrite;
}
else
@ -110,7 +100,7 @@ namespace NadekoBot.DataStructures
public void Dispose()
{
buffer = null;
_buffer = null;
}
}
}

View File

@ -1,7 +1,7 @@
using Discord;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Discord;
namespace NadekoBot.DataStructures.ModuleBehaviors
namespace NadekoBot.Common.ModuleBehaviors
{
/// <summary>
/// Implemented by modules which block execution before anything is executed

View File

@ -1,8 +1,8 @@
using Discord;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
using System.Threading.Tasks;
namespace NadekoBot.DataStructures.ModuleBehaviors
namespace NadekoBot.Common.ModuleBehaviors
{
/// <summary>
/// Implemented by modules which can execute something and prevent further commands from being executed.

View File

@ -1,4 +1,4 @@
namespace NadekoBot.DataStructures.ModuleBehaviors
namespace NadekoBot.Common.ModuleBehaviors
{
public interface IEarlyExecutor
{

View File

@ -1,7 +1,7 @@
using Discord;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Discord;
namespace NadekoBot.DataStructures.ModuleBehaviors
namespace NadekoBot.Common.ModuleBehaviors
{
public interface IInputTransformer
{

View File

@ -1,8 +1,8 @@
using Discord;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
using System.Threading.Tasks;
namespace NadekoBot.DataStructures.ModuleBehaviors
namespace NadekoBot.Common.ModuleBehaviors
{
public interface ILateBlocker
{

View File

@ -1,4 +1,4 @@
namespace NadekoBot.DataStructures.ModuleBehaviors
namespace NadekoBot.Common.ModuleBehaviors
{
public interface ILateBlockingExecutor
{

View File

@ -1,8 +1,8 @@
using Discord;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
using System.Threading.Tasks;
namespace NadekoBot.DataStructures.ModuleBehaviors
namespace NadekoBot.Common.ModuleBehaviors
{
/// <summary>
/// Last thing to be executed, won't stop further executions

View File

@ -1,26 +1,21 @@
using System;
using System.Security.Cryptography;
namespace NadekoBot.Services
namespace NadekoBot.Common
{
public class NadekoRandom : Random
{
RandomNumberGenerator rng;
readonly RandomNumberGenerator _rng;
public NadekoRandom() : base()
{
rng = RandomNumberGenerator.Create();
}
private NadekoRandom(int Seed) : base(Seed)
{
rng = RandomNumberGenerator.Create();
_rng = RandomNumberGenerator.Create();
}
public override int Next()
{
var bytes = new byte[sizeof(int)];
rng.GetBytes(bytes);
_rng.GetBytes(bytes);
return Math.Abs(BitConverter.ToInt32(bytes, 0));
}
@ -29,7 +24,7 @@ namespace NadekoBot.Services
if (maxValue <= 0)
throw new ArgumentOutOfRangeException();
var bytes = new byte[sizeof(int)];
rng.GetBytes(bytes);
_rng.GetBytes(bytes);
return Math.Abs(BitConverter.ToInt32(bytes, 0)) % maxValue;
}
@ -40,27 +35,27 @@ namespace NadekoBot.Services
if (minValue == maxValue)
return minValue;
var bytes = new byte[sizeof(int)];
rng.GetBytes(bytes);
_rng.GetBytes(bytes);
var sign = Math.Sign(BitConverter.ToInt32(bytes, 0));
return (sign * BitConverter.ToInt32(bytes, 0)) % (maxValue - minValue) + minValue;
}
public override void NextBytes(byte[] buffer)
{
rng.GetBytes(buffer);
_rng.GetBytes(buffer);
}
protected override double Sample()
{
var bytes = new byte[sizeof(double)];
rng.GetBytes(bytes);
_rng.GetBytes(bytes);
return Math.Abs(BitConverter.ToDouble(bytes, 0) / double.MaxValue + 1);
}
public override double NextDouble()
{
var bytes = new byte[sizeof(double)];
rng.GetBytes(bytes);
_rng.GetBytes(bytes);
return BitConverter.ToDouble(bytes, 0);
}
}

View File

@ -1,8 +1,8 @@
using Discord.Commands;
using System;
using System;
using System.Threading.Tasks;
using Discord.Commands;
namespace NadekoBot.DataStructures
namespace NadekoBot.Common
{
public class NoPublicBot : PreconditionAttribute
{

View File

@ -1,6 +1,6 @@
using System;
namespace ConcurrentCollections
namespace NadekoBot.Common
{
public static class PlatformHelper
{

View File

@ -1,16 +1,15 @@
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using NadekoBot.Extensions;
using NadekoBot.Services;
using NadekoBot.Services.Administration;
using NadekoBot.Services.Music;
using System;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Text.RegularExpressions;
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using NadekoBot.Extensions;
using NadekoBot.Modules.Administration.Services;
using NadekoBot.Modules.Music.Services;
namespace NadekoBot.DataStructures.Replacements
namespace NadekoBot.Common.Replacements
{
public class ReplacementBuilder
{

View File

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace NadekoBot.DataStructures.Replacements
namespace NadekoBot.Common.Replacements
{
public class Replacer
{

View File

@ -1,22 +1,19 @@
using Discord.Commands;
using Discord.WebSocket;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Threading.Tasks;
using Discord.Commands;
using Discord.WebSocket;
namespace NadekoBot.DataStructures
namespace NadekoBot.Common
{
public class Shard0Precondition : PreconditionAttribute
{
public override Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo command, IServiceProvider services)
{
var c = (DiscordSocketClient)context.Client;
if (c.ShardId == 0)
return Task.FromResult(PreconditionResult.FromSuccess());
else
if (c.ShardId != 0)
return Task.FromResult(PreconditionResult.FromError("Must be ran from shard #0"));
return Task.FromResult(PreconditionResult.FromSuccess());
}
}
}

View File

@ -1,11 +1,7 @@
using Discord;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using Discord;
namespace NadekoBot.DataStructures.ShardCom
namespace NadekoBot.Common.ShardCom
{
public class ShardComMessage
{

View File

@ -1,11 +1,10 @@
using Newtonsoft.Json;
using System;
using System.Net;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace NadekoBot.DataStructures.ShardCom
namespace NadekoBot.Common.ShardCom
{
public class ShardComClient
{

View File

@ -1,11 +1,11 @@
using Newtonsoft.Json;
using System;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace NadekoBot.DataStructures.ShardCom
namespace NadekoBot.Common.ShardCom
{
public class ShardComServer : IDisposable
{

View File

@ -0,0 +1,9 @@
namespace NadekoBot.Common.TypeReaders
{
public enum AddRemove
{
Add = 0,
Rem = 1,
Rm = 1,
}
}

View File

@ -1,25 +1,18 @@
using Discord.Commands;
using NadekoBot.Services;
using NadekoBot.Services.CustomReactions;
using System;
using System;
using System.Linq;
using System.Threading.Tasks;
using Discord.Commands;
using NadekoBot.Modules.CustomReactions.Services;
using NadekoBot.Services;
namespace NadekoBot.TypeReaders
namespace NadekoBot.Common.TypeReaders
{
public class CommandTypeReader : TypeReader
{
private readonly CommandService _cmds;
private readonly CommandHandler _cmdHandler;
public CommandTypeReader(CommandService cmds, CommandHandler cmdHandler)
{
_cmds = cmds;
_cmdHandler = cmdHandler;
}
public override Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider _)
public override Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
{
var _cmds = ((INServiceProvider)services).GetService<CommandService>();
var _cmdHandler = ((INServiceProvider)services).GetService<CommandHandler>();
input = input.ToUpperInvariant();
var prefix = _cmdHandler.GetPrefix(context.Guild);
if (!input.StartsWith(prefix.ToUpperInvariant()))
@ -38,17 +31,12 @@ namespace NadekoBot.TypeReaders
public class CommandOrCrTypeReader : CommandTypeReader
{
private readonly CustomReactionsService _crs;
public CommandOrCrTypeReader(CustomReactionsService crs, CommandService cmds, CommandHandler cmdHandler) : base(cmds, cmdHandler)
{
_crs = crs;
}
public override async Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider _)
public override async Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
{
input = input.ToUpperInvariant();
var _crs = ((INServiceProvider)services).GetService<CustomReactionsService>();
if (_crs.GlobalReactions.Any(x => x.Trigger.ToUpperInvariant() == input))
{
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input));
@ -65,7 +53,7 @@ namespace NadekoBot.TypeReaders
}
}
var cmd = await base.Read(context, input, _);
var cmd = await base.Read(context, input, services);
if (cmd.IsSuccess)
{
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Name));

View File

@ -1,21 +1,15 @@
using Discord.Commands;
using NadekoBot.Services.Administration;
using System;
using System;
using System.Threading.Tasks;
using Discord.Commands;
using NadekoBot.Modules.Administration.Services;
namespace NadekoBot.TypeReaders
namespace NadekoBot.Common.TypeReaders
{
public class GuildDateTimeTypeReader : TypeReader
{
private readonly GuildTimezoneService _gts;
public GuildDateTimeTypeReader(GuildTimezoneService gts)
{
_gts = gts;
}
public override Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider _)
public override Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
{
var _gts = (GuildTimezoneService)services.GetService(typeof(GuildTimezoneService));
if (!DateTime.TryParse(input, out var dt))
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Input string is in an incorrect format."));

View File

@ -1,10 +1,10 @@
using Discord.Commands;
using Discord.WebSocket;
using System;
using System;
using System.Linq;
using System.Threading.Tasks;
using Discord.Commands;
using Discord.WebSocket;
namespace NadekoBot.TypeReaders
namespace NadekoBot.Common.TypeReaders
{
public class GuildTypeReader : TypeReader
{

View File

@ -1,4 +1,4 @@
namespace NadekoBot.Modules.Permissions
namespace NadekoBot.Common.TypeReaders.Models
{
public class PermissionAction
{

View File

@ -1,10 +1,10 @@
using Discord.Commands;
using NadekoBot.Extensions;
using System;
using System;
using System.Linq;
using System.Threading.Tasks;
using Discord.Commands;
using NadekoBot.Extensions;
namespace NadekoBot.TypeReaders
namespace NadekoBot.Common.TypeReaders
{
public class ModuleTypeReader : TypeReader
{

View File

@ -1,9 +1,9 @@
using Discord.Commands;
using System;
using System.Threading.Tasks;
using NadekoBot.Modules.Permissions;
using System;
using Discord.Commands;
using NadekoBot.Common.TypeReaders.Models;
namespace NadekoBot.TypeReaders
namespace NadekoBot.Common.TypeReaders
{
/// <summary>
/// Used instead of bool for more flexible keywords for true/false only in the permission module

View File

@ -1,23 +0,0 @@
using Discord.Commands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.DataStructures
{
//public class SyncPrecondition : PreconditionAttribute
//{
// public override Task<PreconditionResult> CheckPermissions(ICommandContext context,
// CommandInfo command,
// IServiceProvider services)
// {
// }
//}
//public enum SyncType
//{
// Guild
//}
}

View File

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations

View File

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{

View File

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,45 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class streamrole : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "StreamRoleSettings",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
AddRoleId = table.Column<ulong>(nullable: false),
DateAdded = table.Column<DateTime>(nullable: true),
FromRoleId = table.Column<ulong>(nullable: false),
GuildConfigId = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_StreamRoleSettings", x => x.Id);
table.ForeignKey(
name: "FK_StreamRoleSettings_GuildConfigs_GuildConfigId",
column: x => x.GuildConfigId,
principalTable: "GuildConfigs",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_StreamRoleSettings_GuildConfigId",
table: "StreamRoleSettings",
column: "GuildConfigId",
unique: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "StreamRoleSettings");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class streamrolekwblwl : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "Enabled",
table: "StreamRoleSettings",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<string>(
name: "Keyword",
table: "StreamRoleSettings",
nullable: true);
migrationBuilder.CreateTable(
name: "StreamRoleBlacklistedUser",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
DateAdded = table.Column<DateTime>(nullable: true),
StreamRoleSettingsId = table.Column<int>(nullable: true),
UserId = table.Column<ulong>(nullable: false),
Username = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_StreamRoleBlacklistedUser", x => x.Id);
table.ForeignKey(
name: "FK_StreamRoleBlacklistedUser_StreamRoleSettings_StreamRoleSettingsId",
column: x => x.StreamRoleSettingsId,
principalTable: "StreamRoleSettings",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "StreamRoleWhitelistedUser",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
DateAdded = table.Column<DateTime>(nullable: true),
StreamRoleSettingsId = table.Column<int>(nullable: true),
UserId = table.Column<ulong>(nullable: false),
Username = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_StreamRoleWhitelistedUser", x => x.Id);
table.ForeignKey(
name: "FK_StreamRoleWhitelistedUser_StreamRoleSettings_StreamRoleSettingsId",
column: x => x.StreamRoleSettingsId,
principalTable: "StreamRoleSettings",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_StreamRoleBlacklistedUser_StreamRoleSettingsId",
table: "StreamRoleBlacklistedUser",
column: "StreamRoleSettingsId");
migrationBuilder.CreateIndex(
name: "IX_StreamRoleWhitelistedUser_StreamRoleSettingsId",
table: "StreamRoleWhitelistedUser",
column: "StreamRoleSettingsId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "StreamRoleBlacklistedUser");
migrationBuilder.DropTable(
name: "StreamRoleWhitelistedUser");
migrationBuilder.DropColumn(
name: "Enabled",
table: "StreamRoleSettings");
migrationBuilder.DropColumn(
name: "Keyword",
table: "StreamRoleSettings");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class nsfwblacklist : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "NsfwBlacklitedTag",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
DateAdded = table.Column<DateTime>(nullable: true),
GuildConfigId = table.Column<int>(nullable: true),
Tag = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_NsfwBlacklitedTag", x => x.Id);
table.ForeignKey(
name: "FK_NsfwBlacklitedTag_GuildConfigs_GuildConfigId",
column: x => x.GuildConfigId,
principalTable: "GuildConfigs",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_NsfwBlacklitedTag_GuildConfigId",
table: "NsfwBlacklitedTag",
column: "GuildConfigId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "NsfwBlacklitedTag");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class crca : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "ContainsAnywhere",
table: "CustomReactions",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ContainsAnywhere",
table: "CustomReactions");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class waifuitems : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "WaifuItem",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
DateAdded = table.Column<DateTime>(nullable: true),
Item = table.Column<int>(nullable: false),
ItemEmoji = table.Column<string>(nullable: true),
Price = table.Column<int>(nullable: false),
WaifuInfoId = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_WaifuItem", x => x.Id);
table.ForeignKey(
name: "FK_WaifuItem_WaifuInfo_WaifuInfoId",
column: x => x.WaifuInfoId,
principalTable: "WaifuInfo",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_WaifuItem_WaifuInfoId",
table: "WaifuItem",
column: "WaifuInfoId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "WaifuItem");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class mutetimeantispam : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "MuteTime",
table: "AntiSpamSetting",
nullable: false,
defaultValue: 0);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MuteTime",
table: "AntiSpamSetting");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,296 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class xpandclubs : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "XpMinutesTimeout",
table: "BotConfig",
nullable: false,
defaultValue: 5)
.Annotation("Sqlite:Autoincrement", true);
migrationBuilder.AddColumn<int>(
name: "XpPerMessage",
table: "BotConfig",
nullable: false,
defaultValue: 3)
.Annotation("Sqlite:Autoincrement", true);
migrationBuilder.CreateTable(
name: "Clubs",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
DateAdded = table.Column<DateTime>(nullable: true),
Discrim = table.Column<int>(nullable: false),
ImageUrl = table.Column<string>(nullable: true),
MinimumLevelReq = table.Column<int>(nullable: false),
Name = table.Column<string>(maxLength: 20, nullable: false),
OwnerId = table.Column<int>(nullable: false),
Xp = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Clubs", x => x.Id);
table.UniqueConstraint("AK_Clubs_Name_Discrim", x => new { x.Name, x.Discrim });
table.ForeignKey(
name: "FK_Clubs_DiscordUser_OwnerId",
column: x => x.OwnerId,
principalTable: "DiscordUser",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.Sql(MigrationQueries.UserClub);
migrationBuilder.AddColumn<DateTime>(
name: "LastLevelUp",
table: "DiscordUser",
nullable: false,
defaultValue: DateTime.UtcNow);
migrationBuilder.AddColumn<int>(
name: "NotifyOnLevelUp",
table: "DiscordUser",
nullable: false,
defaultValue: 0);
migrationBuilder.CreateTable(
name: "UserXpStats",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
AwardedXp = table.Column<int>(nullable: false),
DateAdded = table.Column<DateTime>(nullable: true),
GuildId = table.Column<ulong>(nullable: false),
LastLevelUp = table.Column<DateTime>(nullable: false, defaultValue: new DateTime(2017, 9, 9, 1, 7, 29, 858, DateTimeKind.Local)),
NotifyOnLevelUp = table.Column<int>(nullable: false),
UserId = table.Column<ulong>(nullable: false),
Xp = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_UserXpStats", x => x.Id);
});
migrationBuilder.CreateTable(
name: "XpSettings",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
DateAdded = table.Column<DateTime>(nullable: true),
GuildConfigId = table.Column<int>(nullable: false),
NotifyMessage = table.Column<string>(nullable: true),
ServerExcluded = table.Column<bool>(nullable: false),
XpRoleRewardExclusive = table.Column<bool>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_XpSettings", x => x.Id);
table.ForeignKey(
name: "FK_XpSettings_GuildConfigs_GuildConfigId",
column: x => x.GuildConfigId,
principalTable: "GuildConfigs",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClubApplicants",
columns: table => new
{
ClubId = table.Column<int>(nullable: false),
UserId = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClubApplicants", x => new { x.ClubId, x.UserId });
table.ForeignKey(
name: "FK_ClubApplicants_Clubs_ClubId",
column: x => x.ClubId,
principalTable: "Clubs",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ClubApplicants_DiscordUser_UserId",
column: x => x.UserId,
principalTable: "DiscordUser",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClubBans",
columns: table => new
{
ClubId = table.Column<int>(nullable: false),
UserId = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClubBans", x => new { x.ClubId, x.UserId });
table.ForeignKey(
name: "FK_ClubBans_Clubs_ClubId",
column: x => x.ClubId,
principalTable: "Clubs",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ClubBans_DiscordUser_UserId",
column: x => x.UserId,
principalTable: "DiscordUser",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ExcludedItem",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
DateAdded = table.Column<DateTime>(nullable: true),
ItemId = table.Column<ulong>(nullable: false),
ItemType = table.Column<int>(nullable: false),
XpSettingsId = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ExcludedItem", x => x.Id);
table.ForeignKey(
name: "FK_ExcludedItem_XpSettings_XpSettingsId",
column: x => x.XpSettingsId,
principalTable: "XpSettings",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "XpRoleReward",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
DateAdded = table.Column<DateTime>(nullable: true),
Level = table.Column<int>(nullable: false),
RoleId = table.Column<ulong>(nullable: false),
XpSettingsId = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_XpRoleReward", x => x.Id);
table.UniqueConstraint("AK_XpRoleReward_Level", x => x.Level);
table.ForeignKey(
name: "FK_XpRoleReward_XpSettings_XpSettingsId",
column: x => x.XpSettingsId,
principalTable: "XpSettings",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_DiscordUser_ClubId",
table: "DiscordUser",
column: "ClubId");
migrationBuilder.CreateIndex(
name: "IX_ClubApplicants_UserId",
table: "ClubApplicants",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_ClubBans_UserId",
table: "ClubBans",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_Clubs_OwnerId",
table: "Clubs",
column: "OwnerId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ExcludedItem_XpSettingsId",
table: "ExcludedItem",
column: "XpSettingsId");
migrationBuilder.CreateIndex(
name: "IX_UserXpStats_UserId_GuildId",
table: "UserXpStats",
columns: new[] { "UserId", "GuildId" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_XpRoleReward_XpSettingsId",
table: "XpRoleReward",
column: "XpSettingsId");
migrationBuilder.CreateIndex(
name: "IX_XpSettings_GuildConfigId",
table: "XpSettings",
column: "GuildConfigId",
unique: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_DiscordUser_Clubs_ClubId",
table: "DiscordUser");
migrationBuilder.DropTable(
name: "ClubApplicants");
migrationBuilder.DropTable(
name: "ClubBans");
migrationBuilder.DropTable(
name: "ExcludedItem");
migrationBuilder.DropTable(
name: "UserXpStats");
migrationBuilder.DropTable(
name: "XpRoleReward");
migrationBuilder.DropTable(
name: "Clubs");
migrationBuilder.DropTable(
name: "XpSettings");
migrationBuilder.DropIndex(
name: "IX_DiscordUser_ClubId",
table: "DiscordUser");
migrationBuilder.DropColumn(
name: "ClubId",
table: "DiscordUser");
migrationBuilder.DropColumn(
name: "LastLevelUp",
table: "DiscordUser");
migrationBuilder.DropColumn(
name: "NotifyOnLevelUp",
table: "DiscordUser");
migrationBuilder.DropColumn(
name: "XpMinutesTimeout",
table: "BotConfig");
migrationBuilder.DropColumn(
name: "XpPerMessage",
table: "BotConfig");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class lastXpGain : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "LastXpGain",
table: "DiscordUser",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.Sql("DELETE FROM XpRoleReward WHERE XpSettingsId is null");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "LastXpGain",
table: "DiscordUser");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class totalxp : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "TotalXp",
table: "DiscordUser",
nullable: false,
defaultValue: 0);
migrationBuilder.Sql(MigrationQueries.TotalXp);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "TotalXp",
table: "DiscordUser");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class clubadmins : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsClubAdmin",
table: "DiscordUser",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsClubAdmin",
table: "DiscordUser");
}
}
}

View File

@ -0,0 +1,42 @@
namespace NadekoBot.Migrations
{
internal class MigrationQueries
{
public static string UserClub { get; } = @"
CREATE TABLE DiscordUser_tmp(
Id INTEGER PRIMARY KEY,
AvatarId TEXT,
Discriminator TEXT,
UserId INTEGER UNIQUE NOT NULL,
DateAdded TEXT,
Username TEXT
);
INSERT INTO DiscordUser_tmp
SELECT Id, AvatarId, Discriminator, UserId, DateAdded, Username
FROM DiscordUser;
DROP TABLE DiscordUser;
CREATE TABLE DiscordUser(
Id INTEGER PRIMARY KEY,
AvatarId TEXT,
Discriminator TEXT,
UserId INTEGER UNIQUE NOT NULL,
DateAdded TEXT,
Username TEXT,
ClubId INTEGER,
CONSTRAINT FK_DiscordUser_Clubs_ClubId FOREIGN KEY(ClubId) REFERENCES Clubs(Id) ON DELETE RESTRICT
);
INSERT INTO DiscordUser
SELECT Id, AvatarId, Discriminator, UserId, DateAdded, Username, NULL
FROM DiscordUser_tmp;
DROP TABLE DiscordUser_tmp;";
public static string TotalXp { get; } =
@"UPDATE DiscordUser
SET TotalXp = ifnull((SELECT SUM(Xp) FROM UserXpStats WHERE UserId = DiscordUser.UserId), 0)";
}
}

View File

@ -70,6 +70,8 @@ namespace NadekoBot.Migrations
b.Property<int>("MessageThreshold");
b.Property<int>("MuteTime");
b.HasKey("Id");
b.HasIndex("GuildConfigId")
@ -181,6 +183,14 @@ namespace NadekoBot.Migrations
b.Property<int>("TriviaCurrencyReward");
b.Property<int>("XpMinutesTimeout")
.ValueGeneratedOnAdd()
.HasDefaultValue(5);
b.Property<int>("XpPerMessage")
.ValueGeneratedOnAdd()
.HasDefaultValue(3);
b.HasKey("Id");
b.ToTable("BotConfig");
@ -236,6 +246,63 @@ namespace NadekoBot.Migrations
b.ToTable("ClashOfClans");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClubApplicants", b =>
{
b.Property<int>("ClubId");
b.Property<int>("UserId");
b.HasKey("ClubId", "UserId");
b.HasIndex("UserId");
b.ToTable("ClubApplicants");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClubBans", b =>
{
b.Property<int>("ClubId");
b.Property<int>("UserId");
b.HasKey("ClubId", "UserId");
b.HasIndex("UserId");
b.ToTable("ClubBans");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClubInfo", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime?>("DateAdded");
b.Property<int>("Discrim");
b.Property<string>("ImageUrl");
b.Property<int>("MinimumLevelReq");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(20);
b.Property<int>("OwnerId");
b.Property<int>("Xp");
b.HasKey("Id");
b.HasAlternateKey("Name", "Discrim");
b.HasIndex("OwnerId")
.IsUnique();
b.ToTable("Clubs");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b =>
{
b.Property<int>("Id")
@ -361,6 +428,8 @@ namespace NadekoBot.Migrations
b.Property<bool>("AutoDeleteTrigger");
b.Property<bool>("ContainsAnywhere");
b.Property<DateTime?>("DateAdded");
b.Property<bool>("DmResponse");
@ -387,10 +456,24 @@ namespace NadekoBot.Migrations
b.Property<string>("AvatarId");
b.Property<int?>("ClubId");
b.Property<DateTime?>("DateAdded");
b.Property<string>("Discriminator");
b.Property<bool>("IsClubAdmin");
b.Property<DateTime>("LastLevelUp")
.ValueGeneratedOnAdd()
.HasDefaultValue(new DateTime(2017, 9, 15, 5, 48, 8, 660, DateTimeKind.Local));
b.Property<DateTime>("LastXpGain");
b.Property<int>("NotifyOnLevelUp");
b.Property<int>("TotalXp");
b.Property<ulong>("UserId");
b.Property<string>("Username");
@ -399,6 +482,8 @@ namespace NadekoBot.Migrations
b.HasAlternateKey("UserId");
b.HasIndex("ClubId");
b.ToTable("DiscordUser");
});
@ -441,6 +526,26 @@ namespace NadekoBot.Migrations
b.ToTable("EightBallResponses");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ExcludedItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime?>("DateAdded");
b.Property<ulong>("ItemId");
b.Property<int>("ItemType");
b.Property<int?>("XpSettingsId");
b.HasKey("Id");
b.HasIndex("XpSettingsId");
b.ToTable("ExcludedItem");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
{
b.Property<int>("Id")
@ -800,6 +905,24 @@ namespace NadekoBot.Migrations
b.ToTable("MutedUserId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.NsfwBlacklitedTag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime?>("DateAdded");
b.Property<int?>("GuildConfigId");
b.Property<string>("Tag");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("NsfwBlacklitedTag");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b =>
{
b.Property<int>("Id")
@ -1126,6 +1249,71 @@ namespace NadekoBot.Migrations
b.ToTable("StartupCommand");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleBlacklistedUser", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime?>("DateAdded");
b.Property<int?>("StreamRoleSettingsId");
b.Property<ulong>("UserId");
b.Property<string>("Username");
b.HasKey("Id");
b.HasIndex("StreamRoleSettingsId");
b.ToTable("StreamRoleBlacklistedUser");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleSettings", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AddRoleId");
b.Property<DateTime?>("DateAdded");
b.Property<bool>("Enabled");
b.Property<ulong>("FromRoleId");
b.Property<int>("GuildConfigId");
b.Property<string>("Keyword");
b.HasKey("Id");
b.HasIndex("GuildConfigId")
.IsUnique();
b.ToTable("StreamRoleSettings");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleWhitelistedUser", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime?>("DateAdded");
b.Property<int?>("StreamRoleSettingsId");
b.Property<ulong>("UserId");
b.Property<string>("Username");
b.HasKey("Id");
b.HasIndex("StreamRoleSettingsId");
b.ToTable("StreamRoleWhitelistedUser");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b =>
{
b.Property<int>("Id")
@ -1165,6 +1353,35 @@ namespace NadekoBot.Migrations
b.ToTable("PokeGame");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.UserXpStats", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AwardedXp");
b.Property<DateTime?>("DateAdded");
b.Property<ulong>("GuildId");
b.Property<DateTime>("LastLevelUp")
.ValueGeneratedOnAdd()
.HasDefaultValue(new DateTime(2017, 9, 15, 5, 48, 8, 665, DateTimeKind.Local));
b.Property<int>("NotifyOnLevelUp");
b.Property<ulong>("UserId");
b.Property<int>("Xp");
b.HasKey("Id");
b.HasIndex("UserId", "GuildId")
.IsUnique();
b.ToTable("UserXpStats");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b =>
{
b.Property<int>("Id")
@ -1212,6 +1429,28 @@ namespace NadekoBot.Migrations
b.ToTable("WaifuInfo");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime?>("DateAdded");
b.Property<int>("Item");
b.Property<string>("ItemEmoji");
b.Property<int>("Price");
b.Property<int?>("WaifuInfoId");
b.HasKey("Id");
b.HasIndex("WaifuInfoId");
b.ToTable("WaifuItem");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b =>
{
b.Property<int>("Id")
@ -1284,6 +1523,51 @@ namespace NadekoBot.Migrations
b.ToTable("WarningPunishment");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.XpRoleReward", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime?>("DateAdded");
b.Property<int>("Level");
b.Property<ulong>("RoleId");
b.Property<int?>("XpSettingsId");
b.HasKey("Id");
b.HasAlternateKey("Level");
b.HasIndex("XpSettingsId");
b.ToTable("XpRoleReward");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.XpSettings", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime?>("DateAdded");
b.Property<int>("GuildConfigId");
b.Property<string>("NotifyMessage");
b.Property<bool>("ServerExcluded");
b.Property<bool>("XpRoleRewardExclusive");
b.HasKey("Id");
b.HasIndex("GuildConfigId")
.IsUnique();
b.ToTable("XpSettings");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig")
@ -1333,6 +1617,40 @@ namespace NadekoBot.Migrations
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClubApplicants", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.ClubInfo", "Club")
.WithMany("Applicants")
.HasForeignKey("ClubId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClubBans", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.ClubInfo", "Club")
.WithMany("Bans")
.HasForeignKey("ClubId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClubInfo", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Owner")
.WithOne()
.HasForeignKey("NadekoBot.Services.Database.Models.ClubInfo", "OwnerId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
@ -1354,6 +1672,13 @@ namespace NadekoBot.Migrations
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordUser", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.ClubInfo", "Club")
.WithMany("Users")
.HasForeignKey("ClubId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
@ -1361,6 +1686,13 @@ namespace NadekoBot.Migrations
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ExcludedItem", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.XpSettings")
.WithMany("ExclusionList")
.HasForeignKey("XpSettingsId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
@ -1439,6 +1771,13 @@ namespace NadekoBot.Migrations
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.NsfwBlacklitedTag", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
.WithMany("NsfwBlacklistedTags")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next")
@ -1510,6 +1849,28 @@ namespace NadekoBot.Migrations
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleBlacklistedUser", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.StreamRoleSettings")
.WithMany("Blacklist")
.HasForeignKey("StreamRoleSettingsId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleSettings", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig")
.WithOne("StreamRole")
.HasForeignKey("NadekoBot.Services.Database.Models.StreamRoleSettings", "GuildConfigId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleWhitelistedUser", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.StreamRoleSettings")
.WithMany("Whitelist")
.HasForeignKey("StreamRoleSettingsId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
@ -1540,6 +1901,13 @@ namespace NadekoBot.Migrations
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuItem", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.WaifuInfo")
.WithMany("Items")
.HasForeignKey("WaifuInfoId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "New")
@ -1562,6 +1930,21 @@ namespace NadekoBot.Migrations
.WithMany("WarnPunishments")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.XpRoleReward", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.XpSettings")
.WithMany("RoleRewards")
.HasForeignKey("XpSettingsId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.XpSettings", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig")
.WithOne("XpSettings")
.HasForeignKey("NadekoBot.Services.Database.Models.XpSettings", "GuildConfigId")
.OnDelete(DeleteBehavior.Cascade);
});
}
}
}

View File

@ -5,23 +5,21 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NadekoBot.Common.Attributes;
using NadekoBot.Services;
using NadekoBot.Attributes;
using NadekoBot.Modules.Administration.Services;
using NadekoBot.Services.Database.Models;
using NadekoBot.Services.Administration;
namespace NadekoBot.Modules.Administration
{
public partial class Administration : NadekoTopLevelModule
public partial class Administration : NadekoTopLevelModule<AdministrationService>
{
private IGuild _nadekoSupportServer;
private readonly DbService _db;
private readonly AdministrationService _admin;
public Administration(DbService db, AdministrationService admin)
public Administration(DbService db)
{
_db = db;
_admin = admin;
}
[NadekoCommand, Usage, Description, Aliases]
@ -40,12 +38,12 @@ namespace NadekoBot.Modules.Administration
}
if (enabled)
{
_admin.DeleteMessagesOnCommand.Add(Context.Guild.Id);
_service.DeleteMessagesOnCommand.Add(Context.Guild.Id);
await ReplyConfirmLocalized("delmsg_on").ConfigureAwait(false);
}
else
{
_admin.DeleteMessagesOnCommand.TryRemove(Context.Guild.Id);
_service.DeleteMessagesOnCommand.TryRemove(Context.Guild.Id);
await ReplyConfirmLocalized("delmsg_off").ConfigureAwait(false);
}
}
@ -58,7 +56,7 @@ namespace NadekoBot.Modules.Administration
{
var guser = (IGuildUser)Context.User;
var maxRole = guser.GetRoles().Max(x => x.Position);
if ((Context.User.Id != Context.Guild.OwnerId) && (maxRole < role.Position || maxRole <= usr.GetRoles().Max(x => x.Position)))
if ((Context.User.Id != Context.Guild.OwnerId) && (maxRole <= role.Position || maxRole <= usr.GetRoles().Max(x => x.Position)))
return;
try
{

View File

@ -1,26 +1,24 @@
using Discord;
using Discord.Commands;
using NadekoBot.Attributes;
using NadekoBot.Extensions;
using NadekoBot.Services;
using NadekoBot.Services.Administration;
using System.Linq;
using System.Threading.Tasks;
using NadekoBot.Common.Attributes;
using NadekoBot.Modules.Administration.Services;
namespace NadekoBot.Modules.Administration
{
public partial class Administration
{
[Group]
public class AutoAssignRoleCommands : NadekoSubmodule
public class AutoAssignRoleCommands : NadekoSubmodule<AutoAssignRoleService>
{
private readonly DbService _db;
private readonly AutoAssignRoleService _service;
public AutoAssignRoleCommands(AutoAssignRoleService service, DbService db)
public AutoAssignRoleCommands(DbService db)
{
_db = db;
_service = service;
}
[NadekoCommand, Usage, Description, Aliases]
@ -39,7 +37,7 @@ namespace NadekoBot.Modules.Administration
if (role == null)
{
conf.AutoAssignRoleId = 0;
_service.AutoAssignedRoles.TryRemove(Context.Guild.Id, out ulong throwaway);
_service.AutoAssignedRoles.TryRemove(Context.Guild.Id, out _);
}
else
{

View File

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
namespace NadekoBot.Modules.Administration.Commands.Migration
namespace NadekoBot.Modules.Administration.Common.Migration
{
public class CommandPrefixes0_9
{

View File

@ -1,6 +1,6 @@
using System;
namespace NadekoBot.Modules.Administration.Commands.Migration
namespace NadekoBot.Modules.Administration.Common.Migration
{
public class MigrationException : Exception
{

View File

@ -1,8 +1,9 @@
using Discord;
using System.Collections.Concurrent;
using Discord;
using NadekoBot.Common.Collections;
using NadekoBot.Services.Database.Models;
using System.Collections.Concurrent;
namespace NadekoBot.Services.Administration
namespace NadekoBot.Modules.Administration.Common
{
public enum ProtectionType
{

View File

@ -1,12 +1,13 @@
using Discord.WebSocket;
using System;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Discord.WebSocket;
using NadekoBot.Modules.Administration.Services;
namespace NadekoBot.Services.Administration
namespace NadekoBot.Modules.Administration.Common
{
public class Ratelimiter
{

View File

@ -1,10 +1,10 @@
using Discord;
using System;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using Discord;
namespace NadekoBot.Services.Administration
namespace NadekoBot.Modules.Administration.Common
{
public class UserSpamStats : IDisposable
{

View File

@ -1,24 +1,22 @@
using Discord;
using Discord.Commands;
using NadekoBot.Attributes;
using NadekoBot.Services;
using System.Threading.Tasks;
using NadekoBot.Services.Administration;
using NadekoBot.Common.Attributes;
using NadekoBot.Modules.Administration.Services;
namespace NadekoBot.Modules.Administration
{
public partial class Administration
{
[Group]
public class GameChannelCommands : NadekoSubmodule
public class GameChannelCommands : NadekoSubmodule<GameVoiceChannelService>
{
private readonly DbService _db;
private readonly GameVoiceChannelService _service;
public GameChannelCommands(GameVoiceChannelService service, DbService db)
public GameChannelCommands(DbService db)
{
_db = db;
_service = service;
}
[NadekoCommand, Usage, Description, Aliases]

View File

@ -1,6 +1,5 @@
using Discord;
using Discord.Commands;
using NadekoBot.Attributes;
using NadekoBot.Extensions;
using System;
using System.Collections.Generic;
@ -8,6 +7,7 @@ using System.Collections.Immutable;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using NadekoBot.Common.Attributes;
namespace NadekoBot.Modules.Administration
{

View File

@ -1,16 +1,16 @@
using Discord;
using Discord.Commands;
using NadekoBot.Attributes;
using NadekoBot.DataStructures;
using NadekoBot.Extensions;
using NadekoBot.Modules.Permissions;
using NadekoBot.Services;
using NadekoBot.Services.Administration;
using NadekoBot.Services.Database.Models;
using System;
using System.Linq;
using System.Threading.Tasks;
using static NadekoBot.Services.Administration.LogCommandService;
using NadekoBot.Common;
using NadekoBot.Common.Attributes;
using NadekoBot.Common.TypeReaders.Models;
using NadekoBot.Modules.Administration.Services;
using static NadekoBot.Modules.Administration.Services.LogCommandService;
namespace NadekoBot.Modules.Administration
{
@ -18,14 +18,12 @@ namespace NadekoBot.Modules.Administration
{
[Group]
[NoPublicBot]
public class LogCommands : NadekoSubmodule
public class LogCommands : NadekoSubmodule<LogCommandService>
{
private readonly LogCommandService _lc;
private readonly DbService _db;
public LogCommands(LogCommandService lc, DbService db)
public LogCommands(DbService db)
{
_lc = lc;
_db = db;
}
@ -46,7 +44,7 @@ namespace NadekoBot.Modules.Administration
using (var uow = _db.UnitOfWork)
{
logSetting = uow.GuildConfigs.LogSettingsFor(channel.Guild.Id).LogSetting;
_lc.GuildLogSettings.AddOrUpdate(channel.Guild.Id, (id) => logSetting, (id, old) => logSetting);
_service.GuildLogSettings.AddOrUpdate(channel.Guild.Id, (id) => logSetting, (id, old) => logSetting);
logSetting.LogOtherId =
logSetting.MessageUpdatedId =
logSetting.MessageDeletedId =
@ -82,7 +80,7 @@ namespace NadekoBot.Modules.Administration
using (var uow = _db.UnitOfWork)
{
var config = uow.GuildConfigs.LogSettingsFor(channel.Guild.Id);
LogSetting logSetting = _lc.GuildLogSettings.GetOrAdd(channel.Guild.Id, (id) => config.LogSetting);
LogSetting logSetting = _service.GuildLogSettings.GetOrAdd(channel.Guild.Id, (id) => config.LogSetting);
removed = logSetting.IgnoredChannels.RemoveWhere(ilc => ilc.ChannelId == channel.Id);
config.LogSetting.IgnoredChannels.RemoveWhere(ilc => ilc.ChannelId == channel.Id);
if (removed == 0)
@ -106,8 +104,8 @@ namespace NadekoBot.Modules.Administration
[OwnerOnly]
public async Task LogEvents()
{
await Context.Channel.SendConfirmAsync(GetText("log_events") + "\n" +
string.Join(", ", Enum.GetNames(typeof(LogType)).Cast<string>()))
await Context.Channel.SendConfirmAsync(Format.Bold(GetText("log_events")) + "\n" +
$"```fix\n{string.Join(", ", Enum.GetNames(typeof(LogType)).Cast<string>())}```")
.ConfigureAwait(false);
}
@ -122,7 +120,7 @@ namespace NadekoBot.Modules.Administration
using (var uow = _db.UnitOfWork)
{
var logSetting = uow.GuildConfigs.LogSettingsFor(channel.Guild.Id).LogSetting;
_lc.GuildLogSettings.AddOrUpdate(channel.Guild.Id, (id) => logSetting, (id, old) => logSetting);
_service.GuildLogSettings.AddOrUpdate(channel.Guild.Id, (id) => logSetting, (id, old) => logSetting);
switch (type)
{
case LogType.Other:

View File

@ -4,27 +4,28 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Discord.Commands;
using NadekoBot.Attributes;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using Newtonsoft.Json;
using NadekoBot.Modules.Administration.Commands.Migration;
using System.Collections.Concurrent;
using NadekoBot.Extensions;
using NadekoBot.Services.Database;
using Microsoft.Data.Sqlite;
using NadekoBot.Common.Attributes;
using NadekoBot.Common.Collections;
using NadekoBot.Modules.Administration.Common.Migration;
namespace NadekoBot.Modules.Administration
{
public partial class Administration
{
[Group]
public class Migration : NadekoSubmodule
public class MigrationCommands : NadekoSubmodule
{
private const int CURRENT_VERSION = 1;
private readonly DbService _db;
public Migration(DbService db)
public MigrationCommands(DbService db)
{
_db = db;
}
@ -211,10 +212,10 @@ namespace NadekoBot.Modules.Administration
type = FollowedStream.FollowedStreamType.Twitch;
break;
case StreamNotificationConfig0_9.StreamType.Beam:
type = FollowedStream.FollowedStreamType.Beam;
type = FollowedStream.FollowedStreamType.Mixer;
break;
case StreamNotificationConfig0_9.StreamType.Hitbox:
type = FollowedStream.FollowedStreamType.Hitbox;
type = FollowedStream.FollowedStreamType.Smashcast;
break;
default:
break;
@ -351,54 +352,6 @@ namespace NadekoBot.Modules.Administration
oldConfig.RotatingStatuses.ForEach(i => messages.Add(new PlayingStatus { Status = i }));
botConfig.RotatingStatusMessages = messages;
//Prefix
botConfig.ModulePrefixes.Clear();
botConfig.ModulePrefixes.AddRange(new HashSet<ModulePrefix>
{
new ModulePrefix()
{
ModuleName = "Administration",
Prefix = oldConfig.CommandPrefixes.Administration
},
new ModulePrefix()
{
ModuleName = "Searches",
Prefix = oldConfig.CommandPrefixes.Searches
},
new ModulePrefix() {ModuleName = "NSFW", Prefix = oldConfig.CommandPrefixes.NSFW},
new ModulePrefix()
{
ModuleName = "Conversations",
Prefix = oldConfig.CommandPrefixes.Conversations
},
new ModulePrefix()
{
ModuleName = "ClashOfClans",
Prefix = oldConfig.CommandPrefixes.ClashOfClans
},
new ModulePrefix() {ModuleName = "Help", Prefix = oldConfig.CommandPrefixes.Help},
new ModulePrefix() {ModuleName = "Music", Prefix = oldConfig.CommandPrefixes.Music},
new ModulePrefix() {ModuleName = "Trello", Prefix = oldConfig.CommandPrefixes.Trello},
new ModulePrefix() {ModuleName = "Games", Prefix = oldConfig.CommandPrefixes.Games},
new ModulePrefix()
{
ModuleName = "Gambling",
Prefix = oldConfig.CommandPrefixes.Gambling
},
new ModulePrefix()
{
ModuleName = "Permissions",
Prefix = oldConfig.CommandPrefixes.Permissions
},
new ModulePrefix()
{
ModuleName = "Programming",
Prefix = oldConfig.CommandPrefixes.Programming
},
new ModulePrefix() {ModuleName = "Pokemon", Prefix = oldConfig.CommandPrefixes.Pokemon},
new ModulePrefix() {ModuleName = "Utility", Prefix = oldConfig.CommandPrefixes.Utility}
});
//Blacklist
var blacklist = new HashSet<BlacklistItem>(oldConfig.ServerBlacklist.Select(server => new BlacklistItem() { ItemId = server, Type = BlacklistType.Server }));
blacklist.AddRange(oldConfig.ChannelBlacklist.Select(channel => new BlacklistItem() { ItemId = channel, Type = BlacklistType.Channel }));

View File

@ -1,31 +1,29 @@
using Discord;
using Discord.Commands;
using NadekoBot.Attributes;
using NadekoBot.Services;
using NadekoBot.Services.Administration;
using System;
using System.Threading.Tasks;
using NadekoBot.Common.Attributes;
using NadekoBot.Modules.Administration.Services;
namespace NadekoBot.Modules.Administration
{
public partial class Administration
{
[Group]
public class MuteCommands : NadekoSubmodule
public class MuteCommands : NadekoSubmodule<MuteService>
{
private readonly MuteService _service;
private readonly DbService _db;
public MuteCommands(MuteService service, DbService db)
public MuteCommands(DbService db)
{
_service = service;
_db = db;
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageRoles)]
[Priority(1)]
[Priority(0)]
public async Task SetMuteRole([Remainder] string name)
{
name = name.Trim();
@ -45,7 +43,7 @@ namespace NadekoBot.Modules.Administration
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageRoles)]
[Priority(0)]
[Priority(1)]
public Task SetMuteRole([Remainder] IRole role)
=> SetMuteRole(role.Name);
@ -53,7 +51,7 @@ namespace NadekoBot.Modules.Administration
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageRoles)]
[RequireUserPermission(GuildPermission.MuteMembers)]
[Priority(1)]
[Priority(0)]
public async Task Mute(IGuildUser user)
{
try
@ -71,7 +69,7 @@ namespace NadekoBot.Modules.Administration
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageRoles)]
[RequireUserPermission(GuildPermission.MuteMembers)]
[Priority(0)]
[Priority(1)]
public async Task Mute(int minutes, IGuildUser user)
{
if (minutes < 1 || minutes > 1440)

View File

@ -1,26 +1,24 @@
using Discord.Commands;
using NadekoBot.Attributes;
using NadekoBot.Services;
using NadekoBot.Services.Administration;
using NadekoBot.Services.Database.Models;
using System.Linq;
using System.Threading.Tasks;
using NadekoBot.Common.Attributes;
using NadekoBot.Modules.Administration.Services;
namespace NadekoBot.Modules.Administration
{
public partial class Administration
{
[Group]
public class PlayingRotateCommands : NadekoSubmodule
public class PlayingRotateCommands : NadekoSubmodule<PlayingRotateService>
{
private static readonly object _locker = new object();
private readonly DbService _db;
private readonly PlayingRotateService _service;
public PlayingRotateCommands(PlayingRotateService service, DbService db)
public PlayingRotateCommands(DbService db)
{
_db = db;
_service = service;
}
[NadekoCommand, Usage, Description, Aliases]

View File

@ -1,7 +1,7 @@
using Discord;
using Discord.Commands;
using NadekoBot.Attributes;
using System.Threading.Tasks;
using NadekoBot.Common.Attributes;
namespace NadekoBot.Modules.Administration
{
@ -11,7 +11,7 @@ namespace NadekoBot.Modules.Administration
public class PrefixCommands : NadekoSubmodule
{
[NadekoCommand, Usage, Description, Aliases]
[Priority(0)]
[Priority(1)]
public new async Task Prefix()
{
await ReplyConfirmLocalized("prefix_current", Format.Code(_cmdHandler.GetPrefix(Context.Guild))).ConfigureAwait(false);
@ -21,7 +21,7 @@ namespace NadekoBot.Modules.Administration
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.Administrator)]
[Priority(1)]
[Priority(0)]
public new async Task Prefix([Remainder]string prefix)
{
if (string.IsNullOrWhiteSpace(prefix))

View File

@ -1,42 +1,50 @@
using Discord;
using Discord.Commands;
using Microsoft.EntityFrameworkCore;
using NadekoBot.Attributes;
using NadekoBot.Extensions;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using System;
using System.Linq;
using System.Threading.Tasks;
using NadekoBot.Services.Administration;
using NadekoBot.Common.Attributes;
using NadekoBot.Modules.Administration.Common;
using NadekoBot.Modules.Administration.Services;
namespace NadekoBot.Modules.Administration
{
public partial class Administration
{
[Group]
public class ProtectionCommands : NadekoSubmodule
public class ProtectionCommands : NadekoSubmodule<ProtectionService>
{
private readonly ProtectionService _service;
private readonly MuteService _mute;
private readonly DbService _db;
public ProtectionCommands(ProtectionService service, MuteService mute, DbService db)
public ProtectionCommands(MuteService mute, DbService db)
{
_service = service;
_mute = mute;
_db = db;
}
private string GetAntiSpamString(AntiSpamStats stats)
{
var ignoredString = string.Join(", ", stats.AntiSpamSettings.IgnoredChannels.Select(c => $"<#{c.ChannelId}>"));
var settings = stats.AntiSpamSettings;
var ignoredString = string.Join(", ", settings.IgnoredChannels.Select(c => $"<#{c.ChannelId}>"));
if (string.IsNullOrWhiteSpace(ignoredString))
ignoredString = "none";
string add = "";
if (settings.Action == PunishmentAction.Mute
&& settings.MuteTime > 0)
{
add = " (" + settings.MuteTime + "s)";
}
return GetText("spam_stats",
Format.Bold(stats.AntiSpamSettings.MessageThreshold.ToString()),
Format.Bold(stats.AntiSpamSettings.Action.ToString()),
Format.Bold(settings.MessageThreshold.ToString()),
Format.Bold(settings.Action.ToString() + add),
ignoredString);
}
@ -62,8 +70,7 @@ namespace NadekoBot.Modules.Administration
return;
}
AntiRaidStats throwaway;
if (_service.AntiRaidGuilds.TryRemove(Context.Guild.Id, out throwaway))
if (_service.AntiRaidGuilds.TryRemove(Context.Guild.Id, out _))
{
using (var uow = _db.UnitOfWork)
{
@ -114,15 +121,12 @@ namespace NadekoBot.Modules.Administration
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.Administrator)]
public async Task AntiSpam(int messageCount = 3, PunishmentAction action = PunishmentAction.Mute)
[Priority(1)]
public async Task AntiSpam()
{
if (messageCount < 2 || messageCount > 10)
return;
AntiSpamStats throwaway;
if (_service.AntiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway))
if (_service.AntiSpamGuilds.TryRemove(Context.Guild.Id, out var removed))
{
throwaway.UserStats.ForEach(x => x.Value.Dispose());
removed.UserStats.ForEach(x => x.Value.Dispose());
using (var uow = _db.UnitOfWork)
{
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting)
@ -135,6 +139,21 @@ namespace NadekoBot.Modules.Administration
return;
}
await AntiSpam(3).ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.Administrator)]
[Priority(0)]
public async Task AntiSpam(int messageCount, PunishmentAction action = PunishmentAction.Mute, int time = 0)
{
if (messageCount < 2 || messageCount > 10)
return;
if (time < 0 || time > 60 * 12)
return;
try
{
await _mute.GetMuteRole(Context.Guild).ConfigureAwait(false);
@ -152,10 +171,15 @@ namespace NadekoBot.Modules.Administration
{
Action = action,
MessageThreshold = messageCount,
MuteTime = time,
}
};
_service.AntiSpamGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats);
stats = _service.AntiSpamGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) =>
{
stats.AntiSpamSettings.IgnoredChannels = old.AntiSpamSettings.IgnoredChannels;
return stats;
});
using (var uow = _db.UnitOfWork)
{

View File

@ -1,28 +1,19 @@
using Discord;
using Discord.Commands;
using NadekoBot.Attributes;
using NadekoBot.Extensions;
using NadekoBot.Services.Administration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Common.Attributes;
using NadekoBot.Modules.Administration.Services;
namespace NadekoBot.Modules.Administration
{
public partial class Administration
{
[Group]
public class PruneCommands : ModuleBase
public class PruneCommands : NadekoSubmodule<PruneService>
{
private readonly TimeSpan twoWeeks = TimeSpan.FromDays(14);
private readonly PruneService _prune;
public PruneCommands(PruneService prune)
{
_prune = prune;
}
//delets her own messages, no perm required
[NadekoCommand, Usage, Description, Aliases]
@ -31,7 +22,7 @@ namespace NadekoBot.Modules.Administration
{
var user = await Context.Guild.GetCurrentUserAsync().ConfigureAwait(false);
await _prune.PruneWhere((ITextChannel)Context.Channel, 100, (x) => x.Author.Id == user.Id).ConfigureAwait(false);
await _service.PruneWhere((ITextChannel)Context.Channel, 100, (x) => x.Author.Id == user.Id).ConfigureAwait(false);
Context.Message.DeleteAfter(3);
}
// prune x
@ -39,7 +30,7 @@ namespace NadekoBot.Modules.Administration
[RequireContext(ContextType.Guild)]
[RequireUserPermission(ChannelPermission.ManageMessages)]
[RequireBotPermission(GuildPermission.ManageMessages)]
[Priority(0)]
[Priority(1)]
public async Task Prune(int count)
{
count++;
@ -47,7 +38,7 @@ namespace NadekoBot.Modules.Administration
return;
if (count > 1000)
count = 1000;
await _prune.PruneWhere((ITextChannel)Context.Channel, count, x => true).ConfigureAwait(false);
await _service.PruneWhere((ITextChannel)Context.Channel, count, x => true).ConfigureAwait(false);
}
//prune @user [x]
@ -55,7 +46,7 @@ namespace NadekoBot.Modules.Administration
[RequireContext(ContextType.Guild)]
[RequireUserPermission(ChannelPermission.ManageMessages)]
[RequireBotPermission(GuildPermission.ManageMessages)]
[Priority(1)]
[Priority(0)]
public async Task Prune(IGuildUser user, int count = 100)
{
if (user.Id == Context.User.Id)
@ -66,7 +57,7 @@ namespace NadekoBot.Modules.Administration
if (count > 1000)
count = 1000;
await _prune.PruneWhere((ITextChannel)Context.Channel, count, m => m.Author.Id == user.Id && DateTime.UtcNow - m.CreatedAt < twoWeeks);
await _service.PruneWhere((ITextChannel)Context.Channel, count, m => m.Author.Id == user.Id && DateTime.UtcNow - m.CreatedAt < twoWeeks);
}
}
}

View File

@ -1,28 +1,27 @@
using Discord;
using Discord.Commands;
using Microsoft.EntityFrameworkCore;
using NadekoBot.Attributes;
using NadekoBot.Extensions;
using NadekoBot.Services;
using NadekoBot.Services.Administration;
using NadekoBot.Services.Database.Models;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NadekoBot.Common.Attributes;
using NadekoBot.Modules.Administration.Common;
using NadekoBot.Modules.Administration.Services;
namespace NadekoBot.Modules.Administration
{
public partial class Administration
{
[Group]
public class SlowModeCommands : NadekoSubmodule
public class SlowModeCommands : NadekoSubmodule<SlowmodeService>
{
private readonly SlowmodeService _service;
private readonly DbService _db;
public SlowModeCommands(SlowmodeService service, DbService db)
public SlowModeCommands(DbService db)
{
_service = service;
_db = db;
}
@ -31,9 +30,9 @@ namespace NadekoBot.Modules.Administration
[RequireUserPermission(GuildPermission.ManageMessages)]
public async Task Slowmode()
{
if (_service.RatelimitingChannels.TryRemove(Context.Channel.Id, out Ratelimiter throwaway))
if (_service.RatelimitingChannels.TryRemove(Context.Channel.Id, out Ratelimiter removed))
{
throwaway.CancelSource.Cancel();
removed.CancelSource.Cancel();
await ReplyConfirmLocalized("slowmode_disabled").ConfigureAwait(false);
}
}
@ -67,7 +66,7 @@ namespace NadekoBot.Modules.Administration
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageMessages)]
[Priority(1)]
[Priority(0)]
public async Task SlowmodeWhitelist(IGuildUser user)
{
var siu = new SlowmodeIgnoredUser
@ -99,7 +98,7 @@ namespace NadekoBot.Modules.Administration
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageMessages)]
[Priority(0)]
[Priority(1)]
public async Task SlowmodeWhitelist(IRole role)
{
var sir = new SlowmodeIgnoredRole

View File

@ -1,16 +1,16 @@
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using NadekoBot.Attributes;
using NadekoBot.Extensions;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Common.Attributes;
using NadekoBot.Common.Collections;
namespace NadekoBot.Modules.Administration
{
@ -195,18 +195,23 @@ namespace NadekoBot.Modules.Administration
var roleIds = roles.Select(x => x.RoleId).ToArray();
if (conf.ExclusiveSelfAssignedRoles)
{
var sameRoleId = guildUser.RoleIds.FirstOrDefault(r => roleIds.Contains(r));
var sameRoles = guildUser.RoleIds.Where(r => roleIds.Contains(r));
if (sameRoleId != default(ulong))
foreach (var roleId in sameRoles)
{
var sameRole = Context.Guild.GetRole(sameRoleId);
var sameRole = Context.Guild.GetRole(roleId);
if (sameRole != null)
{
await guildUser.RemoveRoleAsync(sameRole).ConfigureAwait(false);
await Task.Delay(500).ConfigureAwait(false);
try
{
await guildUser.RemoveRoleAsync(sameRole).ConfigureAwait(false);
await Task.Delay(300).ConfigureAwait(false);
}
catch (Exception ex)
{
_log.Warn(ex);
}
}
//await ReplyErrorLocalized("self_assign_already_excl", Format.Bold(sameRole?.Name)).ConfigureAwait(false);
//return;
}
}
try

View File

@ -1,6 +1,5 @@
using Discord;
using Discord.Commands;
using NadekoBot.Attributes;
using NadekoBot.Extensions;
using System;
using System.Collections.Generic;
@ -12,34 +11,36 @@ using Discord.WebSocket;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using Microsoft.EntityFrameworkCore;
using NadekoBot.Services.Administration;
using System.Diagnostics;
using NadekoBot.DataStructures;
using NadekoBot.Services.Music;
using NadekoBot.Common.Attributes;
using NadekoBot.Modules.Administration.Services;
using NadekoBot.Modules.Music.Services;
namespace NadekoBot.Modules.Administration
{
public partial class Administration
{
[Group]
public class SelfCommands : NadekoSubmodule
public class SelfCommands : NadekoSubmodule<SelfService>
{
private readonly DbService _db;
private static readonly object _locker = new object();
private readonly SelfService _service;
private readonly DiscordSocketClient _client;
private readonly IImagesService _images;
private readonly MusicService _music;
private readonly IBotConfigProvider _bc;
private readonly NadekoBot _bot;
public SelfCommands(DbService db, SelfService service, DiscordSocketClient client,
MusicService music, IImagesService images)
public SelfCommands(DbService db, NadekoBot bot, DiscordSocketClient client,
MusicService music, IImagesService images, IBotConfigProvider bc)
{
_db = db;
_service = service;
_client = client;
_images = images;
_music = music;
_bc = bc;
_bot = bot;
}
[NadekoCommand, Usage, Description, Aliases]
@ -100,13 +101,13 @@ namespace NadekoBot.Modules.Administration
}
else
{
await Context.Channel.SendConfirmAsync("", string.Join("\n--\n", scmds.Select(x =>
await Context.Channel.SendConfirmAsync("", string.Join("\n", scmds.Select(x =>
{
string str = Format.Code(GetText("server")) + ": " + (x.GuildId == null ? "-" : x.GuildName + "/" + x.GuildId);
string str = $"```css\n[{GetText("server") + "]: " + (x.GuildId == null ? "-" : x.GuildName + " #" + x.GuildId)}";
str += $@"
{Format.Code(GetText("channel"))}: {x.ChannelName}/{x.ChannelId}
{Format.Code(GetText("command_text"))}: {x.CommandText}";
[{GetText("channel")}]: {x.ChannelName} #{x.ChannelId}
[{GetText("command_text")}]: {x.CommandText}```";
return str;
})), footer: GetText("page", page + 1))
.ConfigureAwait(false);
@ -182,9 +183,11 @@ namespace NadekoBot.Modules.Administration
using (var uow = _db.UnitOfWork)
{
var config = uow.BotConfig.GetOrCreate();
_service.ForwardDMs = config.ForwardMessages = !config.ForwardMessages;
config.ForwardMessages = !config.ForwardMessages;
uow.Complete();
}
_bc.Reload();
if (_service.ForwardDMs)
await ReplyConfirmLocalized("fwdm_start").ConfigureAwait(false);
else
@ -199,9 +202,11 @@ namespace NadekoBot.Modules.Administration
{
var config = uow.BotConfig.GetOrCreate();
lock (_locker)
_service.ForwardDMsToAllOwners = config.ForwardToAllOwners = !config.ForwardToAllOwners;
config.ForwardToAllOwners = !config.ForwardToAllOwners;
uow.Complete();
}
_bc.Reload();
if (_service.ForwardDMsToAllOwners)
await ReplyConfirmLocalized("fwall_start").ConfigureAwait(false);
else
@ -289,7 +294,7 @@ namespace NadekoBot.Modules.Administration
[NadekoCommand, Usage, Description, Aliases]
[RequireUserPermission(GuildPermission.ManageNicknames)]
[Priority(1)]
[Priority(0)]
public async Task SetNick([Remainder] string newNick = null)
{
if (string.IsNullOrWhiteSpace(newNick))
@ -303,7 +308,7 @@ namespace NadekoBot.Modules.Administration
[NadekoCommand, Usage, Description, Aliases]
[RequireBotPermission(GuildPermission.ManageNicknames)]
[RequireUserPermission(GuildPermission.ManageNicknames)]
[Priority(0)]
[Priority(1)]
public async Task SetNick(IGuildUser gu, [Remainder] string newNick = null)
{
await gu.ModifyAsync(u => u.Nickname = newNick).ConfigureAwait(false);
@ -346,7 +351,7 @@ namespace NadekoBot.Modules.Administration
[OwnerOnly]
public async Task SetGame([Remainder] string game = null)
{
await _client.SetGameAsync(game).ConfigureAwait(false);
await _bot.SetGameAsync(game).ConfigureAwait(false);
await ReplyConfirmLocalized("set_game").ConfigureAwait(false);
}
@ -406,19 +411,6 @@ namespace NadekoBot.Modules.Administration
await ReplyConfirmLocalized("message_sent").ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
[OwnerOnly]
public async Task Announce([Remainder] string message)
{
var channels = _client.Guilds.Select(g => g.DefaultChannel).ToArray();
if (channels == null)
return;
await Task.WhenAll(channels.Where(c => c != null).Select(c => c.SendConfirmAsync(GetText("message_from_bo", Context.User.ToString()), message)))
.ConfigureAwait(false);
await ReplyConfirmLocalized("message_sent").ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
[OwnerOnly]
public async Task ReloadImages()

View File

@ -1,24 +1,22 @@
using Discord;
using Discord.Commands;
using NadekoBot.Attributes;
using NadekoBot.Extensions;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using System.Threading.Tasks;
using NadekoBot.Common.Attributes;
namespace NadekoBot.Modules.Administration
{
public partial class Administration
{
[Group]
public class ServerGreetCommands : NadekoSubmodule
public class ServerGreetCommands : NadekoSubmodule<GreetSettingsService>
{
private readonly GreetSettingsService _greetService;
private readonly DbService _db;
public ServerGreetCommands(GreetSettingsService greetService, DbService db)
public ServerGreetCommands(DbService db)
{
_greetService = greetService;
_db = db;
}
@ -30,7 +28,7 @@ namespace NadekoBot.Modules.Administration
if (timer < 0 || timer > 600)
return;
await _greetService.SetGreetDel(Context.Guild.Id, timer).ConfigureAwait(false);
await _service.SetGreetDel(Context.Guild.Id, timer).ConfigureAwait(false);
if (timer > 0)
await ReplyConfirmLocalized("greetdel_on", timer).ConfigureAwait(false);
@ -43,7 +41,7 @@ namespace NadekoBot.Modules.Administration
[RequireUserPermission(GuildPermission.ManageGuild)]
public async Task Greet()
{
var enabled = await _greetService.SetGreet(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false);
var enabled = await _service.SetGreet(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false);
if (enabled)
await ReplyConfirmLocalized("greet_on").ConfigureAwait(false);
@ -67,7 +65,7 @@ namespace NadekoBot.Modules.Administration
return;
}
var sendGreetEnabled = _greetService.SetGreetMessage(Context.Guild.Id, ref text);
var sendGreetEnabled = _service.SetGreetMessage(Context.Guild.Id, ref text);
await ReplyConfirmLocalized("greetmsg_new").ConfigureAwait(false);
if (!sendGreetEnabled)
@ -79,7 +77,7 @@ namespace NadekoBot.Modules.Administration
[RequireUserPermission(GuildPermission.ManageGuild)]
public async Task GreetDm()
{
var enabled = await _greetService.SetGreetDm(Context.Guild.Id).ConfigureAwait(false);
var enabled = await _service.SetGreetDm(Context.Guild.Id).ConfigureAwait(false);
if (enabled)
await ReplyConfirmLocalized("greetdm_on").ConfigureAwait(false);
@ -103,7 +101,7 @@ namespace NadekoBot.Modules.Administration
return;
}
var sendGreetEnabled = _greetService.SetGreetDmMessage(Context.Guild.Id, ref text);
var sendGreetEnabled = _service.SetGreetDmMessage(Context.Guild.Id, ref text);
await ReplyConfirmLocalized("greetdmmsg_new").ConfigureAwait(false);
if (!sendGreetEnabled)
@ -115,7 +113,7 @@ namespace NadekoBot.Modules.Administration
[RequireUserPermission(GuildPermission.ManageGuild)]
public async Task Bye()
{
var enabled = await _greetService.SetBye(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false);
var enabled = await _service.SetBye(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false);
if (enabled)
await ReplyConfirmLocalized("bye_on").ConfigureAwait(false);
@ -139,7 +137,7 @@ namespace NadekoBot.Modules.Administration
return;
}
var sendByeEnabled = _greetService.SetByeMessage(Context.Guild.Id, ref text);
var sendByeEnabled = _service.SetByeMessage(Context.Guild.Id, ref text);
await ReplyConfirmLocalized("byemsg_new").ConfigureAwait(false);
if (!sendByeEnabled)
@ -151,7 +149,7 @@ namespace NadekoBot.Modules.Administration
[RequireUserPermission(GuildPermission.ManageGuild)]
public async Task ByeDel(int timer = 30)
{
await _greetService.SetByeDel(Context.Guild.Id, timer).ConfigureAwait(false);
await _service.SetByeDel(Context.Guild.Id, timer).ConfigureAwait(false);
if (timer > 0)
await ReplyConfirmLocalized("byedel_on", timer).ConfigureAwait(false);

View File

@ -1,17 +1,18 @@
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using NadekoBot.Services.Database.Models;
using NLog;
using System;
using System.Collections.Concurrent;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using NadekoBot.Common.Collections;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using NLog;
namespace NadekoBot.Services.Administration
namespace NadekoBot.Modules.Administration.Services
{
public class AdministrationService
public class AdministrationService : INService
{
public readonly ConcurrentHashSet<ulong> DeleteMessagesOnCommand;
private readonly Logger _log;

View File

@ -1,15 +1,16 @@
using Discord.WebSocket;
using NadekoBot.Services.Database.Models;
using NLog;
using System;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Discord.WebSocket;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using NLog;
namespace NadekoBot.Services.Administration
namespace NadekoBot.Modules.Administration.Services
{
public class AutoAssignRoleService
public class AutoAssignRoleService : INService
{
private readonly Logger _log;
private readonly DiscordSocketClient _client;

View File

@ -1,16 +1,17 @@
using Discord.WebSocket;
using NadekoBot.Extensions;
using NadekoBot.Services.Database.Models;
using NLog;
using System;
using System.Collections.Concurrent;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Discord.WebSocket;
using NadekoBot.Common.Collections;
using NadekoBot.Extensions;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using NLog;
namespace NadekoBot.Services.Administration
namespace NadekoBot.Modules.Administration.Services
{
public class GameVoiceChannelService
public class GameVoiceChannelService : INService
{
public readonly ConcurrentHashSet<ulong> GameVoiceChannels = new ConcurrentHashSet<ulong>();
@ -42,7 +43,7 @@ namespace NadekoBot.Services.Administration
if (gUser == null)
return;
var game = gUser.Game?.Name.TrimTo(50).ToLowerInvariant();
var game = gUser.Game?.Name?.TrimTo(50).ToLowerInvariant();
if (oldState.VoiceChannel == newState.VoiceChannel ||
newState.VoiceChannel == null)

View File

@ -1,17 +1,17 @@
using NadekoBot.Extensions;
using NadekoBot.Services.Database.Models;
using System;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Concurrent;
using NadekoBot.Services;
using Discord.WebSocket;
using NadekoBot.Extensions;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
namespace NadekoBot.Services.Administration
namespace NadekoBot.Modules.Administration.Services
{
public class GuildTimezoneService
public class GuildTimezoneService : INService
{
//hack >.>
// todo 70 this is a hack >.<
public static ConcurrentDictionary<ulong, GuildTimezoneService> AllServices { get; } = new ConcurrentDictionary<ulong, GuildTimezoneService>();
private ConcurrentDictionary<ulong, TimeZoneInfo> _timezones;
private readonly DbService _db;

View File

@ -1,19 +1,23 @@
using Discord;
using Discord.WebSocket;
using NadekoBot.Extensions;
using NadekoBot.Services.Database.Models;
using NLog;
using System;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
using NadekoBot.Extensions;
using NadekoBot.Modules.Administration.Common;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using NadekoBot.Services.Impl;
using NLog;
using NadekoBot.Common;
namespace NadekoBot.Services.Administration
namespace NadekoBot.Modules.Administration.Services
{
public class LogCommandService
[NoPublicBot]
public class LogCommandService : INService
{
private readonly DiscordSocketClient _client;
@ -66,14 +70,15 @@ namespace NadekoBot.Services.Administration
{
var keys = PresenceUpdates.Keys.ToList();
await Task.WhenAll(keys.Select(async key =>
await Task.WhenAll(keys.Select(key =>
{
if (PresenceUpdates.TryRemove(key, out List<string> messages))
try { await key.SendConfirmAsync(GetText(key.Guild, "presence_updates"), string.Join(Environment.NewLine, messages)); }
catch
{
// ignored
}
if (PresenceUpdates.TryRemove(key, out var msgs))
{
var title = GetText(key.Guild, "presence_updates");
var desc = string.Join(Environment.NewLine, msgs);
return key.SendConfirmAsync(title, desc.TrimTo(2048));
}
return Task.CompletedTask;
}));
}
catch (Exception ex)
@ -146,10 +151,13 @@ namespace NadekoBot.Services.Administration
{
embed.WithTitle("👥" + GetText(g, "avatar_changed"))
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
.WithThumbnailUrl(before.GetAvatarUrl())
.WithImageUrl(after.GetAvatarUrl())
.WithFooter(fb => fb.WithText(CurrentTime(g)))
.WithOkColor();
if (Uri.IsWellFormedUriString(before.GetAvatarUrl(), UriKind.Absolute))
embed.WithThumbnailUrl(before.GetAvatarUrl());
if (Uri.IsWellFormedUriString(after.GetAvatarUrl(), UriKind.Absolute))
embed.WithImageUrl(after.GetAvatarUrl());
}
else
{
@ -369,40 +377,59 @@ namespace NadekoBot.Services.Administration
{
try
{
if (!GuildLogSettings.TryGetValue(before.Guild.Id, out LogSetting logSetting)
|| (logSetting.UserUpdatedId == null))
if (!GuildLogSettings.TryGetValue(before.Guild.Id, out LogSetting logSetting))
return;
ITextChannel logChannel;
if ((logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) == null)
return;
var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText(CurrentTime(before.Guild)))
.WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}");
if (before.Nickname != after.Nickname)
if (logSetting.UserUpdatedId != null && (logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) != null)
{
embed.WithAuthor(eab => eab.WithName("👥 " + GetText(logChannel.Guild, "nick_change")))
var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText(CurrentTime(before.Guild)))
.WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}");
if (before.Nickname != after.Nickname)
{
embed.WithAuthor(eab => eab.WithName("👥 " + GetText(logChannel.Guild, "nick_change")))
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "old_nick")).WithValue($"{before.Nickname}#{before.Discriminator}"))
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "new_nick")).WithValue($"{after.Nickname}#{after.Discriminator}"));
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "old_nick")).WithValue($"{before.Nickname}#{before.Discriminator}"))
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "new_nick")).WithValue($"{after.Nickname}#{after.Discriminator}"));
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
}
else if (!before.Roles.SequenceEqual(after.Roles))
{
if (before.Roles.Count < after.Roles.Count)
{
var diffRoles = after.Roles.Where(r => !before.Roles.Contains(r)).Select(r => r.Name);
embed.WithAuthor(eab => eab.WithName("⚔ " + GetText(logChannel.Guild, "user_role_add")))
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
}
else if (before.Roles.Count > after.Roles.Count)
{
var diffRoles = before.Roles.Where(r => !after.Roles.Contains(r)).Select(r => r.Name);
embed.WithAuthor(eab => eab.WithName("⚔ " + GetText(logChannel.Guild, "user_role_rem")))
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
}
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
}
}
else if (!before.Roles.SequenceEqual(after.Roles))
logChannel = null;
if (logSetting.LogUserPresenceId != null && (logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserPresence)) != null)
{
if (before.Roles.Count < after.Roles.Count)
if (before.Status != after.Status)
{
var diffRoles = after.Roles.Where(r => !before.Roles.Contains(r)).Select(r => r.Name);
embed.WithAuthor(eab => eab.WithName("⚔ " + GetText(logChannel.Guild, "user_role_add")))
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
var str = "🎭" + Format.Code(PrettyCurrentTime(after.Guild)) +
GetText(logChannel.Guild, "user_status_change",
"👤" + Format.Bold(after.Username),
Format.Bold(after.Status.ToString()));
PresenceUpdates.AddOrUpdate(logChannel,
new List<string>() { str }, (id, list) => { list.Add(str); return list; });
}
else if (before.Roles.Count > after.Roles.Count)
else if (before.Game?.Name != after.Game?.Name)
{
var diffRoles = before.Roles.Where(r => !after.Roles.Contains(r)).Select(r => r.Name);
embed.WithAuthor(eab => eab.WithName("⚔ " + GetText(logChannel.Guild, "user_role_rem")))
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
var str = $"👾`{PrettyCurrentTime(after.Guild)}`👤__**{after.Username}**__ is now playing **{after.Game?.Name ?? "-"}**.";
PresenceUpdates.AddOrUpdate(logChannel,
new List<string>() { str }, (id, list) => { list.Add(str); return list; });
}
}
else
return;
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
}
catch
{
@ -580,7 +607,7 @@ namespace NadekoBot.Services.Administration
"👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
Format.Bold(beforeVch.Name ?? ""));
}
if (str != null)
if (!string.IsNullOrWhiteSpace(str))
PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
}
catch
@ -647,14 +674,17 @@ namespace NadekoBot.Services.Administration
ITextChannel logChannel;
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserLeft)) == null)
return;
await logChannel.EmbedAsync(new EmbedBuilder()
var embed = new EmbedBuilder()
.WithOkColor()
.WithTitle("❌ " + GetText(logChannel.Guild, "user_left"))
.WithThumbnailUrl(usr.GetAvatarUrl())
.WithDescription(usr.ToString())
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
.WithFooter(efb => efb.WithText(CurrentTime(usr.Guild)))).ConfigureAwait(false);
.WithFooter(efb => efb.WithText(CurrentTime(usr.Guild)));
if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
embed.WithThumbnailUrl(usr.GetAvatarUrl());
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
}
catch
{
@ -678,13 +708,17 @@ namespace NadekoBot.Services.Administration
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserJoined)) == null)
return;
await logChannel.EmbedAsync(new EmbedBuilder()
var embed = new EmbedBuilder()
.WithOkColor()
.WithTitle("✅ " + GetText(logChannel.Guild, "user_joined"))
.WithThumbnailUrl(usr.GetAvatarUrl())
.WithDescription($"{usr}")
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
.WithFooter(efb => efb.WithText(CurrentTime(usr.Guild)))).ConfigureAwait(false);
.WithFooter(efb => efb.WithText(CurrentTime(usr.Guild)));
if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
embed.WithThumbnailUrl(usr.GetAvatarUrl());
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
}
catch (Exception ex) { _log.Warn(ex); }
});
@ -704,14 +738,17 @@ namespace NadekoBot.Services.Administration
ITextChannel logChannel;
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserUnbanned)) == null)
return;
await logChannel.EmbedAsync(new EmbedBuilder()
var embed = new EmbedBuilder()
.WithOkColor()
.WithTitle("♻️ " + GetText(logChannel.Guild, "user_unbanned"))
.WithThumbnailUrl(usr.GetAvatarUrl())
.WithDescription(usr.ToString())
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
.WithFooter(efb => efb.WithText(CurrentTime(guild)))).ConfigureAwait(false);
.WithFooter(efb => efb.WithText(CurrentTime(guild)));
if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
embed.WithThumbnailUrl(usr.GetAvatarUrl());
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
}
catch (Exception ex) { _log.Warn(ex); }
});
@ -731,13 +768,19 @@ namespace NadekoBot.Services.Administration
ITextChannel logChannel;
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserBanned)) == null)
return;
await logChannel.EmbedAsync(new EmbedBuilder()
var embed = new EmbedBuilder()
.WithOkColor()
.WithTitle("🚫 " + GetText(logChannel.Guild, "user_banned"))
.WithThumbnailUrl(usr.GetAvatarUrl())
.WithDescription(usr.ToString())
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
.WithFooter(efb => efb.WithText(CurrentTime(guild)))).ConfigureAwait(false);
.WithFooter(efb => efb.WithText(CurrentTime(guild)));
var avatarUrl = usr.GetAvatarUrl();
if (Uri.IsWellFormedUriString(avatarUrl, UriKind.Absolute))
embed.WithThumbnailUrl(usr.GetAvatarUrl());
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
}
catch (Exception ex) { _log.Warn(ex); }
});

View File

@ -1,17 +1,19 @@
using Discord;
using Discord.WebSocket;
using Microsoft.EntityFrameworkCore;
using NadekoBot.Extensions;
using NadekoBot.Services.Database.Models;
using NLog;
using System;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
using Microsoft.EntityFrameworkCore;
using NadekoBot.Common.Collections;
using NadekoBot.Extensions;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using NLog;
namespace NadekoBot.Services.Administration
namespace NadekoBot.Modules.Administration.Services
{
public enum MuteType
{
@ -20,7 +22,7 @@ namespace NadekoBot.Services.Administration
All
}
public class MuteService
public class MuteService : INService
{
public ConcurrentDictionary<ulong, string> GuildMuteRoles { get; }
public ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> MutedUsers { get; }
@ -30,7 +32,7 @@ namespace NadekoBot.Services.Administration
public event Action<IGuildUser, MuteType> UserMuted = delegate { };
public event Action<IGuildUser, MuteType> UserUnmuted = delegate { };
private static readonly OverwritePermissions denyOverwrite = new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny);
private static readonly OverwritePermissions denyOverwrite = new OverwritePermissions(addReactions: PermValue.Deny, sendMessages: PermValue.Deny, attachFiles: PermValue.Deny);
private readonly Logger _log = LogManager.GetCurrentClassLogger();
private readonly DiscordSocketClient _client;

View File

@ -0,0 +1,88 @@
using System;
using System.Linq;
using System.Threading;
using Discord.WebSocket;
using NadekoBot.Common.Replacements;
using NadekoBot.Modules.Music.Services;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using NLog;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Administration.Services
{
public class PlayingRotateService : INService
{
private readonly Timer _t;
private readonly DiscordSocketClient _client;
private readonly MusicService _music;
private readonly Logger _log;
private readonly IDataCache _cache;
private readonly Replacer _rep;
private readonly DbService _db;
private readonly IBotConfigProvider _bcp;
public BotConfig BotConfig => _bcp.BotConfig;
private class TimerState
{
public int Index { get; set; }
}
public PlayingRotateService(DiscordSocketClient client, IBotConfigProvider bcp,
MusicService music, DbService db, IDataCache cache, NadekoBot bot)
{
_client = client;
_bcp = bcp;
_music = music;
_db = db;
_log = LogManager.GetCurrentClassLogger();
_cache = cache;
if (client.ShardId == 0)
{
_rep = new ReplacementBuilder()
.WithClient(client)
.WithStats(client)
.WithMusic(music)
.Build();
_t = new Timer(async (objState) =>
{
try
{
bcp.Reload();
var state = (TimerState)objState;
if (!BotConfig.RotatingStatuses)
return;
if (state.Index >= BotConfig.RotatingStatusMessages.Count)
state.Index = 0;
if (!BotConfig.RotatingStatusMessages.Any())
return;
var status = BotConfig.RotatingStatusMessages[state.Index++].Status;
if (string.IsNullOrWhiteSpace(status))
return;
status = _rep.Replace(status);
try
{
await bot.SetGameAsync(status).ConfigureAwait(false);
}
catch (Exception ex)
{
_log.Warn(ex);
}
}
catch (Exception ex)
{
_log.Warn("Rotating playing status errored.\n" + ex);
}
}, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
}
}
}
}

View File

@ -1,16 +1,18 @@
using Discord;
using Discord.WebSocket;
using NadekoBot.Services.Database.Models;
using NLog;
using System;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
using NadekoBot.Modules.Administration.Common;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using NLog;
namespace NadekoBot.Services.Administration
namespace NadekoBot.Modules.Administration.Services
{
public class ProtectionService
public class ProtectionService : INService
{
public readonly ConcurrentDictionary<ulong, AntiRaidStats> AntiRaidGuilds =
new ConcurrentDictionary<ulong, AntiRaidStats>();
@ -76,7 +78,7 @@ namespace NadekoBot.Services.Administration
if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats))
{
stats.Dispose();
await PunishUsers(spamSettings.AntiSpamSettings.Action, ProtectionType.Spamming, (IGuildUser)msg.Author)
await PunishUsers(spamSettings.AntiSpamSettings.Action, ProtectionType.Spamming, spamSettings.AntiSpamSettings.MuteTime, (IGuildUser)msg.Author)
.ConfigureAwait(false);
}
}
@ -109,7 +111,7 @@ namespace NadekoBot.Services.Administration
var users = settings.RaidUsers.ToArray();
settings.RaidUsers.Clear();
await PunishUsers(settings.AntiRaidSettings.Action, ProtectionType.Raiding, users).ConfigureAwait(false);
await PunishUsers(settings.AntiRaidSettings.Action, ProtectionType.Raiding, 0, users).ConfigureAwait(false);
}
await Task.Delay(1000 * settings.AntiRaidSettings.Seconds).ConfigureAwait(false);
@ -127,7 +129,7 @@ namespace NadekoBot.Services.Administration
}
private async Task PunishUsers(PunishmentAction action, ProtectionType pt, params IGuildUser[] gus)
private async Task PunishUsers(PunishmentAction action, ProtectionType pt, int muteTime, params IGuildUser[] gus)
{
_log.Info($"[{pt}] - Punishing [{gus.Length}] users with [{action}] in {gus[0].Guild.Name} guild");
foreach (var gu in gus)
@ -137,7 +139,10 @@ namespace NadekoBot.Services.Administration
case PunishmentAction.Mute:
try
{
await _mute.MuteUser(gu).ConfigureAwait(false);
if (muteTime <= 0)
await _mute.MuteUser(gu).ConfigureAwait(false);
else
await _mute.TimedMute(gu, TimeSpan.FromSeconds(muteTime)).ConfigureAwait(false);
}
catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); }
break;

View File

@ -1,15 +1,15 @@
using Discord;
using NadekoBot.Extensions;
using System;
using System.Collections.Concurrent;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord;
using NadekoBot.Common.Collections;
using NadekoBot.Extensions;
using NadekoBot.Services;
namespace NadekoBot.Services.Administration
namespace NadekoBot.Modules.Administration.Services
{
public class PruneService
public class PruneService : INService
{
//channelids where prunes are currently occuring
private ConcurrentHashSet<ulong> _pruningGuilds = new ConcurrentHashSet<ulong>();

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