From 248dab485594a0932d6835bb2c79a73caa5752d1 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 28 Aug 2016 22:59:12 +0200 Subject: [PATCH] work on repeater --- ...er.cs => 20160828153124_first.Designer.cs} | 23 ++- ...00228_first.cs => 20160828153124_first.cs} | 25 +++ .../NadekoSqliteContextModelSnapshot.cs | 21 ++ .../Commands/MessageRepeater.cs | 182 ++++++++---------- .../Services/Database/IUnitOfWork.cs | 1 + .../Services/Database/Models/Repeater.cs | 16 ++ .../Services/Database/NadekoContext.cs | 11 ++ .../Repositories/IRepeaterRepository.cs | 14 ++ .../Repositories/Impl/RepeaterRepository.cs | 17 ++ src/NadekoBot/Services/Database/UnitOfWork.cs | 3 + 10 files changed, 209 insertions(+), 104 deletions(-) rename src/NadekoBot/Migrations/{20160828000228_first.Designer.cs => 20160828153124_first.Designer.cs} (94%) rename src/NadekoBot/Migrations/{20160828000228_first.cs => 20160828153124_first.cs} (94%) create mode 100644 src/NadekoBot/Services/Database/Models/Repeater.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/IRepeaterRepository.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/Impl/RepeaterRepository.cs diff --git a/src/NadekoBot/Migrations/20160828000228_first.Designer.cs b/src/NadekoBot/Migrations/20160828153124_first.Designer.cs similarity index 94% rename from src/NadekoBot/Migrations/20160828000228_first.Designer.cs rename to src/NadekoBot/Migrations/20160828153124_first.Designer.cs index 43f73276..9b60ffb2 100644 --- a/src/NadekoBot/Migrations/20160828000228_first.Designer.cs +++ b/src/NadekoBot/Migrations/20160828153124_first.Designer.cs @@ -8,7 +8,7 @@ using NadekoBot.Services.Database.Impl; namespace NadekoBot.Migrations { [DbContext(typeof(NadekoSqliteContext))] - [Migration("20160828000228_first")] + [Migration("20160828153124_first")] partial class first { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -281,6 +281,27 @@ namespace NadekoBot.Migrations b.ToTable("Reminders"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.Repeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.HasKey("Id"); + + b.HasIndex("ChannelId") + .IsUnique(); + + b.ToTable("Repeaters"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => { b.Property("Id") diff --git a/src/NadekoBot/Migrations/20160828000228_first.cs b/src/NadekoBot/Migrations/20160828153124_first.cs similarity index 94% rename from src/NadekoBot/Migrations/20160828000228_first.cs rename to src/NadekoBot/Migrations/20160828153124_first.cs index 081d2cb9..ca6ea305 100644 --- a/src/NadekoBot/Migrations/20160828000228_first.cs +++ b/src/NadekoBot/Migrations/20160828153124_first.cs @@ -125,6 +125,22 @@ namespace NadekoBot.Migrations table.PrimaryKey("PK_Reminders", x => x.Id); }); + migrationBuilder.CreateTable( + name: "Repeaters", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Autoincrement", true), + ChannelId = table.Column(nullable: false), + GuildId = table.Column(nullable: false), + Interval = table.Column(nullable: false), + Message = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Repeaters", x => x.Id); + }); + migrationBuilder.CreateTable( name: "SelfAssignableRoles", columns: table => new @@ -306,6 +322,12 @@ namespace NadekoBot.Migrations table: "RaceAnimal", column: "BotConfigId"); + migrationBuilder.CreateIndex( + name: "IX_Repeaters_ChannelId", + table: "Repeaters", + column: "ChannelId", + unique: true); + migrationBuilder.CreateIndex( name: "IX_SelfAssignableRoles_GuildId_RoleId", table: "SelfAssignableRoles", @@ -345,6 +367,9 @@ namespace NadekoBot.Migrations migrationBuilder.DropTable( name: "Reminders"); + migrationBuilder.DropTable( + name: "Repeaters"); + migrationBuilder.DropTable( name: "SelfAssignableRoles"); diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index b9042c98..0ab69283 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -280,6 +280,27 @@ namespace NadekoBot.Migrations b.ToTable("Reminders"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.Repeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.HasKey("Id"); + + b.HasIndex("ChannelId") + .IsUnique(); + + b.ToTable("Repeaters"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => { b.Property("Id") diff --git a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs index 520372db..95834815 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs @@ -1,130 +1,106 @@ using Discord; using Discord.Commands; -using NadekoBot.Classes; -using NadekoBot.Modules.Permissions.Classes; +using NadekoBot.Attributes; +using NadekoBot.Services; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; using System; using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; -using System.Timers; //todo DB namespace NadekoBot.Modules.Administration { - class MessageRepeater : DiscordCommand + public partial class Administration { - private readonly ConcurrentDictionary repeaters = new ConcurrentDictionary(); - private class Repeater + + [Group] + public class RepeatCommands { - [Newtonsoft.Json.JsonIgnore] - public Timer MessageTimer { get; set; } - [Newtonsoft.Json.JsonIgnore] - public Channel RepeatingChannel { get; set; } + public ConcurrentDictionary repeaters; - public ulong RepeatingServerId { get; set; } - public ulong RepeatingChannelId { get; set; } - public Message lastMessage { get; set; } = null; - public string RepeatingMessage { get; set; } - public int Interval { get; set; } - - public Repeater Start() + public RepeatCommands() { - MessageTimer = new Timer { Interval = Interval }; - MessageTimer.Elapsed += async (s, e) => await Invoke(); - return this; - } - - public async Task Invoke() - { - var ch = RepeatingChannel; - var msg = RepeatingMessage; - if (ch != null && !string.IsNullOrWhiteSpace(msg)) + using (var uow = DbHandler.UnitOfWork()) { - try - { - if (lastMessage != null) - await lastMessage.Delete().ConfigureAwait(false); - } - catch { } - try - { - lastMessage = await ch.SendMessageAsync(msg).ConfigureAwait(false); - } - catch { } + repeaters = new ConcurrentDictionary(uow.Repeaters.GetAll().ToDictionary(r => r.ChannelId)); } } - } - internal override void Init(CommandGroupBuilder cgb) - { - cgb.CreateCommand(Module.Prefix + "repeatinvoke") - .Alias(Module.Prefix + "repinv") - .Description($"Immediately shows the repeat message and restarts the timer. **Needs Manage Messages Permissions.**| `{Prefix}repinv`") - .AddCheck(SimpleCheckers.ManageMessages()) - .Do(async e => + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + [RequirePermission(GuildPermission.ManageMessages)] + public async Task RepeatInvoke(IMessage imsg) + { + var channel = (ITextChannel)imsg.Channel; + + Repeater rep; + if (!repeaters.TryGetValue(channel.Id, out rep)) { - Repeater rep; - if (!repeaters.TryGetValue(e.Server, out rep)) - { - await channel.SendMessageAsync("`No repeating message found on this server.`"); - return; - } + await channel.SendMessageAsync("`No repeating message found on this server.`").ConfigureAwait(false); + return; + } - await rep.Invoke(); - }); + await channel.SendMessageAsync("🔄 " + rep.Message); + } - cgb.CreateCommand(Module.Prefix + "repeat") - .Description("Repeat a message every X minutes. If no parameters are specified, " + - $"repeat is disabled. **Needs Manage Messages Permissions.** |`{Prefix}repeat 5 Hello there`") - .Parameter("minutes", ParameterType.Optional) - .Parameter("msg", ParameterType.Unparsed) - .AddCheck(SimpleCheckers.ManageMessages()) - .Do(async e => + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task Repeat(IMessage imsg, int minutes, [Remainder] string message = null) + { + var channel = (ITextChannel)imsg.Channel; + + if (minutes < 1 || minutes > 1500) + return; + + Repeater rep; + + if (string.IsNullOrWhiteSpace(message)) //turn off { - var minutesStr = minutes; - var msg = msg; - - // if both null, disable - if (string.IsNullOrWhiteSpace(msg) && string.IsNullOrWhiteSpace(minutesStr)) + if (repeaters.TryRemove(channel.Id, out rep)) { - - Repeater rep; - if (!repeaters.TryRemove(e.Server, out rep)) - return; - rep.MessageTimer.Stop(); - await channel.SendMessageAsync("Repeating disabled").ConfigureAwait(false); - return; - } - int minutes; - if (!int.TryParse(minutesStr, out minutes) || minutes < 1 || minutes > 1440) - { - await channel.SendMessageAsync("Invalid value").ConfigureAwait(false); - return; - } - - var repeater = repeaters.GetOrAdd( - e.Server, - s => new Repeater + using (var uow = DbHandler.UnitOfWork()) { - Interval = minutes * 60 * 1000, - RepeatingChannel = e.Channel, - RepeatingChannelId = e.Channel.Id, - RepeatingServerId = e.Server.Id, - }.Start() - ); + uow.Repeaters.Remove(rep); + await uow.CompleteAsync(); + } + await channel.SendMessageAsync("`Stopped repeating a message.`").ConfigureAwait(false); + } + else + await channel.SendMessageAsync("`No message is repeating.`").ConfigureAwait(false); + return; + } - if (!string.IsNullOrWhiteSpace(msg)) - repeater.RepeatingMessage = msg; - - repeater.MessageTimer.Stop(); - repeater.MessageTimer.Start(); - - await channel.SendMessageAsync(String.Format("👌 Repeating `{0}` every " + - "**{1}** minutes on {2} channel.", - repeater.RepeatingMessage, minutes, repeater.RepeatingChannel)) - .ConfigureAwait(false); + rep = repeaters.AddOrUpdate(channel.Id, (cid) => + { + using (var uow = DbHandler.UnitOfWork()) + { + var localRep = new Repeater + { + ChannelId = channel.Id, + GuildId = channel.Guild.Id, + Interval = TimeSpan.FromMinutes(minutes), + Message = message, + }; + uow.Repeaters.Add(localRep); + uow.Complete(); + return localRep; + } + }, (cid, old) => + { + using (var uow = DbHandler.UnitOfWork()) + { + old.Message = message; + old.Interval = TimeSpan.FromMinutes(minutes); + uow.Repeaters.Update(old); + uow.Complete(); + return old; + } }); - } + } - public MessageRepeater(DiscordModule module) : base(module) { } + } } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/IUnitOfWork.cs b/src/NadekoBot/Services/Database/IUnitOfWork.cs index 3a3fb2c2..905af9af 100644 --- a/src/NadekoBot/Services/Database/IUnitOfWork.cs +++ b/src/NadekoBot/Services/Database/IUnitOfWork.cs @@ -16,6 +16,7 @@ namespace NadekoBot.Services.Database IReminderRepository Reminders { get; } ISelfAssignedRolesRepository SelfAssignedRoles { get; } IBotConfigRepository BotConfig { get; } + IRepeaterRepository Repeaters { get; } int Complete(); Task CompleteAsync(); diff --git a/src/NadekoBot/Services/Database/Models/Repeater.cs b/src/NadekoBot/Services/Database/Models/Repeater.cs new file mode 100644 index 00000000..ba5552f9 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/Repeater.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Models +{ + public class Repeater :DbEntity + { + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + public string Message { get; set; } + public TimeSpan Interval { get; set; } + } +} diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index 378c1637..a8e9ae39 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -18,6 +18,7 @@ namespace NadekoBot.Services.Database public DbSet Reminders { get; set; } public DbSet SelfAssignableRoles { get; set; } public DbSet BotConfig { get; set; } + public DbSet Repeaters { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { @@ -63,6 +64,16 @@ namespace NadekoBot.Services.Database .IsUnique(); #endregion + + #region Repeater + + var repeaterEntity = modelBuilder.Entity(); + + repeaterEntity + .HasIndex(r => r.ChannelId) + .IsUnique(); + + #endregion } protected abstract override void OnConfiguring(DbContextOptionsBuilder optionsBuilder); } diff --git a/src/NadekoBot/Services/Database/Repositories/IRepeaterRepository.cs b/src/NadekoBot/Services/Database/Repositories/IRepeaterRepository.cs new file mode 100644 index 00000000..7bd5c67f --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/IRepeaterRepository.cs @@ -0,0 +1,14 @@ +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Repositories +{ + public interface IRepeaterRepository : IRepository + { + + } +} diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/RepeaterRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/RepeaterRepository.cs new file mode 100644 index 00000000..33885856 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/Impl/RepeaterRepository.cs @@ -0,0 +1,17 @@ +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; + +namespace NadekoBot.Services.Database.Repositories.Impl +{ + public class RepeaterRepository : Repository, IRepeaterRepository + { + public RepeaterRepository(DbContext context) : base(context) + { + } + } +} diff --git a/src/NadekoBot/Services/Database/UnitOfWork.cs b/src/NadekoBot/Services/Database/UnitOfWork.cs index 5550bc6c..11dca26f 100644 --- a/src/NadekoBot/Services/Database/UnitOfWork.cs +++ b/src/NadekoBot/Services/Database/UnitOfWork.cs @@ -33,6 +33,9 @@ namespace NadekoBot.Services.Database private IBotConfigRepository _botConfig; public IBotConfigRepository BotConfig => _botConfig ?? (_botConfig = new BotConfigRepository(_context)); + private IRepeaterRepository _repeaters; + public IRepeaterRepository Repeaters => _repeaters ?? (_repeaters = new RepeaterRepository(_context)); + public UnitOfWork(NadekoContext context) { _context = context;