reorganized administration

This commit is contained in:
Master Kwoth 2016-03-29 15:20:18 +02:00
parent a6ae2701f7
commit 0d8598c845
14 changed files with 454 additions and 260 deletions

View File

@ -1,16 +1,19 @@
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Extensions;
using NadekoBot.Modules;
using NadekoBot.Modules.Administration.Commands;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using NadekoBot.Extensions;
using System.Threading.Tasks;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using System.Timers; using System.Timers;
using NadekoBot.Modules;
namespace NadekoBot { namespace NadekoBot
public class NadekoStats { {
public class NadekoStats
{
public static NadekoStats Instance { get; } = new NadekoStats(); public static NadekoStats Instance { get; } = new NadekoStats();
public string BotVersion => $"{Assembly.GetExecutingAssembly().GetName().Name} v{Assembly.GetExecutingAssembly().GetName().Version}"; public string BotVersion => $"{Assembly.GetExecutingAssembly().GetName().Name} v{Assembly.GetExecutingAssembly().GetName().Version}";
@ -23,11 +26,12 @@ namespace NadekoBot {
public int TextChannelsCount { get; private set; } = 0; public int TextChannelsCount { get; private set; } = 0;
public int VoiceChannelsCount { get; private set; } = 0; public int VoiceChannelsCount { get; private set; } = 0;
private readonly Timer commandLogTimer = new Timer() {Interval = 10000}; private readonly Timer commandLogTimer = new Timer() { Interval = 10000 };
static NadekoStats() { } static NadekoStats() { }
private NadekoStats() { private NadekoStats()
{
var commandService = NadekoBot.Client.GetService<CommandService>(); var commandService = NadekoBot.Client.GetService<CommandService>();
statsStopwatch.Start(); statsStopwatch.Start();
@ -43,52 +47,66 @@ namespace NadekoBot {
TextChannelsCount = channelsArray.Count(c => c.Type == ChannelType.Text); TextChannelsCount = channelsArray.Count(c => c.Type == ChannelType.Text);
VoiceChannelsCount = channelsArray.Count() - TextChannelsCount; VoiceChannelsCount = channelsArray.Count() - TextChannelsCount;
NadekoBot.Client.JoinedServer += (s, e) => { NadekoBot.Client.JoinedServer += (s, e) =>
try { {
try
{
ServerCount++; ServerCount++;
TextChannelsCount += e.Server.TextChannels.Count(); TextChannelsCount += e.Server.TextChannels.Count();
VoiceChannelsCount += e.Server.VoiceChannels.Count(); VoiceChannelsCount += e.Server.VoiceChannels.Count();
} catch { } }
catch { }
}; };
NadekoBot.Client.LeftServer += (s, e) => { NadekoBot.Client.LeftServer += (s, e) =>
try { {
try
{
ServerCount--; ServerCount--;
TextChannelsCount -= e.Server.TextChannels.Count(); TextChannelsCount -= e.Server.TextChannels.Count();
VoiceChannelsCount -= e.Server.VoiceChannels.Count(); VoiceChannelsCount -= e.Server.VoiceChannels.Count();
} catch { } }
catch { }
}; };
NadekoBot.Client.ChannelCreated += (s, e) => { NadekoBot.Client.ChannelCreated += (s, e) =>
try { {
try
{
if (e.Channel.IsPrivate) if (e.Channel.IsPrivate)
return; return;
if (e.Channel.Type == ChannelType.Text) if (e.Channel.Type == ChannelType.Text)
TextChannelsCount++; TextChannelsCount++;
else if (e.Channel.Type == ChannelType.Voice) else if (e.Channel.Type == ChannelType.Voice)
VoiceChannelsCount++; VoiceChannelsCount++;
} catch { } }
catch { }
}; };
NadekoBot.Client.ChannelDestroyed += (s, e) => { NadekoBot.Client.ChannelDestroyed += (s, e) =>
try { {
try
{
if (e.Channel.IsPrivate) if (e.Channel.IsPrivate)
return; return;
if (e.Channel.Type == ChannelType.Text) if (e.Channel.Type == ChannelType.Text)
VoiceChannelsCount++; VoiceChannelsCount++;
else if (e.Channel.Type == ChannelType.Voice) else if (e.Channel.Type == ChannelType.Voice)
VoiceChannelsCount--; VoiceChannelsCount--;
} catch { } }
catch { }
}; };
} }
public TimeSpan GetUptime() => public TimeSpan GetUptime() =>
DateTime.Now - Process.GetCurrentProcess().StartTime; DateTime.Now - Process.GetCurrentProcess().StartTime;
public string GetUptimeString() { public string GetUptimeString()
{
var time = (DateTime.Now - Process.GetCurrentProcess().StartTime); var time = (DateTime.Now - Process.GetCurrentProcess().StartTime);
return time.Days + " days, " + time.Hours + " hours, and " + time.Minutes + " minutes."; return time.Days + " days, " + time.Hours + " hours, and " + time.Minutes + " minutes.";
} }
public Task LoadStats() => public Task LoadStats() =>
Task.Run(() => { Task.Run(() =>
{
var songs = Music.MusicPlayers.Count(mp => mp.Value.CurrentSong != null); var songs = Music.MusicPlayers.Count(mp => mp.Value.CurrentSong != null);
var sb = new System.Text.StringBuilder(); var sb = new System.Text.StringBuilder();
sb.AppendLine("`Author: Kwoth` `Library: Discord.Net`"); sb.AppendLine("`Author: Kwoth` `Library: Discord.Net`");
@ -102,7 +120,7 @@ namespace NadekoBot {
sb.AppendLine($" | VoiceChannels: {VoiceChannelsCount}`"); sb.AppendLine($" | VoiceChannels: {VoiceChannelsCount}`");
sb.AppendLine($"`Commands Ran this session: {commandsRan}`"); sb.AppendLine($"`Commands Ran this session: {commandsRan}`");
sb.AppendLine($"`Message queue size: {NadekoBot.Client.MessageQueue.Count}`"); sb.AppendLine($"`Message queue size: {NadekoBot.Client.MessageQueue.Count}`");
sb.Append($"`Greeted {Commands.ServerGreetCommand.Greeted} times.`"); sb.Append($"`Greeted {ServerGreetCommand.Greeted} times.`");
sb.AppendLine($" `| Playing {songs} songs, ".SnPl(songs) + sb.AppendLine($" `| Playing {songs} songs, ".SnPl(songs) +
$"{Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count)} queued.`"); $"{Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count)} queued.`");
sb.AppendLine($"`Heap: {Heap(false)}`"); sb.AppendLine($"`Heap: {Heap(false)}`");
@ -111,7 +129,8 @@ namespace NadekoBot {
public string Heap(bool pass = true) => Math.Round((double)GC.GetTotalMemory(pass) / 1.MiB(), 2).ToString(); public string Heap(bool pass = true) => Math.Round((double)GC.GetTotalMemory(pass) / 1.MiB(), 2).ToString();
public async Task<string> GetStats() { public async Task<string> GetStats()
{
if (statsStopwatch.Elapsed.Seconds < 4 && if (statsStopwatch.Elapsed.Seconds < 4 &&
!string.IsNullOrWhiteSpace(statsCache)) return statsCache; !string.IsNullOrWhiteSpace(statsCache)) return statsCache;
await LoadStats(); await LoadStats();
@ -119,35 +138,45 @@ namespace NadekoBot {
return statsCache; return statsCache;
} }
private async Task StartCollecting() { private async Task StartCollecting()
while (true) { {
while (true)
{
await Task.Delay(new TimeSpan(0, 30, 0)); await Task.Delay(new TimeSpan(0, 30, 0));
try { try
{
var onlineUsers = await Task.Run(() => NadekoBot.Client.Servers.Sum(x => x.Users.Count())); var onlineUsers = await Task.Run(() => NadekoBot.Client.Servers.Sum(x => x.Users.Count()));
var realOnlineUsers = await Task.Run(() => NadekoBot.Client.Servers var realOnlineUsers = await Task.Run(() => NadekoBot.Client.Servers
.Sum(x => x.Users.Count(u => u.Status == UserStatus.Online))); .Sum(x => x.Users.Count(u => u.Status == UserStatus.Online)));
var connectedServers = NadekoBot.Client.Servers.Count(); var connectedServers = NadekoBot.Client.Servers.Count();
Classes.DbHandler.Instance.InsertData(new Classes._DataModels.Stats { Classes.DbHandler.Instance.InsertData(new Classes._DataModels.Stats
{
OnlineUsers = onlineUsers, OnlineUsers = onlineUsers,
RealOnlineUsers = realOnlineUsers, RealOnlineUsers = realOnlineUsers,
Uptime = GetUptime(), Uptime = GetUptime(),
ConnectedServers = connectedServers, ConnectedServers = connectedServers,
DateAdded = DateTime.Now DateAdded = DateTime.Now
}); });
} catch { }
catch
{
Console.WriteLine("DB Exception in stats collecting."); Console.WriteLine("DB Exception in stats collecting.");
break; break;
} }
} }
} }
private async void StatsCollector_RanCommand(object sender, CommandEventArgs e) { private async void StatsCollector_RanCommand(object sender, CommandEventArgs e)
{
Console.WriteLine($">>Command {e.Command.Text}"); Console.WriteLine($">>Command {e.Command.Text}");
await Task.Run(() => { await Task.Run(() =>
try { {
try
{
commandsRan++; commandsRan++;
Classes.DbHandler.Instance.InsertData(new Classes._DataModels.Command { Classes.DbHandler.Instance.InsertData(new Classes._DataModels.Command
{
ServerId = (long)e.Server.Id, ServerId = (long)e.Server.Id,
ServerName = e.Server.Name, ServerName = e.Server.Name,
ChannelId = (long)e.Channel.Id, ChannelId = (long)e.Channel.Id,
@ -157,7 +186,9 @@ namespace NadekoBot {
CommandName = e.Command.Text, CommandName = e.Command.Text,
DateAdded = DateTime.Now DateAdded = DateTime.Now
}); });
} catch { }
catch
{
Console.WriteLine("Error in ran command DB write."); Console.WriteLine("Error in ran command DB write.");
} }
}); });

View File

@ -1,27 +1,29 @@
using System; using Discord;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Discord;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using NadekoBot.Modules; using NadekoBot.Modules;
using System;
using System.Linq;
using ServerPermissions = NadekoBot.Classes.Permissions.ServerPermissions; using ServerPermissions = NadekoBot.Classes.Permissions.ServerPermissions;
namespace NadekoBot.Commands { namespace NadekoBot.Commands
internal class FilterWords : DiscordCommand { {
public FilterWords(DiscordModule module) : base(module) { internal class FilterWords : DiscordCommand
NadekoBot.Client.MessageReceived += async (sender, args) => { {
public FilterWords(DiscordModule module) : base(module)
{
NadekoBot.Client.MessageReceived += async (sender, args) =>
{
if (args.Channel.IsPrivate || args.User.Id == NadekoBot.Client.CurrentUser.Id) return; if (args.Channel.IsPrivate || args.User.Id == NadekoBot.Client.CurrentUser.Id) return;
try { try
{
ServerPermissions serverPerms; ServerPermissions serverPerms;
if (!IsChannelOrServerFiltering(args.Channel, out serverPerms)) return; if (!IsChannelOrServerFiltering(args.Channel, out serverPerms)) return;
var wordsInMessage = args.Message.RawText.ToLowerInvariant().Split(' '); var wordsInMessage = args.Message.RawText.ToLowerInvariant().Split(' ');
if (serverPerms.Words.Any(w => wordsInMessage.Contains(w))) { if (serverPerms.Words.Any(w => wordsInMessage.Contains(w)))
{
await args.Message.Delete(); await args.Message.Delete();
IncidentsHandler.Add(args.Server.Id, $"User [{args.User.Name}/{args.User.Id}] posted " + IncidentsHandler.Add(args.Server.Id, $"User [{args.User.Name}/{args.User.Id}] posted " +
$"BANNED WORD in [{args.Channel.Name}/{args.Channel.Id}] channel. " + $"BANNED WORD in [{args.Channel.Name}/{args.Channel.Id}] channel. " +
@ -30,11 +32,13 @@ namespace NadekoBot.Commands {
await args.Channel.SendMessage($"{args.User.Mention} One or more of the words you used " + await args.Channel.SendMessage($"{args.User.Mention} One or more of the words you used " +
$"in that sentence are not allowed here."); $"in that sentence are not allowed here.");
} }
} catch { } }
catch { }
}; };
} }
private static bool IsChannelOrServerFiltering(Channel channel, out ServerPermissions serverPerms) { private static bool IsChannelOrServerFiltering(Channel channel, out ServerPermissions serverPerms)
{
if (!PermissionsHandler.PermissionsDict.TryGetValue(channel.Server.Id, out serverPerms)) return false; if (!PermissionsHandler.PermissionsDict.TryGetValue(channel.Server.Id, out serverPerms)) return false;
if (serverPerms.Permissions.FilterWords) if (serverPerms.Permissions.FilterWords)
@ -44,7 +48,8 @@ namespace NadekoBot.Commands {
return serverPerms.ChannelPermissions.TryGetValue(channel.Id, out perms) && perms.FilterWords; return serverPerms.ChannelPermissions.TryGetValue(channel.Id, out perms) && perms.FilterWords;
} }
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "cfw") cgb.CreateCommand(Module.Prefix + "cfw")
.Alias(Module.Prefix + "channelfilterwords") .Alias(Module.Prefix + "channelfilterwords")
.Description("Enables or disables automatic deleting of messages containing banned words on the channel." + .Description("Enables or disables automatic deleting of messages containing banned words on the channel." +
@ -52,12 +57,15 @@ namespace NadekoBot.Commands {
"\n**Usage**: ;cfi enable #general-chat") "\n**Usage**: ;cfi enable #general-chat")
.Parameter("bool") .Parameter("bool")
.Parameter("channel", ParameterType.Optional) .Parameter("channel", ParameterType.Optional)
.Do(async e => { .Do(async e =>
try { {
try
{
var state = PermissionHelper.ValidateBool(e.GetArg("bool")); var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
var chanStr = e.GetArg("channel")?.ToLowerInvariant().Trim(); var chanStr = e.GetArg("channel")?.ToLowerInvariant().Trim();
if (chanStr != "all") { if (chanStr != "all")
{
var chan = string.IsNullOrWhiteSpace(chanStr) var chan = string.IsNullOrWhiteSpace(chanStr)
? e.Channel ? e.Channel
: PermissionHelper.ValidateChannel(e.Server, chanStr); : PermissionHelper.ValidateChannel(e.Server, chanStr);
@ -67,11 +75,14 @@ namespace NadekoBot.Commands {
} }
//all channels //all channels
foreach (var curChannel in e.Server.TextChannels) { foreach (var curChannel in e.Server.TextChannels)
{
PermissionsHandler.SetChannelWordPermission(curChannel, state); PermissionsHandler.SetChannelWordPermission(curChannel, state);
} }
await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **ALL** channels."); await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **ALL** channels.");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($"💢 Error: {ex.Message}"); await e.Channel.SendMessage($"💢 Error: {ex.Message}");
} }
}); });
@ -81,15 +92,19 @@ namespace NadekoBot.Commands {
.Description("Adds a new word to the list of filtered words" + .Description("Adds a new word to the list of filtered words" +
"\n**Usage**: ;aw poop") "\n**Usage**: ;aw poop")
.Parameter("word", ParameterType.Unparsed) .Parameter("word", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
try { {
try
{
var word = e.GetArg("word"); var word = e.GetArg("word");
if (string.IsNullOrWhiteSpace(word)) if (string.IsNullOrWhiteSpace(word))
return; return;
PermissionsHandler.AddFilteredWord(e.Server, word.ToLowerInvariant().Trim()); PermissionsHandler.AddFilteredWord(e.Server, word.ToLowerInvariant().Trim());
await e.Channel.SendMessage($"Successfully added new filtered word."); await e.Channel.SendMessage($"Successfully added new filtered word.");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($"💢 Error: {ex.Message}"); await e.Channel.SendMessage($"💢 Error: {ex.Message}");
} }
}); });
@ -99,15 +114,19 @@ namespace NadekoBot.Commands {
.Description("Removes the word from the list of filtered words" + .Description("Removes the word from the list of filtered words" +
"\n**Usage**: ;rw poop") "\n**Usage**: ;rw poop")
.Parameter("word", ParameterType.Unparsed) .Parameter("word", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
try { {
try
{
var word = e.GetArg("word"); var word = e.GetArg("word");
if (string.IsNullOrWhiteSpace(word)) if (string.IsNullOrWhiteSpace(word))
return; return;
PermissionsHandler.RemoveFilteredWord(e.Server, word.ToLowerInvariant().Trim()); PermissionsHandler.RemoveFilteredWord(e.Server, word.ToLowerInvariant().Trim());
await e.Channel.SendMessage($"Successfully removed filtered word."); await e.Channel.SendMessage($"Successfully removed filtered word.");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($"💢 Error: {ex.Message}"); await e.Channel.SendMessage($"💢 Error: {ex.Message}");
} }
}); });
@ -116,14 +135,18 @@ namespace NadekoBot.Commands {
.Alias(Module.Prefix + "listfilteredwords") .Alias(Module.Prefix + "listfilteredwords")
.Description("Shows a list of filtered words" + .Description("Shows a list of filtered words" +
"\n**Usage**: ;lfw") "\n**Usage**: ;lfw")
.Do(async e => { .Do(async e =>
try { {
try
{
ServerPermissions serverPerms; ServerPermissions serverPerms;
if (!PermissionsHandler.PermissionsDict.TryGetValue(e.Server.Id, out serverPerms)) if (!PermissionsHandler.PermissionsDict.TryGetValue(e.Server.Id, out serverPerms))
return; return;
await e.Channel.SendMessage($"There are `{serverPerms.Words.Count}` filtered words.\n" + await e.Channel.SendMessage($"There are `{serverPerms.Words.Count}` filtered words.\n" +
string.Join("\n", serverPerms.Words)); string.Join("\n", serverPerms.Words));
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($"💢 Error: {ex.Message}"); await e.Channel.SendMessage($"💢 Error: {ex.Message}");
} }
}); });
@ -132,13 +155,17 @@ namespace NadekoBot.Commands {
.Alias(Module.Prefix + "serverfilterwords") .Alias(Module.Prefix + "serverfilterwords")
.Description("Enables or disables automatic deleting of messages containing forbidden words on the server.\n**Usage**: ;sfi disable") .Description("Enables or disables automatic deleting of messages containing forbidden words on the server.\n**Usage**: ;sfi disable")
.Parameter("bool") .Parameter("bool")
.Do(async e => { .Do(async e =>
try { {
try
{
var state = PermissionHelper.ValidateBool(e.GetArg("bool")); var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
PermissionsHandler.SetServerWordPermission(e.Server, state); PermissionsHandler.SetServerWordPermission(e.Server, state);
await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** on this server."); await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** on this server.");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($"💢 Error: {ex.Message}"); await e.Channel.SendMessage($"💢 Error: {ex.Message}");
} }
}); });

View File

@ -4,19 +4,19 @@ using Discord.Modules;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Classes._DataModels;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using NadekoBot.Commands;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using NadekoBot.Modules.Administration.Commands;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace NadekoBot.Modules namespace NadekoBot.Modules.Administration
{ {
internal class Administration : DiscordModule internal class AdministrationModule : DiscordModule
{ {
public Administration() public AdministrationModule()
{ {
commands.Add(new ServerGreetCommand(this)); commands.Add(new ServerGreetCommand(this));
commands.Add(new LogCommand(this)); commands.Add(new LogCommand(this));

View File

@ -1,36 +1,48 @@
using System; using Discord;
using Discord.Commands;
using NadekoBot.Classes.Permissions;
using NadekoBot.Commands;
using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Discord;
using Discord.Commands;
using NadekoBot.Classes.Permissions;
using NadekoBot.Modules;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
class CrossServerTextChannel : DiscordCommand { {
public CrossServerTextChannel(DiscordModule module) : base(module) { class CrossServerTextChannel : DiscordCommand
NadekoBot.Client.MessageReceived += async (s, e) => { {
try { public CrossServerTextChannel(DiscordModule module) : base(module)
{
NadekoBot.Client.MessageReceived += async (s, e) =>
{
try
{
if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return; if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return;
foreach (var subscriber in Subscribers) { foreach (var subscriber in Subscribers)
{
var set = subscriber.Value; var set = subscriber.Value;
if (!set.Contains(e.Channel)) if (!set.Contains(e.Channel))
continue; continue;
foreach (var chan in set.Except(new[] { e.Channel })) { foreach (var chan in set.Except(new[] { e.Channel }))
{
await chan.SendMessage(GetText(e.Server, e.Channel, e.User, e.Message)); await chan.SendMessage(GetText(e.Server, e.Channel, e.User, e.Message));
} }
} }
} catch { } }
catch { }
}; };
NadekoBot.Client.MessageUpdated += async (s, e) => { NadekoBot.Client.MessageUpdated += async (s, e) =>
try { {
try
{
if (e.After?.User?.Id == null || e.After.User.Id == NadekoBot.Client.CurrentUser.Id) return; if (e.After?.User?.Id == null || e.After.User.Id == NadekoBot.Client.CurrentUser.Id) return;
foreach (var subscriber in Subscribers) { foreach (var subscriber in Subscribers)
{
var set = subscriber.Value; var set = subscriber.Value;
if (!set.Contains(e.Channel)) if (!set.Contains(e.Channel))
continue; continue;
foreach (var chan in set.Except(new[] { e.Channel })) { foreach (var chan in set.Except(new[] { e.Channel }))
{
var msg = chan.Messages var msg = chan.Messages
.FirstOrDefault(m => .FirstOrDefault(m =>
m.RawText == GetText(e.Server, e.Channel, e.User, e.Before)); m.RawText == GetText(e.Server, e.Channel, e.User, e.Before));
@ -39,7 +51,8 @@ namespace NadekoBot.Commands {
} }
} }
} catch { } }
catch { }
}; };
} }
@ -48,15 +61,18 @@ namespace NadekoBot.Commands {
public static readonly ConcurrentDictionary<int, HashSet<Channel>> Subscribers = new ConcurrentDictionary<int, HashSet<Channel>>(); public static readonly ConcurrentDictionary<int, HashSet<Channel>> Subscribers = new ConcurrentDictionary<int, HashSet<Channel>>();
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "scsc") cgb.CreateCommand(Module.Prefix + "scsc")
.Description("Starts an instance of cross server channel. You will get a token as a DM" + .Description("Starts an instance of cross server channel. You will get a token as a DM" +
"that other people will use to tune in to the same instance") "that other people will use to tune in to the same instance")
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => { .Do(async e =>
{
var token = new Random().Next(); var token = new Random().Next();
var set = new HashSet<Channel>(); var set = new HashSet<Channel>();
if (Subscribers.TryAdd(token, set)) { if (Subscribers.TryAdd(token, set))
{
set.Add(e.Channel); set.Add(e.Channel);
await e.User.SendMessage("This is your CSC token:" + token.ToString()); await e.User.SendMessage("This is your CSC token:" + token.ToString());
} }
@ -66,7 +82,8 @@ namespace NadekoBot.Commands {
.Description("Joins current channel to an instance of cross server channel using the token.") .Description("Joins current channel to an instance of cross server channel using the token.")
.Parameter("token") .Parameter("token")
.AddCheck(SimpleCheckers.ManageServer()) .AddCheck(SimpleCheckers.ManageServer())
.Do(async e => { .Do(async e =>
{
int token; int token;
if (!int.TryParse(e.GetArg("token"), out token)) if (!int.TryParse(e.GetArg("token"), out token))
return; return;
@ -80,8 +97,10 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "lcsc") cgb.CreateCommand(Module.Prefix + "lcsc")
.Description("Leaves Cross server channel instance from this channel") .Description("Leaves Cross server channel instance from this channel")
.AddCheck(SimpleCheckers.ManageServer()) .AddCheck(SimpleCheckers.ManageServer())
.Do(async e => { .Do(async e =>
foreach (var subscriber in Subscribers) { {
foreach (var subscriber in Subscribers)
{
subscriber.Value.Remove(e.Channel); subscriber.Value.Remove(e.Channel);
} }
await e.Channel.SendMessage(":ok:"); await e.Channel.SendMessage(":ok:");

View File

@ -2,13 +2,13 @@
using Discord.Commands; using Discord.Commands;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using NadekoBot.Modules; using NadekoBot.Commands;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace NadekoBot.Commands namespace NadekoBot.Modules.Administration.Commands
{ {
internal class LogCommand : DiscordCommand internal class LogCommand : DiscordCommand
{ {

View File

@ -1,15 +1,18 @@
using System; using Discord;
using System.Timers;
using System.Collections.Concurrent;
using Discord;
using NadekoBot.Classes.Permissions;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Modules; using NadekoBot.Classes.Permissions;
using NadekoBot.Commands;
using System;
using System.Collections.Concurrent;
using System.Timers;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
class MessageRepeater : DiscordCommand { {
class MessageRepeater : DiscordCommand
{
private readonly ConcurrentDictionary<Server, Repeater> repeaters = new ConcurrentDictionary<Server, Repeater>(); private readonly ConcurrentDictionary<Server, Repeater> repeaters = new ConcurrentDictionary<Server, Repeater>();
private class Repeater { private class Repeater
{
[Newtonsoft.Json.JsonIgnore] [Newtonsoft.Json.JsonIgnore]
public Timer MessageTimer { get; set; } public Timer MessageTimer { get; set; }
[Newtonsoft.Json.JsonIgnore] [Newtonsoft.Json.JsonIgnore]
@ -20,21 +23,27 @@ namespace NadekoBot.Commands {
public string RepeatingMessage { get; set; } public string RepeatingMessage { get; set; }
public int Interval { get; set; } public int Interval { get; set; }
public Repeater Start() { public Repeater Start()
{
MessageTimer = new Timer { Interval = Interval }; MessageTimer = new Timer { Interval = Interval };
MessageTimer.Elapsed += async (s, e) => { MessageTimer.Elapsed += async (s, e) =>
{
var ch = RepeatingChannel; var ch = RepeatingChannel;
var msg = RepeatingMessage; var msg = RepeatingMessage;
if (ch != null && !string.IsNullOrWhiteSpace(msg)) { if (ch != null && !string.IsNullOrWhiteSpace(msg))
try { {
try
{
await ch.SendMessage(msg); await ch.SendMessage(msg);
} catch { } }
catch { }
} }
}; };
return this; return this;
} }
} }
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "repeat") cgb.CreateCommand(Module.Prefix + "repeat")
.Description("Repeat a message every X minutes. If no parameters are specified, " + .Description("Repeat a message every X minutes. If no parameters are specified, " +
@ -42,12 +51,14 @@ namespace NadekoBot.Commands {
.Parameter("minutes", ParameterType.Optional) .Parameter("minutes", ParameterType.Optional)
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.ManageMessages()) .AddCheck(SimpleCheckers.ManageMessages())
.Do(async e => { .Do(async e =>
{
var minutesStr = e.GetArg("minutes"); var minutesStr = e.GetArg("minutes");
var msg = e.GetArg("msg"); var msg = e.GetArg("msg");
// if both null, disable // if both null, disable
if (string.IsNullOrWhiteSpace(msg) && string.IsNullOrWhiteSpace(minutesStr)) { if (string.IsNullOrWhiteSpace(msg) && string.IsNullOrWhiteSpace(minutesStr))
{
await e.Channel.SendMessage("Repeating disabled"); await e.Channel.SendMessage("Repeating disabled");
Repeater rep; Repeater rep;
if (repeaters.TryGetValue(e.Server, out rep)) if (repeaters.TryGetValue(e.Server, out rep))
@ -55,14 +66,16 @@ namespace NadekoBot.Commands {
return; return;
} }
int minutes; int minutes;
if (!int.TryParse(minutesStr, out minutes) || minutes < 1 || minutes > 720) { if (!int.TryParse(minutesStr, out minutes) || minutes < 1 || minutes > 720)
{
await e.Channel.SendMessage("Invalid value"); await e.Channel.SendMessage("Invalid value");
return; return;
} }
var repeater = repeaters.GetOrAdd( var repeater = repeaters.GetOrAdd(
e.Server, e.Server,
s => new Repeater { s => new Repeater
{
Interval = minutes * 60 * 1000, Interval = minutes * 60 * 1000,
RepeatingChannel = e.Channel, RepeatingChannel = e.Channel,
RepeatingChannelId = e.Channel.Id, RepeatingChannelId = e.Channel.Id,
@ -82,6 +95,6 @@ namespace NadekoBot.Commands {
}); });
} }
public MessageRepeater(DiscordModule module) : base(module) {} public MessageRepeater(DiscordModule module) : base(module) { }
} }
} }

View File

@ -1,15 +1,17 @@
using System; using Discord.Commands;
using NadekoBot.Classes.JSONModels;
using NadekoBot.Commands;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.Commands;
using System.Timers; using System.Timers;
using NadekoBot.Classes.JSONModels;
using NadekoBot.Modules;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
internal class PlayingRotate : DiscordCommand { {
internal class PlayingRotate : DiscordCommand
{
private static readonly Timer timer = new Timer(12000); private static readonly Timer timer = new Timer(12000);
public static Dictionary<string, Func<string>> PlayingPlaceholders { get; } = public static Dictionary<string, Func<string>> PlayingPlaceholders { get; } =
@ -34,16 +36,21 @@ namespace NadekoBot.Commands {
private readonly object playingPlaceholderLock = new object(); private readonly object playingPlaceholderLock = new object();
public PlayingRotate(DiscordModule module) : base(module) { public PlayingRotate(DiscordModule module) : base(module)
{
var i = -1; var i = -1;
timer.Elapsed += (s, e) => { timer.Elapsed += (s, e) =>
try { {
try
{
i++; i++;
var status = ""; var status = "";
lock (playingPlaceholderLock) { lock (playingPlaceholderLock)
{
if (PlayingPlaceholders.Count == 0) if (PlayingPlaceholders.Count == 0)
return; return;
if (i >= PlayingPlaceholders.Count) { if (i >= PlayingPlaceholders.Count)
{
i = -1; i = -1;
return; return;
} }
@ -54,14 +61,17 @@ namespace NadekoBot.Commands {
if (string.IsNullOrWhiteSpace(status)) if (string.IsNullOrWhiteSpace(status))
return; return;
Task.Run(() => { NadekoBot.Client.SetGame(status); }); Task.Run(() => { NadekoBot.Client.SetGame(status); });
} catch { } }
catch { }
}; };
timer.Enabled = NadekoBot.Config.IsRotatingStatus; timer.Enabled = NadekoBot.Config.IsRotatingStatus;
} }
public Func<CommandEventArgs, Task> DoFunc() => async e => { public Func<CommandEventArgs, Task> DoFunc() => async e =>
lock (playingPlaceholderLock) { {
lock (playingPlaceholderLock)
{
if (timer.Enabled) if (timer.Enabled)
timer.Stop(); timer.Stop();
else else
@ -72,7 +82,8 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage($"❗`Rotating playing status has been {(timer.Enabled ? "enabled" : "disabled")}.`"); await e.Channel.SendMessage($"❗`Rotating playing status has been {(timer.Enabled ? "enabled" : "disabled")}.`");
}; };
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "rotateplaying") cgb.CreateCommand(Module.Prefix + "rotateplaying")
.Alias(Module.Prefix + "ropl") .Alias(Module.Prefix + "ropl")
.Description("Toggles rotation of playing status of the dynamic strings you specified earlier.") .Description("Toggles rotation of playing status of the dynamic strings you specified earlier.")
@ -85,11 +96,13 @@ namespace NadekoBot.Commands {
"Supported placeholders: " + string.Join(", ", PlayingPlaceholders.Keys)) "Supported placeholders: " + string.Join(", ", PlayingPlaceholders.Keys))
.Parameter("text", ParameterType.Unparsed) .Parameter("text", ParameterType.Unparsed)
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly()) .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(async e => { .Do(async e =>
{
var arg = e.GetArg("text"); var arg = e.GetArg("text");
if (string.IsNullOrWhiteSpace(arg)) if (string.IsNullOrWhiteSpace(arg))
return; return;
lock (playingPlaceholderLock) { lock (playingPlaceholderLock)
{
NadekoBot.Config.RotatingStatuses.Add(arg); NadekoBot.Config.RotatingStatuses.Add(arg);
ConfigHandler.SaveConfig(); ConfigHandler.SaveConfig();
} }
@ -100,12 +113,14 @@ namespace NadekoBot.Commands {
.Alias(Module.Prefix + "lipl") .Alias(Module.Prefix + "lipl")
.Description("Lists all playing statuses with their corresponding number.") .Description("Lists all playing statuses with their corresponding number.")
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly()) .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(async e => { .Do(async e =>
{
if (NadekoBot.Config.RotatingStatuses.Count == 0) if (NadekoBot.Config.RotatingStatuses.Count == 0)
await e.Channel.SendMessage("`There are no playing strings. " + await e.Channel.SendMessage("`There are no playing strings. " +
"Add some with .addplaying [text] command.`"); "Add some with .addplaying [text] command.`");
var sb = new StringBuilder(); var sb = new StringBuilder();
for (var i = 0; i < NadekoBot.Config.RotatingStatuses.Count; i++) { for (var i = 0; i < NadekoBot.Config.RotatingStatuses.Count; i++)
{
sb.AppendLine($"`{i + 1}.` {NadekoBot.Config.RotatingStatuses[i]}"); sb.AppendLine($"`{i + 1}.` {NadekoBot.Config.RotatingStatuses[i]}");
} }
await e.Channel.SendMessage(sb.ToString()); await e.Channel.SendMessage(sb.ToString());
@ -116,11 +131,13 @@ namespace NadekoBot.Commands {
.Description("Removes a playing string on a given number.") .Description("Removes a playing string on a given number.")
.Parameter("number", ParameterType.Required) .Parameter("number", ParameterType.Required)
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly()) .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(async e => { .Do(async e =>
{
var arg = e.GetArg("number"); var arg = e.GetArg("number");
int num; int num;
string str; string str;
lock (playingPlaceholderLock) { lock (playingPlaceholderLock)
{
if (!int.TryParse(arg.Trim(), out num) || num <= 0 || num > NadekoBot.Config.RotatingStatuses.Count) if (!int.TryParse(arg.Trim(), out num) || num <= 0 || num > NadekoBot.Config.RotatingStatuses.Count)
return; return;
str = NadekoBot.Config.RotatingStatuses[num - 1]; str = NadekoBot.Config.RotatingStatuses[num - 1];

View File

@ -1,28 +1,36 @@
using System;
using System.Collections.Concurrent;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using NadekoBot.Modules; using NadekoBot.Commands;
using System;
using System.Collections.Concurrent;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
internal class RatelimitCommand : DiscordCommand { {
internal class RatelimitCommand : DiscordCommand
{
public static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>> RatelimitingChannels = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>>(); public static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>> RatelimitingChannels = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>>();
private static readonly TimeSpan ratelimitTime = new TimeSpan(0, 0, 0, 5); private static readonly TimeSpan ratelimitTime = new TimeSpan(0, 0, 0, 5);
public RatelimitCommand(DiscordModule module) : base(module) { public RatelimitCommand(DiscordModule module) : base(module)
NadekoBot.Client.MessageReceived += async (s, e) => { {
NadekoBot.Client.MessageReceived += async (s, e) =>
{
if (e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id) if (e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
return; return;
ConcurrentDictionary<ulong, DateTime> userTimePair; ConcurrentDictionary<ulong, DateTime> userTimePair;
if (!RatelimitingChannels.TryGetValue(e.Channel.Id, out userTimePair)) return; if (!RatelimitingChannels.TryGetValue(e.Channel.Id, out userTimePair)) return;
DateTime lastMessageTime; DateTime lastMessageTime;
if (userTimePair.TryGetValue(e.User.Id, out lastMessageTime)) { if (userTimePair.TryGetValue(e.User.Id, out lastMessageTime))
if (DateTime.Now - lastMessageTime < ratelimitTime) { {
try { if (DateTime.Now - lastMessageTime < ratelimitTime)
{
try
{
await e.Message.Delete(); await e.Message.Delete();
} catch { } }
catch { }
return; return;
} }
} }
@ -30,23 +38,27 @@ namespace NadekoBot.Commands {
}; };
} }
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "slowmode") cgb.CreateCommand(Module.Prefix + "slowmode")
.Description("Toggles slow mode. When ON, users will be able to send only 1 message every 5 seconds.") .Description("Toggles slow mode. When ON, users will be able to send only 1 message every 5 seconds.")
.Parameter("minutes", ParameterType.Optional) .Parameter("minutes", ParameterType.Optional)
.AddCheck(SimpleCheckers.ManageMessages()) .AddCheck(SimpleCheckers.ManageMessages())
.Do(async e => { .Do(async e =>
{
//var minutesStr = e.GetArg("minutes"); //var minutesStr = e.GetArg("minutes");
//if (string.IsNullOrWhiteSpace(minutesStr)) { //if (string.IsNullOrWhiteSpace(minutesStr)) {
// RatelimitingChannels.Remove(e.Channel.Id); // RatelimitingChannels.Remove(e.Channel.Id);
// return; // return;
//} //}
ConcurrentDictionary<ulong, DateTime> throwaway; ConcurrentDictionary<ulong, DateTime> throwaway;
if (RatelimitingChannels.TryRemove(e.Channel.Id, out throwaway)) { if (RatelimitingChannels.TryRemove(e.Channel.Id, out throwaway))
{
await e.Channel.SendMessage("Slow mode disabled."); await e.Channel.SendMessage("Slow mode disabled.");
return; return;
} }
if (RatelimitingChannels.TryAdd(e.Channel.Id, new ConcurrentDictionary<ulong, DateTime>())) { if (RatelimitingChannels.TryAdd(e.Channel.Id, new ConcurrentDictionary<ulong, DateTime>()))
{
await e.Channel.SendMessage("Slow mode initiated. " + await e.Channel.SendMessage("Slow mode initiated. " +
"Users can't send more than 1 message every 5 seconds."); "Users can't send more than 1 message every 5 seconds.");
} }

View File

@ -1,29 +1,35 @@
using System.Collections.Generic; using Discord.Commands;
using System.Linq;
using System.Text;
using Discord.Commands;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using NadekoBot.Modules; using NadekoBot.Commands;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
internal class SelfAssignedRolesCommand : DiscordCommand { {
internal class SelfAssignedRolesCommand : DiscordCommand
{
public SelfAssignedRolesCommand(DiscordModule module) : base(module) { } public SelfAssignedRolesCommand(DiscordModule module) : base(module) { }
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(".asar") cgb.CreateCommand(".asar")
.Description("Adds a role, or list of roles separated by whitespace" + .Description("Adds a role, or list of roles separated by whitespace" +
"(use quotations for multiword roles) to the list of self-assignable roles.\n**Usage**: .asar Gamer") "(use quotations for multiword roles) to the list of self-assignable roles.\n**Usage**: .asar Gamer")
.Parameter("roles", ParameterType.Multiple) .Parameter("roles", ParameterType.Multiple)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => { .Do(async e =>
{
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
var msg = new StringBuilder(); var msg = new StringBuilder();
foreach (var arg in e.Args) { foreach (var arg in e.Args)
{
var role = e.Server.FindRoles(arg.Trim()).FirstOrDefault(); var role = e.Server.FindRoles(arg.Trim()).FirstOrDefault();
if (role == null) if (role == null)
msg.AppendLine($":anger:Role **{arg}** not found."); msg.AppendLine($":anger:Role **{arg}** not found.");
else { else {
if (config.ListOfSelfAssignableRoles.Contains(role.Id)) { if (config.ListOfSelfAssignableRoles.Contains(role.Id))
{
msg.AppendLine($":anger:Role **{role.Name}** is already in the list."); msg.AppendLine($":anger:Role **{role.Name}** is already in the list.");
continue; continue;
} }
@ -38,17 +44,20 @@ namespace NadekoBot.Commands {
.Description("Removes a specified role from the list of self-assignable roles.") .Description("Removes a specified role from the list of self-assignable roles.")
.Parameter("role", ParameterType.Unparsed) .Parameter("role", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => { .Do(async e =>
{
var roleName = e.GetArg("role")?.Trim(); var roleName = e.GetArg("role")?.Trim();
if (string.IsNullOrWhiteSpace(roleName)) if (string.IsNullOrWhiteSpace(roleName))
return; return;
var role = e.Server.FindRoles(roleName).FirstOrDefault(); var role = e.Server.FindRoles(roleName).FirstOrDefault();
if (role == null) { if (role == null)
{
await e.Channel.SendMessage(":anger:That role does not exist."); await e.Channel.SendMessage(":anger:That role does not exist.");
return; return;
} }
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (!config.ListOfSelfAssignableRoles.Contains(role.Id)) { if (!config.ListOfSelfAssignableRoles.Contains(role.Id))
{
await e.Channel.SendMessage(":anger:That role is not self-assignable."); await e.Channel.SendMessage(":anger:That role is not self-assignable.");
return; return;
} }
@ -59,20 +68,25 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(".lsar") cgb.CreateCommand(".lsar")
.Description("Lits all self-assignable roles.") .Description("Lits all self-assignable roles.")
.Parameter("roles", ParameterType.Multiple) .Parameter("roles", ParameterType.Multiple)
.Do(async e => { .Do(async e =>
{
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
var msg = new StringBuilder($"There are `{config.ListOfSelfAssignableRoles.Count}` self assignable roles:\n"); var msg = new StringBuilder($"There are `{config.ListOfSelfAssignableRoles.Count}` self assignable roles:\n");
var toRemove = new HashSet<ulong>(); var toRemove = new HashSet<ulong>();
foreach (var roleId in config.ListOfSelfAssignableRoles) { foreach (var roleId in config.ListOfSelfAssignableRoles)
{
var role = e.Server.GetRole(roleId); var role = e.Server.GetRole(roleId);
if (role == null) { if (role == null)
{
msg.Append($"`{roleId} not found. Cleaned up.`, "); msg.Append($"`{roleId} not found. Cleaned up.`, ");
toRemove.Add(roleId); toRemove.Add(roleId);
} else { }
else {
msg.Append($"**{role.Name}**, "); msg.Append($"**{role.Name}**, ");
} }
} }
foreach (var id in toRemove) { foreach (var id in toRemove)
{
config.ListOfSelfAssignableRoles.Remove(id); config.ListOfSelfAssignableRoles.Remove(id);
} }
await e.Channel.SendMessage(msg.ToString()); await e.Channel.SendMessage(msg.ToString());
@ -83,21 +97,25 @@ namespace NadekoBot.Commands {
"Role must be on a list of self-assignable roles." + "Role must be on a list of self-assignable roles." +
"\n**Usage**: .iam Gamer") "\n**Usage**: .iam Gamer")
.Parameter("role", ParameterType.Unparsed) .Parameter("role", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
var roleName = e.GetArg("role")?.Trim(); var roleName = e.GetArg("role")?.Trim();
if (string.IsNullOrWhiteSpace(roleName)) if (string.IsNullOrWhiteSpace(roleName))
return; return;
var role = e.Server.FindRoles(roleName).FirstOrDefault(); var role = e.Server.FindRoles(roleName).FirstOrDefault();
if (role == null) { if (role == null)
{
await e.Channel.SendMessage(":anger:That role does not exist."); await e.Channel.SendMessage(":anger:That role does not exist.");
return; return;
} }
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (!config.ListOfSelfAssignableRoles.Contains(role.Id)) { if (!config.ListOfSelfAssignableRoles.Contains(role.Id))
{
await e.Channel.SendMessage(":anger:That role is not self-assignable."); await e.Channel.SendMessage(":anger:That role is not self-assignable.");
return; return;
} }
if (e.User.HasRole(role)) { if (e.User.HasRole(role))
{
await e.Channel.SendMessage($":anger:You already have {role.Name} role."); await e.Channel.SendMessage($":anger:You already have {role.Name} role.");
return; return;
} }
@ -111,21 +129,25 @@ namespace NadekoBot.Commands {
"Role must be on a list of self-assignable roles." + "Role must be on a list of self-assignable roles." +
"\n**Usage**: .iamn Gamer") "\n**Usage**: .iamn Gamer")
.Parameter("role", ParameterType.Unparsed) .Parameter("role", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
var roleName = e.GetArg("role")?.Trim(); var roleName = e.GetArg("role")?.Trim();
if (string.IsNullOrWhiteSpace(roleName)) if (string.IsNullOrWhiteSpace(roleName))
return; return;
var role = e.Server.FindRoles(roleName).FirstOrDefault(); var role = e.Server.FindRoles(roleName).FirstOrDefault();
if (role == null) { if (role == null)
{
await e.Channel.SendMessage(":anger:That role does not exist."); await e.Channel.SendMessage(":anger:That role does not exist.");
return; return;
} }
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (!config.ListOfSelfAssignableRoles.Contains(role.Id)) { if (!config.ListOfSelfAssignableRoles.Contains(role.Id))
{
await e.Channel.SendMessage(":anger:That role is not self-assignable."); await e.Channel.SendMessage(":anger:That role is not self-assignable.");
return; return;
} }
if (!e.User.HasRole(role)) { if (!e.User.HasRole(role))
{
await e.Channel.SendMessage($":anger:You don't have {role.Name} role."); await e.Channel.SendMessage($":anger:You don't have {role.Name} role.");
return; return;
} }

View File

@ -1,12 +1,9 @@
using System; using Discord;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Discord.Commands; using Discord.Commands;
using System.Collections.Concurrent; using NadekoBot.Commands;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using Discord; using System.Collections.Concurrent;
using NadekoBot.Modules; using System.Linq;
/* Voltana's legacy /* Voltana's legacy
public class AsyncLazy<T> : Lazy<Task<T>> public class AsyncLazy<T> : Lazy<Task<T>>
@ -21,14 +18,17 @@ public class AsyncLazy<T> : Lazy<Task<T>>
} }
*/ */
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
internal class ServerGreetCommand : DiscordCommand { {
internal class ServerGreetCommand : DiscordCommand
{
public static ConcurrentDictionary<ulong, AnnounceControls> AnnouncementsDictionary; public static ConcurrentDictionary<ulong, AnnounceControls> AnnouncementsDictionary;
public static long Greeted = 0; public static long Greeted = 0;
public ServerGreetCommand(DiscordModule module) : base(module) { public ServerGreetCommand(DiscordModule module) : base(module)
{
AnnouncementsDictionary = new ConcurrentDictionary<ulong, AnnounceControls>(); AnnouncementsDictionary = new ConcurrentDictionary<ulong, AnnounceControls>();
NadekoBot.Client.UserJoined += UserJoined; NadekoBot.Client.UserJoined += UserJoined;
@ -41,8 +41,10 @@ namespace NadekoBot.Commands {
AnnouncementsDictionary.TryAdd((ulong)obj.ServerId, new AnnounceControls(obj)); AnnouncementsDictionary.TryAdd((ulong)obj.ServerId, new AnnounceControls(obj));
} }
private async void UserLeft(object sender, UserEventArgs e) { private async void UserLeft(object sender, UserEventArgs e)
try { {
try
{
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) || if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) ||
!AnnouncementsDictionary[e.Server.Id].Bye) return; !AnnouncementsDictionary[e.Server.Id].Bye) return;
@ -52,9 +54,11 @@ namespace NadekoBot.Commands {
if (string.IsNullOrEmpty(msg)) if (string.IsNullOrEmpty(msg))
return; return;
if (controls.ByePM) { if (controls.ByePM)
{
Greeted++; Greeted++;
try { try
{
await e.User.SendMessage($"`Farewell Message From {e.Server?.Name}`\n" + msg); await e.User.SendMessage($"`Farewell Message From {e.Server?.Name}`\n" + msg);
} }
catch { } catch { }
@ -68,8 +72,10 @@ namespace NadekoBot.Commands {
catch { } catch { }
} }
private async void UserJoined(object sender, Discord.UserEventArgs e) { private async void UserJoined(object sender, Discord.UserEventArgs e)
try { {
try
{
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) || if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) ||
!AnnouncementsDictionary[e.Server.Id].Greet) return; !AnnouncementsDictionary[e.Server.Id].Greet) return;
@ -79,7 +85,8 @@ namespace NadekoBot.Commands {
var msg = controls.GreetText.Replace("%user%", e.User.Mention).Trim(); var msg = controls.GreetText.Replace("%user%", e.User.Mention).Trim();
if (string.IsNullOrEmpty(msg)) if (string.IsNullOrEmpty(msg))
return; return;
if (controls.GreetPM) { if (controls.GreetPM)
{
Greeted++; Greeted++;
await e.User.SendMessage($"`Welcome Message From {e.Server.Name}`\n" + msg); await e.User.SendMessage($"`Welcome Message From {e.Server.Name}`\n" + msg);
} }
@ -92,7 +99,8 @@ namespace NadekoBot.Commands {
catch { } catch { }
} }
public class AnnounceControls { public class AnnounceControls
{
private Classes._DataModels.Announcement _model { get; } private Classes._DataModels.Announcement _model { get; }
public bool Greet { public bool Greet {
@ -139,28 +147,36 @@ namespace NadekoBot.Commands {
set { _model.ServerId = (long)value; } set { _model.ServerId = (long)value; }
} }
public AnnounceControls(Classes._DataModels.Announcement model) { public AnnounceControls(Classes._DataModels.Announcement model)
{
this._model = model; this._model = model;
} }
public AnnounceControls(ulong serverId) { public AnnounceControls(ulong serverId)
{
this._model = new Classes._DataModels.Announcement(); this._model = new Classes._DataModels.Announcement();
ServerId = serverId; ServerId = serverId;
} }
internal bool ToggleBye(ulong id) { internal bool ToggleBye(ulong id)
if (Bye) { {
if (Bye)
{
return Bye = false; return Bye = false;
} else { }
else {
ByeChannel = id; ByeChannel = id;
return Bye = true; return Bye = true;
} }
} }
internal bool ToggleGreet(ulong id) { internal bool ToggleGreet(ulong id)
if (Greet) { {
if (Greet)
{
return Greet = false; return Greet = false;
} else { }
else {
GreetChannel = id; GreetChannel = id;
return Greet = true; return Greet = true;
} }
@ -168,16 +184,19 @@ namespace NadekoBot.Commands {
internal bool ToggleGreetPM() => GreetPM = !GreetPM; internal bool ToggleGreetPM() => GreetPM = !GreetPM;
internal bool ToggleByePM() => ByePM = !ByePM; internal bool ToggleByePM() => ByePM = !ByePM;
private void Save() { private void Save()
{
Classes.DbHandler.Instance.Save(_model); Classes.DbHandler.Instance.Save(_model);
} }
} }
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "greet") cgb.CreateCommand(Module.Prefix + "greet")
.Description("Enables or Disables anouncements on the current channel when someone joins the server.") .Description("Enables or Disables anouncements on the current channel when someone joins the server.")
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return; if (!e.User.ServerPermissions.ManageServer) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
@ -193,7 +212,8 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "greetmsg") cgb.CreateCommand(Module.Prefix + "greetmsg")
.Description("Sets a new announce message. Type %user% if you want to mention the new member.\n**Usage**: .greetmsg Welcome to the server, %user%.") .Description("Sets a new announce message. Type %user% if you want to mention the new member.\n**Usage**: .greetmsg Welcome to the server, %user%.")
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return; if (!e.User.ServerPermissions.ManageServer) return;
if (e.GetArg("msg") == null) return; if (e.GetArg("msg") == null) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
@ -207,7 +227,8 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "bye") cgb.CreateCommand(Module.Prefix + "bye")
.Description("Enables or Disables anouncements on the current channel when someone leaves the server.") .Description("Enables or Disables anouncements on the current channel when someone leaves the server.")
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return; if (!e.User.ServerPermissions.ManageServer) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
@ -223,7 +244,8 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "byemsg") cgb.CreateCommand(Module.Prefix + "byemsg")
.Description("Sets a new announce leave message. Type %user% if you want to mention the new member.\n**Usage**: .byemsg %user% has left the server.") .Description("Sets a new announce leave message. Type %user% if you want to mention the new member.\n**Usage**: .byemsg %user% has left the server.")
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return; if (!e.User.ServerPermissions.ManageServer) return;
if (e.GetArg("msg") == null) return; if (e.GetArg("msg") == null) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
@ -237,7 +259,8 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "byepm") cgb.CreateCommand(Module.Prefix + "byepm")
.Description("Toggles whether the good bye messages will be sent in a PM or in the text channel.") .Description("Toggles whether the good bye messages will be sent in a PM or in the text channel.")
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return; if (!e.User.ServerPermissions.ManageServer) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
@ -253,7 +276,8 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "greetpm") cgb.CreateCommand(Module.Prefix + "greetpm")
.Description("Toggles whether the greet messages will be sent in a PM or in the text channel.") .Description("Toggles whether the greet messages will be sent in a PM or in the text channel.")
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return; if (!e.User.ServerPermissions.ManageServer) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id));

View File

@ -1,34 +1,40 @@
using System; using Discord;
using Discord.Commands;
using NadekoBot.Commands;
using System;
using System.Collections.Concurrent;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.Commands;
using System.Collections.Concurrent;
using Discord;
using NadekoBot.Modules;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
internal class VoiceNotificationCommand : DiscordCommand { {
internal class VoiceNotificationCommand : DiscordCommand
{
//voicechannel/text channel //voicechannel/text channel
private readonly ConcurrentDictionary<Channel, Channel> subscribers = new ConcurrentDictionary<Channel, Channel>(); private readonly ConcurrentDictionary<Channel, Channel> subscribers = new ConcurrentDictionary<Channel, Channel>();
public Func<CommandEventArgs, Task> DoFunc() => async e => { public Func<CommandEventArgs, Task> DoFunc() => async e =>
{
var arg = e.GetArg("voice_name"); var arg = e.GetArg("voice_name");
if (string.IsNullOrWhiteSpace("voice_name")) if (string.IsNullOrWhiteSpace("voice_name"))
return; return;
var voiceChannel = e.Server.FindChannels(arg, ChannelType.Voice).FirstOrDefault(); var voiceChannel = e.Server.FindChannels(arg, ChannelType.Voice).FirstOrDefault();
if (voiceChannel == null) if (voiceChannel == null)
return; return;
if (subscribers.ContainsKey(voiceChannel)) { if (subscribers.ContainsKey(voiceChannel))
{
await e.Channel.SendMessage("`Voice channel notifications disabled.`"); await e.Channel.SendMessage("`Voice channel notifications disabled.`");
return; return;
} }
if (subscribers.TryAdd(voiceChannel, e.Channel)) { if (subscribers.TryAdd(voiceChannel, e.Channel))
{
await e.Channel.SendMessage("`Voice channel notifications enabled.`"); await e.Channel.SendMessage("`Voice channel notifications enabled.`");
} }
}; };
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "voicenotif") cgb.CreateCommand(Module.Prefix + "voicenotif")
.Description("Enables notifications on who joined/left the voice channel.\n**Usage**:.voicenotif Karaoke club") .Description("Enables notifications on who joined/left the voice channel.\n**Usage**:.voicenotif Karaoke club")
.Parameter("voice_name", ParameterType.Unparsed) .Parameter("voice_name", ParameterType.Unparsed)

View File

@ -1,20 +1,24 @@
using System; using Discord;
using System.Linq;
using System.Runtime.CompilerServices;
using Discord;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using NadekoBot.Modules; using NadekoBot.Commands;
using System;
using System.Linq;
using ChPermOverride = Discord.ChannelPermissionOverrides; using ChPermOverride = Discord.ChannelPermissionOverrides;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
internal class VoicePlusTextCommand : DiscordCommand { {
internal class VoicePlusTextCommand : DiscordCommand
{
public VoicePlusTextCommand(DiscordModule module) : base(module) { public VoicePlusTextCommand(DiscordModule module) : base(module)
{
// changing servers may cause bugs // changing servers may cause bugs
NadekoBot.Client.UserUpdated += async (sender, e) => { NadekoBot.Client.UserUpdated += async (sender, e) =>
try { {
try
{
if (e.Server == null) if (e.Server == null)
return; return;
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
@ -24,20 +28,24 @@ namespace NadekoBot.Commands {
var serverPerms = e.Server.GetUser(NadekoBot.Client.CurrentUser.Id)?.ServerPermissions; var serverPerms = e.Server.GetUser(NadekoBot.Client.CurrentUser.Id)?.ServerPermissions;
if (serverPerms == null) if (serverPerms == null)
return; return;
if (!serverPerms.Value.ManageChannels || !serverPerms.Value.ManageRoles) { if (!serverPerms.Value.ManageChannels || !serverPerms.Value.ManageRoles)
{
try { try
{
await e.Server.Owner.SendMessage( await e.Server.Owner.SendMessage(
"I don't have manage server and/or Manage Channels permission," + "I don't have manage server and/or Manage Channels permission," +
$" so I cannot run voice+text on **{e.Server.Name}** server."); $" so I cannot run voice+text on **{e.Server.Name}** server.");
} catch { } // meh }
catch { } // meh
config.VoicePlusTextEnabled = false; config.VoicePlusTextEnabled = false;
return; return;
} }
var beforeVch = e.Before.VoiceChannel; var beforeVch = e.Before.VoiceChannel;
if (beforeVch != null) { if (beforeVch != null)
{
var textChannel = var textChannel =
e.Server.FindChannels(GetChannelName(beforeVch.Name), ChannelType.Text).FirstOrDefault(); e.Server.FindChannels(GetChannelName(beforeVch.Name), ChannelType.Text).FirstOrDefault();
if (textChannel != null) if (textChannel != null)
@ -46,12 +54,14 @@ namespace NadekoBot.Commands {
sendMessages: PermValue.Deny)); sendMessages: PermValue.Deny));
} }
var afterVch = e.After.VoiceChannel; var afterVch = e.After.VoiceChannel;
if (afterVch != null) { if (afterVch != null)
{
var textChannel = e.Server.FindChannels( var textChannel = e.Server.FindChannels(
GetChannelName(afterVch.Name), GetChannelName(afterVch.Name),
ChannelType.Text) ChannelType.Text)
.FirstOrDefault(); .FirstOrDefault();
if (textChannel == null) { if (textChannel == null)
{
textChannel = (await e.Server.CreateChannel(GetChannelName(afterVch.Name), ChannelType.Text)); textChannel = (await e.Server.CreateChannel(GetChannelName(afterVch.Name), ChannelType.Text));
await textChannel.AddPermissionsRule(e.Server.EveryoneRole, await textChannel.AddPermissionsRule(e.Server.EveryoneRole,
new ChPermOverride(readMessages: PermValue.Deny, new ChPermOverride(readMessages: PermValue.Deny,
@ -61,7 +71,9 @@ namespace NadekoBot.Commands {
new ChPermOverride(readMessages: PermValue.Allow, new ChPermOverride(readMessages: PermValue.Allow,
sendMessages: PermValue.Allow)); sendMessages: PermValue.Allow));
} }
} catch (Exception ex) { }
catch (Exception ex)
{
Console.WriteLine(ex); Console.WriteLine(ex);
} }
}; };
@ -70,22 +82,30 @@ namespace NadekoBot.Commands {
private string GetChannelName(string voiceName) => private string GetChannelName(string voiceName) =>
voiceName.Replace(" ", "-").Trim() + "-voice"; voiceName.Replace(" ", "-").Trim() + "-voice";
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "v+t") cgb.CreateCommand(Module.Prefix + "v+t")
.Alias(Module.Prefix + "voice+text") .Alias(Module.Prefix + "voice+text")
.Description("Creates a text channel for each voice channel only users in that voice channel can see." + .Description("Creates a text channel for each voice channel only users in that voice channel can see." +
"If you are server owner, keep in mind you will see them all the time regardless.") "If you are server owner, keep in mind you will see them all the time regardless.")
.AddCheck(SimpleCheckers.ManageChannels()) .AddCheck(SimpleCheckers.ManageChannels())
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => { .Do(async e =>
try { {
try
{
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (config.VoicePlusTextEnabled == true) { if (config.VoicePlusTextEnabled == true)
{
config.VoicePlusTextEnabled = false; config.VoicePlusTextEnabled = false;
foreach (var textChannel in e.Server.TextChannels.Where(c => c.Name.EndsWith("-voice"))) { foreach (var textChannel in e.Server.TextChannels.Where(c => c.Name.EndsWith("-voice")))
try { {
try
{
await textChannel.Delete(); await textChannel.Delete();
} catch { }
catch
{
await await
e.Channel.SendMessage( e.Channel.SendMessage(
":anger: Error: Most likely i don't have permissions to do this."); ":anger: Error: Most likely i don't have permissions to do this.");
@ -99,7 +119,9 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage("Successfuly enabled voice + text feature. " + await e.Channel.SendMessage("Successfuly enabled voice + text feature. " +
"**Make sure the bot has manage roles and manage channels permissions**"); "**Make sure the bot has manage roles and manage channels permissions**");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage(ex.ToString()); await e.Channel.SendMessage(ex.ToString());
} }
}); });

View File

@ -5,6 +5,7 @@ using Discord.Modules;
using NadekoBot.Classes.JSONModels; using NadekoBot.Classes.JSONModels;
using NadekoBot.Commands; using NadekoBot.Commands;
using NadekoBot.Modules; using NadekoBot.Modules;
using NadekoBot.Modules.Administration;
using NadekoBot.Modules.Gambling; using NadekoBot.Modules.Gambling;
using NadekoBot.Modules.Pokemon; using NadekoBot.Modules.Pokemon;
using NadekoBot.Modules.Translator; using NadekoBot.Modules.Translator;
@ -157,7 +158,7 @@ namespace NadekoBot
})); }));
//install modules //install modules
modules.Add(new Administration(), "Administration", ModuleFilter.None); modules.Add(new AdministrationModule(), "Administration", ModuleFilter.None);
modules.Add(new Help(), "Help", ModuleFilter.None); modules.Add(new Help(), "Help", ModuleFilter.None);
modules.Add(new PermissionModule(), "Permissions", ModuleFilter.None); modules.Add(new PermissionModule(), "Permissions", ModuleFilter.None);
modules.Add(new Conversations(), "Conversations", ModuleFilter.None); modules.Add(new Conversations(), "Conversations", ModuleFilter.None);

View File

@ -150,22 +150,22 @@
<Compile Include="Classes\_DataModels\TypingArticleModel.cs" /> <Compile Include="Classes\_DataModels\TypingArticleModel.cs" />
<Compile Include="Classes\_DataModels\UserQuoteModel.cs" /> <Compile Include="Classes\_DataModels\UserQuoteModel.cs" />
<Compile Include="Commands\BetrayGame.cs" /> <Compile Include="Commands\BetrayGame.cs" />
<Compile Include="Commands\CrossServerTextChannel.cs" /> <Compile Include="Modules\Administration\Commands\CrossServerTextChannel.cs" />
<Compile Include="Commands\SelfAssignedRolesCommand.cs" /> <Compile Include="Modules\Administration\Commands\SelfAssignedRolesCommand.cs" />
<Compile Include="Modules\ClashOfClans.cs" /> <Compile Include="Modules\ClashOfClans.cs" />
<Compile Include="Commands\FilterWordsCommand.cs" /> <Compile Include="Commands\FilterWordsCommand.cs" />
<Compile Include="Commands\FilterInvitesCommand.cs" /> <Compile Include="Commands\FilterInvitesCommand.cs" />
<Compile Include="Commands\LogCommand.cs" /> <Compile Include="Modules\Administration\Commands\LogCommand.cs" />
<Compile Include="Commands\LoLCommands.cs" /> <Compile Include="Commands\LoLCommands.cs" />
<Compile Include="Commands\MessageRepeater.cs" /> <Compile Include="Modules\Administration\Commands\MessageRepeater.cs" />
<Compile Include="Commands\PlayingRotate.cs" /> <Compile Include="Modules\Administration\Commands\PlayingRotate.cs" />
<Compile Include="Commands\StreamNotifications.cs" /> <Compile Include="Commands\StreamNotifications.cs" />
<Compile Include="Commands\TriviaCommand.cs" /> <Compile Include="Commands\TriviaCommand.cs" />
<Compile Include="Classes\Trivia\TriviaGame.cs" /> <Compile Include="Classes\Trivia\TriviaGame.cs" />
<Compile Include="Classes\Trivia\TriviaQuestion.cs" /> <Compile Include="Classes\Trivia\TriviaQuestion.cs" />
<Compile Include="Classes\Trivia\TriviaQuestionPool.cs" /> <Compile Include="Classes\Trivia\TriviaQuestionPool.cs" />
<Compile Include="Commands\RequestsCommand.cs" /> <Compile Include="Commands\RequestsCommand.cs" />
<Compile Include="Commands\ServerGreetCommand.cs" /> <Compile Include="Modules\Administration\Commands\ServerGreetCommand.cs" />
<Compile Include="Commands\SpeedTyping.cs" /> <Compile Include="Commands\SpeedTyping.cs" />
<Compile Include="Modules\Gambling\Helpers\Cards.cs" /> <Compile Include="Modules\Gambling\Helpers\Cards.cs" />
<Compile Include="Classes\Extensions.cs" /> <Compile Include="Classes\Extensions.cs" />
@ -175,9 +175,9 @@
<Compile Include="Modules\Gambling\DrawCommand.cs" /> <Compile Include="Modules\Gambling\DrawCommand.cs" />
<Compile Include="Modules\Gambling\FlipCoinCommand.cs" /> <Compile Include="Modules\Gambling\FlipCoinCommand.cs" />
<Compile Include="Commands\HelpCommand.cs" /> <Compile Include="Commands\HelpCommand.cs" />
<Compile Include="Commands\VoiceNotificationCommand.cs" /> <Compile Include="Modules\Administration\Commands\VoiceNotificationCommand.cs" />
<Compile Include="Commands\VoicePlusTextCommand.cs" /> <Compile Include="Modules\Administration\Commands\VoicePlusTextCommand.cs" />
<Compile Include="Modules\Administration.cs" /> <Compile Include="Modules\Administration\AdministrationModule.cs" />
<Compile Include="Modules\Conversations.cs" /> <Compile Include="Modules\Conversations.cs" />
<Compile Include="Modules\DiscordModule.cs" /> <Compile Include="Modules\DiscordModule.cs" />
<Compile Include="Modules\Gambling\GamblingModule.cs" /> <Compile Include="Modules\Gambling\GamblingModule.cs" />
@ -187,7 +187,7 @@
<Compile Include="Commands\PollCommand.cs" /> <Compile Include="Commands\PollCommand.cs" />
<Compile Include="Modules\NSFW.cs" /> <Compile Include="Modules\NSFW.cs" />
<Compile Include="Modules\Permissions.cs" /> <Compile Include="Modules\Permissions.cs" />
<Compile Include="Commands\RatelimitCommand.cs" /> <Compile Include="Modules\Administration\Commands\RatelimitCommand.cs" />
<Compile Include="Modules\Pokemon\DefaultMoves.cs" /> <Compile Include="Modules\Pokemon\DefaultMoves.cs" />
<Compile Include="Modules\Pokemon\PokemonModule.cs" /> <Compile Include="Modules\Pokemon\PokemonModule.cs" />
<Compile Include="Modules\Pokemon\PokemonTypes\IPokeTypeExtensions.cs" /> <Compile Include="Modules\Pokemon\PokemonTypes\IPokeTypeExtensions.cs" />