diff --git a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs index 8d50a80e..2e06347a 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs @@ -1,14 +1,18 @@ using Discord; using Discord.Commands; +using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; +using NadekoBot.Services.Database; using NadekoBot.Services.Database.Models; using NLog; using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; @@ -19,7 +23,8 @@ namespace NadekoBot.Modules.Administration [Group] public class RepeatCommands : ModuleBase { - public static ConcurrentDictionary repeaters { get; } + //guildid/RepeatRunners + public static ConcurrentDictionary> repeaters { get; } public class RepeatRunner { @@ -83,7 +88,10 @@ namespace NadekoBot.Modules.Administration var sw = Stopwatch.StartNew(); using (var uow = DbHandler.UnitOfWork()) { - repeaters = new ConcurrentDictionary(uow.Repeaters.GetAll().Select(r => new RepeatRunner(r)).Where(r => r != null).ToDictionary(r => r.Repeater.ChannelId)); + repeaters = new ConcurrentDictionary>(NadekoBot.AllGuildConfigs + .ToDictionary(gc => gc.GuildId, + gc => new ConcurrentQueue(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr)) + .Where(gr => gr.Channel != null)))); } sw.Stop(); @@ -93,41 +101,70 @@ namespace NadekoBot.Modules.Administration [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageMessages)] - public async Task RepeatInvoke() + public async Task RepeatInvoke(int index) { - RepeatRunner rep; + index -= 1; + ConcurrentQueue rep; if (!repeaters.TryGetValue(Context.Channel.Id, out rep)) { await Context.Channel.SendErrorAsync("ℹ️ **No repeating message found on this server.**").ConfigureAwait(false); return; } - rep.Reset(); - await Context.Channel.SendMessageAsync("🔄 " + rep.Repeater.Message).ConfigureAwait(false); - } - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.ManageMessages)] - public async Task Repeat() - { - RepeatRunner rep; - if (repeaters.TryRemove(Context.Channel.Id, out rep)) + var repList = rep.ToList(); + + if (index >= repList.Count) { - using (var uow = DbHandler.UnitOfWork()) - { - uow.Repeaters.Remove(rep.Repeater); - await uow.CompleteAsync(); - } - rep.Stop(); - await Context.Channel.SendConfirmAsync("✅ **Stopped repeating a message.**").ConfigureAwait(false); + await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false); + return; } - else - await Context.Channel.SendConfirmAsync("ℹ️ **No message is repeating.**").ConfigureAwait(false); + var repeater = repList[index].Repeater; + + await Context.Channel.SendMessageAsync("🔄 " + repeater.Message).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageMessages)] + [Priority(0)] + public async Task RepeatRemove(int index) + { + if (index < 1) + return; + index -= 1; + + ConcurrentQueue rep; + if (!repeaters.TryGetValue(Context.Guild.Id, out rep)) + return; + + var repeaterList = rep.ToList(); + + if (index >= repeaterList.Count) + { + await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false); + return; + } + + var repeater = repeaterList[index]; + repeater.Stop(); + repeaterList.RemoveAt(index); + + using (var uow = DbHandler.UnitOfWork()) + { + var guildConfig = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(gc => gc.GuildRepeaters)); + + guildConfig.GuildRepeaters.RemoveWhere(r=>r.Id == repeater.Repeater.Id); + await uow.CompleteAsync().ConfigureAwait(false); + } + + if (repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue(repeaterList), rep)) + await Context.Channel.SendConfirmAsync("✅ **Stopped repeating a message.**").ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + [Priority(1)] public async Task Repeat(int minutes, [Remainder] string message) { if (minutes < 1 || minutes > 10080) @@ -136,38 +173,52 @@ namespace NadekoBot.Modules.Administration if (string.IsNullOrWhiteSpace(message)) return; - RepeatRunner rep; + var toAdd = new Repeater() + { + ChannelId = Context.Channel.Id, + GuildId = Context.Guild.Id, + Interval = TimeSpan.FromMinutes(minutes), + Message = message + }; - rep = repeaters.AddOrUpdate(Context.Channel.Id, (cid) => + var rep = new RepeatRunner(toAdd, (ITextChannel)Context.Channel); + + repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue(new[] { rep }), (key, old) => { - using (var uow = DbHandler.UnitOfWork()) - { - var localRep = new Repeater - { - ChannelId = Context.Channel.Id, - GuildId = Context.Guild.Id, - Interval = TimeSpan.FromMinutes(minutes), - Message = message, - }; - uow.Repeaters.Add(localRep); - uow.Complete(); - return new RepeatRunner(localRep, (ITextChannel)Context.Channel); - } - }, (cid, old) => - { - using (var uow = DbHandler.UnitOfWork()) - { - old.Repeater.Message = message; - old.Repeater.Interval = TimeSpan.FromMinutes(minutes); - uow.Repeaters.Update(old.Repeater); - uow.Complete(); - } - old.Reset(); + old.Enqueue(rep); return old; }); - + await Context.Channel.SendConfirmAsync($"🔁 Repeating **\"{rep.Repeater.Message}\"** every `{rep.Repeater.Interval.Days} day(s), {rep.Repeater.Interval.Hours} hour(s) and {rep.Repeater.Interval.Minutes} minute(s)`.").ConfigureAwait(false); } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + public async Task RepeatList() + { + ConcurrentQueue repRunners; + if (!repeaters.TryGetValue(Context.Guild.Id, out repRunners)) + { + await Context.Channel.SendConfirmAsync("No repeaters running on this server.").ConfigureAwait(false); + return; + } + + var replist = repRunners.ToList(); + var sb = new StringBuilder(); + + for (int i = 0; i < replist.Count; i++) + { + var rep = replist[i]; + + sb.AppendLine($"`{i + 1}.` {rep.Channel.Mention} | {(int)rep.Repeater.Interval.TotalHours}:{rep.Repeater.Interval:mm} | {rep.Repeater.Message.TrimTo(20)}"); + } + + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle("List Of Repeaters") + .WithDescription(sb.ToString())) + .ConfigureAwait(false); + } } } } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 58126412..fc8637da 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -5712,7 +5712,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Repeat a message every X minutes. If no parameters are specified, repeat is disabled.. + /// Looks up a localized string similar to Repeat a message every X minutes in the current channel.. /// public static string repeat_desc { get { @@ -5739,7 +5739,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Immediately shows the repeat message and restarts the timer.. + /// Looks up a localized string similar to Immediately shows the repeat message on a certain index and restarts its timer.. /// public static string repeatinvoke_desc { get { @@ -5748,7 +5748,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}repinv`. + /// Looks up a localized string similar to `{0}repinv 1`. /// public static string repeatinvoke_usage { get { @@ -5756,6 +5756,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to repeatlist replst. + /// + public static string repeatlist_cmd { + get { + return ResourceManager.GetString("repeatlist_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows currently repeating messages and their indexes.. + /// + public static string repeatlist_desc { + get { + return ResourceManager.GetString("repeatlist_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}repeatlist`. + /// + public static string repeatlist_usage { + get { + return ResourceManager.GetString("repeatlist_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to rpeatplaylst rpl. /// @@ -5783,6 +5810,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to repeatremove reprm. + /// + public static string repeatremove_cmd { + get { + return ResourceManager.GetString("repeatremove_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes.. + /// + public static string repeatremove_desc { + get { + return ResourceManager.GetString("repeatremove_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}reprm 2`. + /// + public static string repeatremove_usage { + get { + return ResourceManager.GetString("repeatremove_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to reptcursong rcs. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 3b13300e..cc144d2d 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -265,16 +265,16 @@ repeatinvoke repinv - Immediately shows the repeat message and restarts the timer. + Immediately shows the repeat message on a certain index and restarts its timer. - `{0}repinv` + `{0}repinv 1` repeat - Repeat a message every X minutes. If no parameters are specified, repeat is disabled. + Repeat a message every X minutes in the current channel. `{0}repeat 5 Hello there` @@ -2889,4 +2889,22 @@ `{0}pollstats` + + repeatlist replst + + + Shows currently repeating messages and their indexes. + + + `{0}repeatlist` + + + repeatremove reprm + + + Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes. + + + `{0}reprm 2` + \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index 99608eff..e4ed7c97 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -58,6 +58,7 @@ namespace NadekoBot.Services.Database.Models public string MuteRoleName { get; set; } public bool CleverbotEnabled { get; set; } + public HashSet GuildRepeaters { get; set; } } public class FilterChannelId : DbEntity