Startup commands added. Closes #195; .sclist .scadd .scrm .scclr. Won't support music commands atm, but that can come in the future, there is support for it (your current voice channel is recorded when adding)

This commit is contained in:
Kwoth 2017-03-31 14:07:18 +02:00
parent 272bf6b85e
commit 0a7bbd60f7
17 changed files with 2090 additions and 147 deletions

View File

@ -6,6 +6,6 @@ namespace NadekoBot.Attributes
public class OwnerOnlyAttribute : PreconditionAttribute public class OwnerOnlyAttribute : PreconditionAttribute
{ {
public override Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo executingCommand,IDependencyMap depMap) => public override Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo executingCommand,IDependencyMap depMap) =>
Task.FromResult((NadekoBot.Credentials.IsOwner(context.User) ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner"))); Task.FromResult((NadekoBot.Credentials.IsOwner(context.User) || NadekoBot.Client.CurrentUser.Id == context.User.Id ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner")));
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class startupcommands : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "StartupCommand",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
BotConfigId = table.Column<int>(nullable: true),
ChannelId = table.Column<ulong>(nullable: false),
ChannelName = table.Column<string>(nullable: true),
CommandText = table.Column<string>(nullable: true),
DateAdded = table.Column<DateTime>(nullable: true),
GuildId = table.Column<ulong>(nullable: true),
GuildName = table.Column<string>(nullable: true),
Index = table.Column<int>(nullable: false),
VoiceChannelId = table.Column<ulong>(nullable: true),
VoiceChannelName = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_StartupCommand", x => x.Id);
table.ForeignKey(
name: "FK_StartupCommand_BotConfig_BotConfigId",
column: x => x.BotConfigId,
principalTable: "BotConfig",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_StartupCommand_BotConfigId",
table: "StartupCommand",
column: "BotConfigId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "StartupCommand");
}
}
}

View File

@ -950,6 +950,38 @@ namespace NadekoBot.Migrations
b.ToTable("SelfAssignableRoles"); b.ToTable("SelfAssignableRoles");
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<ulong>("ChannelId");
b.Property<string>("ChannelName");
b.Property<string>("CommandText");
b.Property<DateTime?>("DateAdded");
b.Property<ulong?>("GuildId");
b.Property<string>("GuildName");
b.Property<int>("Index");
b.Property<ulong?>("VoiceChannelId");
b.Property<string>("VoiceChannelName");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("StartupCommand");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@ -1288,6 +1320,13 @@ namespace NadekoBot.Migrations
.HasForeignKey("BotConfigId"); .HasForeignKey("BotConfigId");
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
.WithMany("StartupCommands")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b =>
{ {
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")

View File

@ -32,7 +32,7 @@ namespace NadekoBot.Modules.Administration
} }
private static Task DelMsgOnCmd_Handler(SocketUserMessage msg, CommandInfo cmd) private static Task DelMsgOnCmd_Handler(IUserMessage msg, CommandInfo cmd)
{ {
var _ = Task.Run(async () => var _ = Task.Run(async () =>
{ {

View File

@ -10,6 +10,8 @@ using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.WebSocket; using Discord.WebSocket;
using NadekoBot.Services; using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using Microsoft.EntityFrameworkCore;
namespace NadekoBot.Modules.Administration namespace NadekoBot.Modules.Administration
{ {
@ -31,6 +33,166 @@ namespace NadekoBot.Modules.Administration
_forwardDMs = config.ForwardMessages; _forwardDMs = config.ForwardMessages;
_forwardDMsToAllOwners = config.ForwardToAllOwners; _forwardDMsToAllOwners = config.ForwardToAllOwners;
} }
var _ = Task.Run(async () =>
{
#if !GLOBAL_NADEKO
await Task.Delay(2000);
#else
await Task.Delay(10000);
#endif
foreach (var cmd in NadekoBot.BotConfig.StartupCommands)
{
if (cmd.GuildId != null)
{
var guild = NadekoBot.Client.GetGuild(cmd.GuildId.Value);
var channel = guild?.GetChannel(cmd.ChannelId) as SocketTextChannel;
if (channel == null)
continue;
try
{
var msg = await channel.SendMessageAsync(cmd.CommandText).ConfigureAwait(false);
await NadekoBot.CommandHandler.TryRunCommand(guild, channel, msg).ConfigureAwait(false);
//msg.DeleteAfter(5);
}
catch { }
}
}
});
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[OwnerOnly]
public async Task StartupCommandAdd([Remainder] string cmdText)
{
var guser = ((IGuildUser)Context.User);
var cmd = new StartupCommand()
{
CommandText = cmdText,
ChannelId = Context.Channel.Id,
ChannelName = Context.Channel.Name,
GuildId = Context.Guild?.Id,
GuildName = Context.Guild?.Name,
VoiceChannelId = guser.VoiceChannel?.Id,
VoiceChannelName = guser.VoiceChannel?.Name,
};
using (var uow = DbHandler.UnitOfWork())
{
uow.BotConfig
.GetOrCreate(set => set.Include(x => x.StartupCommands))
.StartupCommands.Add(cmd);
await uow.CompleteAsync().ConfigureAwait(false);
}
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
.WithTitle(GetText("scadd"))
.AddField(efb => efb.WithName(GetText("server"))
.WithValue(cmd.GuildId == null ? $"-" : $"{cmd.GuildName}/{cmd.GuildId}").WithIsInline(true))
.AddField(efb => efb.WithName(GetText("channel"))
.WithValue($"{cmd.ChannelName}/{cmd.ChannelId}").WithIsInline(true))
.AddField(efb => efb.WithName(GetText("command_text"))
.WithValue(cmdText).WithIsInline(false)));
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[OwnerOnly]
public async Task StartupCommands(int page = 1)
{
if (page < 1)
return;
page -= 1;
IEnumerable<StartupCommand> scmds;
using (var uow = DbHandler.UnitOfWork())
{
scmds = uow.BotConfig
.GetOrCreate(set => set.Include(x => x.StartupCommands))
.StartupCommands
.OrderBy(x => x.Id)
.ToArray();
}
scmds = scmds.Skip(page * 5).Take(5);
if (!scmds.Any())
{
await ReplyErrorLocalized("startcmdlist_none").ConfigureAwait(false);
}
else
{
await Context.Channel.SendConfirmAsync("", string.Join("\n--\n", scmds.Select(x =>
{
string str = Format.Code(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}";
return str;
})),footer: GetText("page", page + 1))
.ConfigureAwait(false);
}
}
[NadekoCommand, Usage, Description, Aliases]
[OwnerOnly]
public async Task Wait(int miliseconds)
{
if (miliseconds <= 0)
return;
Context.Message.DeleteAfter(0);
try
{
var msg = await Context.Channel.SendConfirmAsync($"⏲ {miliseconds}ms")
.ConfigureAwait(false);
msg.DeleteAfter(miliseconds / 1000);
}
catch { }
await Task.Delay(miliseconds);
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[OwnerOnly]
public async Task StartupCommandRemove([Remainder] string cmdText)
{
StartupCommand cmd;
using (var uow = DbHandler.UnitOfWork())
{
var cmds = uow.BotConfig
.GetOrCreate(set => set.Include(x => x.StartupCommands))
.StartupCommands;
cmd = cmds
.FirstOrDefault(x => x.CommandText.ToLowerInvariant() == cmdText.ToLowerInvariant());
if (cmd != null)
{
cmds.Remove(cmd);
await uow.CompleteAsync().ConfigureAwait(false);
}
}
if(cmd == null)
await ReplyErrorLocalized("scrm_fail").ConfigureAwait(false);
else
await ReplyConfirmLocalized("scrm").ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[OwnerOnly]
public async Task StartupCommandsClear()
{
using (var uow = DbHandler.UnitOfWork())
{
uow.BotConfig
.GetOrCreate(set => set.Include(x => x.StartupCommands))
.StartupCommands
.Clear();
uow.Complete();
}
await ReplyConfirmLocalized("startcmds_cleared").ConfigureAwait(false);
} }
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
@ -68,7 +230,7 @@ namespace NadekoBot.Modules.Administration
} }
public static async Task HandleDmForwarding(SocketMessage msg, List<IDMChannel> ownerChannels) public static async Task HandleDmForwarding(IUserMessage msg, List<IDMChannel> ownerChannels)
{ {
if (_forwardDMs && ownerChannels.Any()) if (_forwardDMs && ownerChannels.Any())
{ {
@ -157,7 +319,7 @@ namespace NadekoBot.Modules.Administration
else else
{ {
await server.DeleteAsync().ConfigureAwait(false); await server.DeleteAsync().ConfigureAwait(false);
await ReplyConfirmLocalized("deleted_server",Format.Bold(server.Name)).ConfigureAwait(false); await ReplyConfirmLocalized("deleted_server", Format.Bold(server.Name)).ConfigureAwait(false);
} }
} }

View File

@ -61,7 +61,10 @@ namespace NadekoBot.Modules.Administration
switch (p.Punishment) switch (p.Punishment)
{ {
case PunishmentAction.Mute: case PunishmentAction.Mute:
await MuteCommands.TimedMute(user, TimeSpan.FromMinutes(p.Time)); if (p.Time == 0)
await MuteCommands.MuteUser(user).ConfigureAwait(false);
else
await MuteCommands.TimedMute(user, TimeSpan.FromMinutes(p.Time)).ConfigureAwait(false);
break; break;
case PunishmentAction.Kick: case PunishmentAction.Kick:
await user.KickAsync().ConfigureAwait(false); await user.KickAsync().ConfigureAwait(false);

View File

@ -59,7 +59,7 @@ namespace NadekoBot.Modules.CustomReactions
public void ClearStats() => ReactionStats.Clear(); public void ClearStats() => ReactionStats.Clear();
public static CustomReaction TryGetCustomReaction(SocketUserMessage umsg) public static CustomReaction TryGetCustomReaction(IUserMessage umsg)
{ {
var channel = umsg.Channel as SocketTextChannel; var channel = umsg.Channel as SocketTextChannel;
if (channel == null) if (channel == null)

View File

@ -40,7 +40,7 @@ namespace NadekoBot.Modules.Games
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
} }
public static async Task<bool> TryAsk(SocketUserMessage msg) public static async Task<bool> TryAsk(IUserMessage msg)
{ {
var channel = msg.Channel as ITextChannel; var channel = msg.Channel as ITextChannel;

View File

@ -7889,6 +7889,114 @@ namespace NadekoBot.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to scadd.
/// </summary>
public static string startupcommandadd_cmd {
get {
return ResourceManager.GetString("startupcommandadd_cmd", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up..
/// </summary>
public static string startupcommandadd_desc {
get {
return ResourceManager.GetString("startupcommandadd_desc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to `{0}scadd .stats`.
/// </summary>
public static string startupcommandadd_usage {
get {
return ResourceManager.GetString("startupcommandadd_usage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to scrm.
/// </summary>
public static string startupcommandremove_cmd {
get {
return ResourceManager.GetString("startupcommandremove_cmd", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Removes a startup command with the provided command text..
/// </summary>
public static string startupcommandremove_desc {
get {
return ResourceManager.GetString("startupcommandremove_desc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to `{0}scrm .stats`.
/// </summary>
public static string startupcommandremove_usage {
get {
return ResourceManager.GetString("startupcommandremove_usage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to sclist.
/// </summary>
public static string startupcommands_cmd {
get {
return ResourceManager.GetString("startupcommands_cmd", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Lists all startup commands in the order they will be executed in..
/// </summary>
public static string startupcommands_desc {
get {
return ResourceManager.GetString("startupcommands_desc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to `{0}sclist`.
/// </summary>
public static string startupcommands_usage {
get {
return ResourceManager.GetString("startupcommands_usage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to scclr.
/// </summary>
public static string startupcommandsclear_cmd {
get {
return ResourceManager.GetString("startupcommandsclear_cmd", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Removes all startup commands..
/// </summary>
public static string startupcommandsclear_desc {
get {
return ResourceManager.GetString("startupcommandsclear_desc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to `{0}scclr`.
/// </summary>
public static string startupcommandsclear_usage {
get {
return ResourceManager.GetString("startupcommandsclear_usage", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to startwar sw. /// Looks up a localized string similar to startwar sw.
/// </summary> /// </summary>
@ -9131,6 +9239,33 @@ namespace NadekoBot.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to wait.
/// </summary>
public static string wait_cmd {
get {
return ResourceManager.GetString("wait_cmd", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Used only as a startup command. Waits a certain number of miliseconds before continuing the execution of the following startup commands..
/// </summary>
public static string wait_desc {
get {
return ResourceManager.GetString("wait_desc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to `{0}wait 3000`.
/// </summary>
public static string wait_usage {
get {
return ResourceManager.GetString("wait_usage", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to warn. /// Looks up a localized string similar to warn.
/// </summary> /// </summary>

View File

@ -3240,6 +3240,42 @@
<data name="warn_usage" xml:space="preserve"> <data name="warn_usage" xml:space="preserve">
<value>`{0}warn @b1nzy`</value> <value>`{0}warn @b1nzy`</value>
</data> </data>
<data name="startupcommandadd_cmd" xml:space="preserve">
<value>scadd</value>
</data>
<data name="startupcommandadd_desc" xml:space="preserve">
<value>Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up.</value>
</data>
<data name="startupcommandadd_usage" xml:space="preserve">
<value>`{0}scadd .stats`</value>
</data>
<data name="startupcommandremove_cmd" xml:space="preserve">
<value>scrm</value>
</data>
<data name="startupcommandremove_desc" xml:space="preserve">
<value>Removes a startup command with the provided command text.</value>
</data>
<data name="startupcommandremove_usage" xml:space="preserve">
<value>`{0}scrm .stats`</value>
</data>
<data name="startupcommandsclear_cmd" xml:space="preserve">
<value>scclr</value>
</data>
<data name="startupcommandsclear_desc" xml:space="preserve">
<value>Removes all startup commands.</value>
</data>
<data name="startupcommandsclear_usage" xml:space="preserve">
<value>`{0}scclr`</value>
</data>
<data name="startupcommands_cmd" xml:space="preserve">
<value>sclist</value>
</data>
<data name="startupcommands_desc" xml:space="preserve">
<value>Lists all startup commands in the order they will be executed in.</value>
</data>
<data name="startupcommands_usage" xml:space="preserve">
<value>`{0}sclist`</value>
</data>
<data name="unban_cmd" xml:space="preserve"> <data name="unban_cmd" xml:space="preserve">
<value>unban</value> <value>unban</value>
</data> </data>
@ -3249,6 +3285,15 @@
<data name="unban_usage" xml:space="preserve"> <data name="unban_usage" xml:space="preserve">
<value>`{0}unban kwoth#1234` or `{0}unban 123123123`</value> <value>`{0}unban kwoth#1234` or `{0}unban 123123123`</value>
</data> </data>
<data name="wait_cmd" xml:space="preserve">
<value>wait</value>
</data>
<data name="wait_desc" xml:space="preserve">
<value>Used only as a startup command. Waits a certain number of miliseconds before continuing the execution of the following startup commands.</value>
</data>
<data name="wait_usage" xml:space="preserve">
<value>`{0}wait 3000`</value>
</data>
<data name="warnclear_cmd" xml:space="preserve"> <data name="warnclear_cmd" xml:space="preserve">
<value>warnclear warnc</value> <value>warnclear warnc</value>
</data> </data>

View File

@ -231,6 +231,15 @@ namespace NadekoBot.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Channel.
/// </summary>
public static string administration_channel {
get {
return ResourceManager.GetString("administration_channel", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Cleaned up.. /// Looks up a localized string similar to Cleaned up..
/// </summary> /// </summary>
@ -240,6 +249,15 @@ namespace NadekoBot.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Command Text.
/// </summary>
public static string administration_command_text {
get {
return ResourceManager.GetString("administration_command_text", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Content. /// Looks up a localized string similar to Content.
/// </summary> /// </summary>
@ -1233,6 +1251,33 @@ namespace NadekoBot.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to New startup command added..
/// </summary>
public static string administration_scadd {
get {
return ResourceManager.GetString("administration_scadd", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Startup command successfully removed..
/// </summary>
public static string administration_scrm {
get {
return ResourceManager.GetString("administration_scrm", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Startup command not found..
/// </summary>
public static string administration_scrm_fail {
get {
return ResourceManager.GetString("administration_scrm_fail", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to You already have {0} role.. /// Looks up a localized string similar to You already have {0} role..
/// </summary> /// </summary>
@ -1332,6 +1377,15 @@ namespace NadekoBot.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Server.
/// </summary>
public static string administration_server {
get {
return ResourceManager.GetString("administration_server", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to New avatar set!. /// Looks up a localized string similar to New avatar set!.
/// </summary> /// </summary>
@ -1486,6 +1540,24 @@ namespace NadekoBot.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to No startup commands on this page..
/// </summary>
public static string administration_startcmdlist_none {
get {
return ResourceManager.GetString("administration_startcmdlist_none", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cleared all startup commands..
/// </summary>
public static string administration_startcmds_cleared {
get {
return ResourceManager.GetString("administration_startcmds_cleared", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Text channel created.. /// Looks up a localized string similar to Text channel created..
/// </summary> /// </summary>

View File

@ -2278,6 +2278,12 @@ Owner ID: {2}</value>
<data name="searches_compet_playtime" xml:space="preserve"> <data name="searches_compet_playtime" xml:space="preserve">
<value>Competitive playtime</value> <value>Competitive playtime</value>
</data> </data>
<data name="administration_channel" xml:space="preserve">
<value>Channel</value>
</data>
<data name="administration_command_text" xml:space="preserve">
<value>Command Text</value>
</data>
<data name="administration_moderator" xml:space="preserve"> <data name="administration_moderator" xml:space="preserve">
<value>Moderator</value> <value>Moderator</value>
</data> </data>
@ -2287,6 +2293,24 @@ Owner ID: {2}</value>
<data name="administration_reason" xml:space="preserve"> <data name="administration_reason" xml:space="preserve">
<value>Reason</value> <value>Reason</value>
</data> </data>
<data name="administration_scadd" xml:space="preserve">
<value>New startup command added.</value>
</data>
<data name="administration_scrm" xml:space="preserve">
<value>Startup command successfully removed.</value>
</data>
<data name="administration_scrm_fail" xml:space="preserve">
<value>Startup command not found.</value>
</data>
<data name="administration_server" xml:space="preserve">
<value>Server</value>
</data>
<data name="administration_startcmdlist_none" xml:space="preserve">
<value>No startup commands on this page.</value>
</data>
<data name="administration_startcmds_cleared" xml:space="preserve">
<value>Cleared all startup commands.</value>
</data>
<data name="administration_unbanned_user" xml:space="preserve"> <data name="administration_unbanned_user" xml:space="preserve">
<value>User {0} has been unbanned.</value> <value>User {0} has been unbanned.</value>
</data> </data>

View File

@ -37,7 +37,7 @@ namespace NadekoBot.Services
private List<IDMChannel> ownerChannels { get; set; } = new List<IDMChannel>(); private List<IDMChannel> ownerChannels { get; set; } = new List<IDMChannel>();
public event Func<SocketUserMessage, CommandInfo, Task> CommandExecuted = delegate { return Task.CompletedTask; }; public event Func<IUserMessage, CommandInfo, Task> CommandExecuted = delegate { return Task.CompletedTask; };
//userid/msg count //userid/msg count
public ConcurrentDictionary<ulong, uint> UserMessagesSent { get; } = new ConcurrentDictionary<ulong, uint>(); public ConcurrentDictionary<ulong, uint> UserMessagesSent { get; } = new ConcurrentDictionary<ulong, uint>();
@ -109,7 +109,7 @@ namespace NadekoBot.Services
return Task.CompletedTask; return Task.CompletedTask;
} }
private async Task<bool> TryRunCleverbot(SocketUserMessage usrMsg, IGuild guild) private async Task<bool> TryRunCleverbot(IUserMessage usrMsg, IGuild guild)
{ {
if (guild == null) if (guild == null)
return false; return false;
@ -130,14 +130,13 @@ namespace NadekoBot.Services
return false; return false;
} }
private bool IsBlacklisted(IGuild guild, SocketUserMessage usrMsg) => private bool IsBlacklisted(IGuild guild, IUserMessage usrMsg) =>
usrMsg.Author?.Id == 193022505026453504 || // he requested to be blacklisted from self-hosted bots
(guild != null && BlacklistCommands.BlacklistedGuilds.Contains(guild.Id)) || (guild != null && BlacklistCommands.BlacklistedGuilds.Contains(guild.Id)) ||
BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) || BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) ||
BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id); BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id);
private const float _oneThousandth = 1.0f / 1000; private const float _oneThousandth = 1.0f / 1000;
private Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int exec1, int exec2, int exec3, int total) private Task LogSuccessfulExecution(IUserMessage usrMsg, ExecuteCommandResult exec, ITextChannel channel, int exec1, int exec2, int exec3, int total)
{ {
_log.Info("Command Executed after {4}/{5}/{6}/{7}s\n\t" + _log.Info("Command Executed after {4}/{5}/{6}/{7}s\n\t" +
"User: {0}\n\t" + "User: {0}\n\t" +
@ -156,7 +155,7 @@ namespace NadekoBot.Services
return Task.CompletedTask; return Task.CompletedTask;
} }
private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int exec1, int exec2, int exec3, int total) private void LogErroredExecution(IUserMessage usrMsg, ExecuteCommandResult exec, ITextChannel channel, int exec1, int exec2, int exec3, int total)
{ {
_log.Warn("Command Errored after {5}/{6}/{7}/{8}s\n\t" + _log.Warn("Command Errored after {5}/{6}/{7}/{8}s\n\t" +
"User: {0}\n\t" + "User: {0}\n\t" +
@ -176,7 +175,7 @@ namespace NadekoBot.Services
); );
} }
private async Task<bool> InviteFiltered(IGuild guild, SocketUserMessage usrMsg) private async Task<bool> InviteFiltered(IGuild guild, IUserMessage usrMsg)
{ {
if ((Permissions.FilterCommands.InviteFilteringChannels.Contains(usrMsg.Channel.Id) || if ((Permissions.FilterCommands.InviteFilteringChannels.Contains(usrMsg.Channel.Id) ||
Permissions.FilterCommands.InviteFilteringServers.Contains(guild.Id)) && Permissions.FilterCommands.InviteFilteringServers.Contains(guild.Id)) &&
@ -196,7 +195,7 @@ namespace NadekoBot.Services
return false; return false;
} }
private async Task<bool> WordFiltered(IGuild guild, SocketUserMessage usrMsg) private async Task<bool> WordFiltered(IGuild guild, IUserMessage usrMsg)
{ {
var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id) ?? new ConcurrentHashSet<string>(); var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id) ?? new ConcurrentHashSet<string>();
var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet<string>(); var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet<string>();
@ -232,8 +231,6 @@ namespace NadekoBot.Services
if (msg.Author.IsBot || !NadekoBot.Ready) //no bots, wait until bot connected and initialized if (msg.Author.IsBot || !NadekoBot.Ready) //no bots, wait until bot connected and initialized
return; return;
var execTime = Environment.TickCount;
var usrMsg = msg as SocketUserMessage; var usrMsg = msg as SocketUserMessage;
if (usrMsg == null) //has to be an user message, not system/other messages. if (usrMsg == null) //has to be an user message, not system/other messages.
return; return;
@ -248,131 +245,7 @@ namespace NadekoBot.Services
var channel = msg.Channel as SocketTextChannel; var channel = msg.Channel as SocketTextChannel;
var guild = channel?.Guild; var guild = channel?.Guild;
if (guild != null && guild.OwnerId != msg.Author.Id) await TryRunCommand(guild, channel, usrMsg);
{
if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
return;
if (await WordFiltered(guild, usrMsg).ConfigureAwait(false))
return;
}
if (IsBlacklisted(guild, usrMsg))
return;
var exec1 = Environment.TickCount - execTime;
var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false);
if (cleverBotRan)
return;
var exec2 = Environment.TickCount - execTime;
// maybe this message is a custom reaction
// todo log custom reaction executions. return struct with info
var cr = await Task.Run(() => CustomReactions.TryGetCustomReaction(usrMsg)).ConfigureAwait(false);
if (cr != null) //if it was, don't execute the command
{
try
{
if (guild != null)
{
PermissionCache pc;
if (!Permissions.Cache.TryGetValue(guild.Id, out pc))
{
using (var uow = DbHandler.UnitOfWork())
{
var config = uow.GuildConfigs.For(guild.Id,
set => set.Include(x => x.Permissions));
Permissions.UpdateCache(config);
}
Permissions.Cache.TryGetValue(guild.Id, out pc);
if (pc == null)
throw new Exception("Cache is null.");
}
int index;
if (
!pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions",
out index))
{
//todo print in guild actually
var returnMsg =
$"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
_log.Info(returnMsg);
return;
}
}
await cr.Send(usrMsg).ConfigureAwait(false);
if (cr.AutoDeleteTrigger)
{
try { await msg.DeleteAsync().ConfigureAwait(false); } catch { }
}
}
catch (Exception ex)
{
_log.Warn("Sending CREmbed failed");
_log.Warn(ex);
}
return;
}
var exec3 = Environment.TickCount - execTime;
string messageContent = usrMsg.Content;
if (guild != null)
{
ConcurrentDictionary<string, string> maps;
if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out maps))
{
string newMessageContent;
if (maps.TryGetValue(messageContent.Trim().ToLowerInvariant(), out newMessageContent))
{
_log.Info(@"--Mapping Command--
GuildId: {0}
Trigger: {1}
Mapping: {2}", guild.Id, messageContent, newMessageContent);
var oldMessageContent = messageContent;
messageContent = newMessageContent;
try { await usrMsg.Channel.SendConfirmAsync($"{oldMessageContent} => {newMessageContent}").ConfigureAwait(false); } catch { }
}
}
}
// execute the command and measure the time it took
var exec = await Task.Run(() => ExecuteCommand(new CommandContext(_client, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best)).ConfigureAwait(false);
execTime = Environment.TickCount - execTime;
if (exec.Result.IsSuccess)
{
await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false);
await LogSuccessfulExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime).ConfigureAwait(false);
}
else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand)
{
LogErroredExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime);
if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception)
{
if (exec.PermissionCache != null && exec.PermissionCache.Verbose)
try { await msg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { }
}
}
else
{
if (msg.Channel is IPrivateChannel)
{
// rofl, gotta do this to prevent dm help message being sent to
// users who are voting on private polls (sending a number in a DM)
int vote;
if (int.TryParse(msg.Content, out vote)) return;
await msg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false);
await SelfCommands.HandleDmForwarding(msg, ownerChannels).ConfigureAwait(false);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -388,6 +261,137 @@ namespace NadekoBot.Services
return Task.CompletedTask; return Task.CompletedTask;
} }
public async Task TryRunCommand(SocketGuild guild, ITextChannel channel, IUserMessage usrMsg)
{
var execTime = Environment.TickCount;
if (guild != null && guild.OwnerId != usrMsg.Author.Id)
{
if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
return;
if (await WordFiltered(guild, usrMsg).ConfigureAwait(false))
return;
}
if (IsBlacklisted(guild, usrMsg))
return;
var exec1 = Environment.TickCount - execTime;
var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false);
if (cleverBotRan)
return;
var exec2 = Environment.TickCount - execTime;
// maybe this message is a custom reaction
// todo log custom reaction executions. return struct with info
var cr = await Task.Run(() => CustomReactions.TryGetCustomReaction(usrMsg)).ConfigureAwait(false);
if (cr != null) //if it was, don't execute the command
{
try
{
if (guild != null)
{
PermissionCache pc;
if (!Permissions.Cache.TryGetValue(guild.Id, out pc))
{
using (var uow = DbHandler.UnitOfWork())
{
var config = uow.GuildConfigs.For(guild.Id,
set => set.Include(x => x.Permissions));
Permissions.UpdateCache(config);
}
Permissions.Cache.TryGetValue(guild.Id, out pc);
if (pc == null)
throw new Exception("Cache is null.");
}
int index;
if (
!pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions",
out index))
{
//todo print in guild actually
var returnMsg =
$"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
_log.Info(returnMsg);
return;
}
}
await cr.Send(usrMsg).ConfigureAwait(false);
if (cr.AutoDeleteTrigger)
{
try { await usrMsg.DeleteAsync().ConfigureAwait(false); } catch { }
}
}
catch (Exception ex)
{
_log.Warn("Sending CREmbed failed");
_log.Warn(ex);
}
return;
}
var exec3 = Environment.TickCount - execTime;
string messageContent = usrMsg.Content;
if (guild != null)
{
ConcurrentDictionary<string, string> maps;
if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out maps))
{
string newMessageContent;
if (maps.TryGetValue(messageContent.Trim().ToLowerInvariant(), out newMessageContent))
{
_log.Info(@"--Mapping Command--
GuildId: {0}
Trigger: {1}
Mapping: {2}", guild.Id, messageContent, newMessageContent);
var oldMessageContent = messageContent;
messageContent = newMessageContent;
try { await usrMsg.Channel.SendConfirmAsync($"{oldMessageContent} => {newMessageContent}").ConfigureAwait(false); } catch { }
}
}
}
// execute the command and measure the time it took
var exec = await Task.Run(() => ExecuteCommand(new CommandContext(_client, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best)).ConfigureAwait(false);
execTime = Environment.TickCount - execTime;
if (exec.Result.IsSuccess)
{
await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false);
await LogSuccessfulExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime).ConfigureAwait(false);
}
else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand)
{
LogErroredExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime);
if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception)
{
if (exec.PermissionCache != null && exec.PermissionCache.Verbose)
try { await usrMsg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { }
}
}
else
{
if (usrMsg.Channel is IPrivateChannel)
{
// rofl, gotta do this to prevent dm help message being sent to
// users who are voting on private polls (sending a number in a DM)
int vote;
if (int.TryParse(usrMsg.Content, out vote)) return;
await usrMsg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false);
await SelfCommands.HandleDmForwarding(usrMsg, ownerChannels).ConfigureAwait(false);
}
}
}
public Task<ExecuteCommandResult> ExecuteCommandAsync(CommandContext context, int argPos, IDependencyMap dependencyMap = null, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception) public Task<ExecuteCommandResult> ExecuteCommandAsync(CommandContext context, int argPos, IDependencyMap dependencyMap = null, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
=> ExecuteCommand(context, context.Message.Content.Substring(argPos), dependencyMap, multiMatchHandling); => ExecuteCommand(context, context.Message.Content.Substring(argPos), dependencyMap, multiMatchHandling);

View File

@ -61,6 +61,19 @@ Nadeko Support Server: https://discord.gg/nadekobot";
public string OkColor { get; set; } = "71cd40"; public string OkColor { get; set; } = "71cd40";
public string ErrorColor { get; set; } = "ee281f"; public string ErrorColor { get; set; } = "ee281f";
public string Locale { get; set; } = null; public string Locale { get; set; } = null;
public List<StartupCommand> StartupCommands { get; set; }
}
public class StartupCommand : DbEntity, IIndexed
{
public int Index { get; set; }
public string CommandText { get; set; }
public ulong ChannelId { get; set; }
public string ChannelName { get; set; }
public ulong? GuildId { get; set; }
public string GuildName { get; set; }
public ulong? VoiceChannelId { get; set; }
public string VoiceChannelName { get; set; }
} }
public class PlayingStatus :DbEntity public class PlayingStatus :DbEntity

View File

@ -1,9 +1,12 @@
using NadekoBot.Services.Database.Models; using Microsoft.EntityFrameworkCore;
using NadekoBot.Services.Database.Models;
using System;
using System.Linq;
namespace NadekoBot.Services.Database.Repositories namespace NadekoBot.Services.Database.Repositories
{ {
public interface IBotConfigRepository : IRepository<BotConfig> public interface IBotConfigRepository : IRepository<BotConfig>
{ {
BotConfig GetOrCreate(); BotConfig GetOrCreate(Func<DbSet<BotConfig>, IQueryable<BotConfig>> includes = null);
} }
} }

View File

@ -1,6 +1,7 @@
using NadekoBot.Services.Database.Models; using NadekoBot.Services.Database.Models;
using System.Linq; using System.Linq;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System;
namespace NadekoBot.Services.Database.Repositories.Impl namespace NadekoBot.Services.Database.Repositories.Impl
{ {
@ -10,15 +11,21 @@ namespace NadekoBot.Services.Database.Repositories.Impl
{ {
} }
public BotConfig GetOrCreate() public BotConfig GetOrCreate(Func<DbSet<BotConfig>, IQueryable<BotConfig>> includes = null)
{ {
var config = _set.Include(bc => bc.RotatingStatusMessages) BotConfig config;
if (includes == null)
config = _set.Include(bc => bc.RotatingStatusMessages)
.Include(bc => bc.RaceAnimals) .Include(bc => bc.RaceAnimals)
.Include(bc => bc.Blacklist) .Include(bc => bc.Blacklist)
.Include(bc => bc.EightBallResponses) .Include(bc => bc.EightBallResponses)
.Include(bc => bc.ModulePrefixes) .Include(bc => bc.ModulePrefixes)
.Include(bc => bc.StartupCommands)
//.Include(bc => bc.CommandCosts) //.Include(bc => bc.CommandCosts)
.FirstOrDefault(); .FirstOrDefault();
else
config = includes(_set).FirstOrDefault();
if (config == null) if (config == null)
{ {