From 6ca96d025de413a8f6ea50b73d8b432d990cda97 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 26 Aug 2016 00:05:29 +0200 Subject: [PATCH] Reminders converted --- ...er.cs => 20160825184527_first.Designer.cs} | 24 +- ...72257_first.cs => 20160825184527_first.cs} | 21 ++ .../NadekoSqliteContextModelSnapshot.cs | 22 ++ .../Modules/Utility/Commands/Remind.cs | 357 +++++++++--------- .../Services/Database/IUnitOfWork.cs | 1 + .../Services/Database/Models/Reminder.cs | 18 + .../Services/Database/NadekoContext.cs | 1 + .../Repositories/IReminderRepository.cs | 14 + .../Repositories/Impl/ReminderRepository.cs | 17 + src/NadekoBot/Services/Database/UnitOfWork.cs | 3 + src/NadekoBot/_Models/DataModels/Reminder.cs | 14 - 11 files changed, 302 insertions(+), 190 deletions(-) rename src/NadekoBot/Migrations/{20160825172257_first.Designer.cs => 20160825184527_first.Designer.cs} (87%) rename src/NadekoBot/Migrations/{20160825172257_first.cs => 20160825184527_first.cs} (87%) create mode 100644 src/NadekoBot/Services/Database/Models/Reminder.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/IReminderRepository.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/Impl/ReminderRepository.cs delete mode 100644 src/NadekoBot/_Models/DataModels/Reminder.cs diff --git a/src/NadekoBot/Migrations/20160825172257_first.Designer.cs b/src/NadekoBot/Migrations/20160825184527_first.Designer.cs similarity index 87% rename from src/NadekoBot/Migrations/20160825172257_first.Designer.cs rename to src/NadekoBot/Migrations/20160825184527_first.Designer.cs index d445b8da..67cccb93 100644 --- a/src/NadekoBot/Migrations/20160825172257_first.Designer.cs +++ b/src/NadekoBot/Migrations/20160825184527_first.Designer.cs @@ -8,7 +8,7 @@ using NadekoBot.Services.Database.Impl; namespace NadekoBot.Migrations { [DbContext(typeof(NadekoSqliteContext))] - [Migration("20160825172257_first")] + [Migration("20160825184527_first")] partial class first { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -143,6 +143,28 @@ namespace NadekoBot.Migrations b.ToTable("Quotes"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => { b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") diff --git a/src/NadekoBot/Migrations/20160825172257_first.cs b/src/NadekoBot/Migrations/20160825184527_first.cs similarity index 87% rename from src/NadekoBot/Migrations/20160825172257_first.cs rename to src/NadekoBot/Migrations/20160825184527_first.cs index f9a4b3c6..0ebda92c 100644 --- a/src/NadekoBot/Migrations/20160825172257_first.cs +++ b/src/NadekoBot/Migrations/20160825184527_first.cs @@ -84,6 +84,24 @@ namespace NadekoBot.Migrations table.PrimaryKey("PK_Quotes", x => x.Id); }); + migrationBuilder.CreateTable( + name: "Reminders", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Autoincrement", true), + ChannelId = table.Column(nullable: false), + IsPrivate = table.Column(nullable: false), + Message = table.Column(nullable: true), + ServerId = table.Column(nullable: false), + UserId = table.Column(nullable: false), + When = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Reminders", x => x.Id); + }); + migrationBuilder.CreateTable( name: "ClashCallers", columns: table => new @@ -139,6 +157,9 @@ namespace NadekoBot.Migrations migrationBuilder.DropTable( name: "Quotes"); + migrationBuilder.DropTable( + name: "Reminders"); + migrationBuilder.DropTable( name: "ClashOfClans"); } diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 02d12786..fe3144fd 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -142,6 +142,28 @@ namespace NadekoBot.Migrations b.ToTable("Quotes"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => { b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") diff --git a/src/NadekoBot/Modules/Utility/Commands/Remind.cs b/src/NadekoBot/Modules/Utility/Commands/Remind.cs index f6c67748..882fa5d8 100644 --- a/src/NadekoBot/Modules/Utility/Commands/Remind.cs +++ b/src/NadekoBot/Modules/Utility/Commands/Remind.cs @@ -1,197 +1,204 @@ -//using Discord; -//using Discord.Commands; -//using NadekoBot.Classes; -//using NadekoBot.DataModels; -//using NadekoBot.Modules.Permissions.Classes; -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using System.Text.RegularExpressions; -//using System.Timers; +using Discord; +using Discord.Commands; +using Discord.WebSocket; +using NadekoBot.Attributes; +using NadekoBot.Services; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; -//namespace NadekoBot.Modules.Utility -//{ -// class Remind : DiscordCommand -// { +namespace NadekoBot.Modules.Utility +{ + public partial class Utility + { + public class RemindCommands + { -// Regex regex = new Regex(@"^(?:(?\d)mo)?(?:(?\d)w)?(?:(?\d{1,2})d)?(?:(?\d{1,2})h)?(?:(?\d{1,2})m)?$", -// RegexOptions.Compiled | RegexOptions.Multiline); + Regex regex = new Regex(@"^(?:(?\d)mo)?(?:(?\d)w)?(?:(?\d{1,2})d)?(?:(?\d{1,2})h)?(?:(?\d{1,2})m)?$", + RegexOptions.Compiled | RegexOptions.Multiline); -// List reminders = new List(); + IDictionary> replacements = new Dictionary> + { + { "%message%" , (r) => r.Message }, + { "%user%", (r) => $"<@!{r.UserId}>" }, + { "%target%", (r) => r.IsPrivate ? "Direct Message" : $"<#{r.ChannelId}>"} + }; -// IDictionary> replacements = new Dictionary> -// { -// { "%message%" , (r) => r.Message }, -// { "%user%", (r) => $"<@!{r.UserId}>" }, -// { "%target%", (r) => r.IsPrivate ? "Direct Message" : $"<#{r.ChannelId}>"} -// }; + public RemindCommands() + { + List reminders; + using (var uow = DbHandler.UnitOfWork()) + { + reminders = uow.Reminders.GetAll().ToList(); + } -// public Remind(DiscordModule module) : base(module) -// { -// var remList = DbHandler.Instance.GetAllRows(); + foreach (var r in reminders) + { + var t = StartReminder(r); + } + } -// reminders = remList.Select(StartNewReminder).ToList(); -// } + private async Task StartReminder(Reminder r) + { + var now = DateTime.Now; + var twoMins = new TimeSpan(0, 2, 0); + TimeSpan time = (r.When - now) < twoMins + ? twoMins //if the time is less than 2 minutes, + : r.When - now; //it will send the message 2 minutes after start + //To account for high bot startup times + if (time.TotalMilliseconds > int.MaxValue) + return; -// private Timer StartNewReminder(Reminder r) -// { -// var now = DateTime.Now; -// var twoMins = new TimeSpan(0, 2, 0); -// TimeSpan time = (r.When - now) < twoMins -// ? twoMins //if the time is less than 2 minutes, -// : r.When - now; //it will send the message 2 minutes after start -// //To account for high bot startup times -// if (time.TotalMilliseconds > int.MaxValue) -// return null; -// var t = new Timer(time.TotalMilliseconds); -// t.Elapsed += async (s, e) => -// { -// try -// { -// Channel ch; -// if (r.IsPrivate) -// { -// ch = NadekoBot.Client.PrivateChannels.FirstOrDefault(c => (long)c.Id == r.ChannelId); -// if (ch == null) -// ch = await NadekoBot.Client.CreatePrivateChannel((ulong)r.ChannelId).ConfigureAwait(false); -// } -// else -// ch = NadekoBot.Client.GetServer((ulong)r.ServerId)?.GetChannel((ulong)r.ChannelId); + await Task.Delay(time); + try + { + IMessageChannel ch; + if (r.IsPrivate) + { + ch = await NadekoBot.Client.GetDMChannelAsync(r.ChannelId).ConfigureAwait(false); + } + else + { + ch = NadekoBot.Client.GetGuilds() + .Where(g => g.Id == r.ServerId) + .FirstOrDefault() + .GetTextChannels() + .Where(c => c.Id == r.ChannelId) + .FirstOrDefault(); + } + if (ch == null) + return; -// if (ch == null) -// return; + await ch.SendMessageAsync( + replacements.Aggregate(NadekoBot.Config.RemindMessageFormat, + (cur, replace) => cur.Replace(replace.Key, replace.Value(r))) + ).ConfigureAwait(false); //it works trust me -// await ch.SendMessageAsync( -// replacements.Aggregate(NadekoBot.Config.RemindMessageFormat, -// (cur, replace) => cur.Replace(replace.Key, replace.Value(r))) -// ).ConfigureAwait(false); //it works trust me + } + catch (Exception ex) + { + Console.WriteLine($"Timer error! {ex}"); + } + finally + { + using (var uow = DbHandler.UnitOfWork()) + { + uow.Reminders.Remove(r); + await uow.CompleteAsync(); + } + } + } -// } -// catch (Exception ex) -// { -// Console.WriteLine($"Timer error! {ex}"); -// } -// finally -// { -// DbHandler.Instance.Delete(r.Id.Value); -// t.Stop(); -// t.Dispose(); -// } -// }; -// t.Start(); -// return t; -// } + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task Remind(IMessage imsg, string meorchannel, string timeStr, [Remainder] string message) + { + var channel = (ITextChannel)imsg.Channel; -// internal override void Init(CommandGroupBuilder cgb) -// { -// cgb.CreateCommand(Module.Prefix + "remind") -// .Description("Sends a message to you or a channel after certain amount of time. " + -// "First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. " + -// "Third argument is a (multiword)message. " + -// $" | `{Prefix}remind me 1d5h Do something` or `{Prefix}remind #general Start now!`") -// .Parameter("meorchannel", ParameterType.Required) -// .Parameter("time", ParameterType.Required) -// .Parameter("message", ParameterType.Unparsed) -// .Do(async e => -// { -// var meorchStr = meorchannel.ToUpperInvariant(); -// Channel ch; -// bool isPrivate = false; -// if (meorchStr == "ME") -// { -// isPrivate = true; -// ch = await imsg.Author.CreatePMChannel().ConfigureAwait(false); -// } -// else if (meorchStr == "HERE") -// { -// ch = e.Channel; -// } -// else -// { -// ch = e.Server.FindChannels(meorchStr).FirstOrDefault(); -// } + var meorchStr = meorchannel.ToUpperInvariant(); + IMessageChannel ch; + bool isPrivate = false; + if (meorchStr == "ME") + { + isPrivate = true; + ch = await ((IGuildUser)imsg.Author).CreateDMChannelAsync().ConfigureAwait(false); + } + else if (meorchStr == "HERE") + { + ch = channel; + } + else + { + ch = channel.Guild.GetTextChannels().FirstOrDefault(c => c.Name == meorchStr || c.Id.ToString() == meorchStr); + } -// if (ch == null) -// { -// await channel.SendMessageAsync($"{imsg.Author.Mention} Something went wrong (channel cannot be found) ;(").ConfigureAwait(false); -// return; -// } + if (ch == null) + { + await channel.SendMessageAsync($"{imsg.Author.Mention} Something went wrong (channel cannot be found) ;(").ConfigureAwait(false); + return; + } -// var timeStr = time; + var m = regex.Match(timeStr); -// var m = regex.Match(timeStr); + if (m.Length == 0) + { + await channel.SendMessageAsync("Not a valid time format blablabla").ConfigureAwait(false); + return; + } -// if (m.Length == 0) -// { -// await channel.SendMessageAsync("Not a valid time format blablabla").ConfigureAwait(false); -// return; -// } + string output = ""; + var namesAndValues = new Dictionary(); -// string output = ""; -// var namesAndValues = new Dictionary(); + foreach (var groupName in regex.GetGroupNames()) + { + if (groupName == "0") continue; + int value = 0; + int.TryParse(m.Groups[groupName].Value, out value); -// foreach (var groupName in regex.GetGroupNames()) -// { -// if (groupName == "0") continue; -// int value = 0; -// int.TryParse(m.Groups[groupName].Value, out value); + if (string.IsNullOrEmpty(m.Groups[groupName].Value)) + { + namesAndValues[groupName] = 0; + continue; + } + else if (value < 1 || + (groupName == "months" && value > 1) || + (groupName == "weeks" && value > 4) || + (groupName == "days" && value >= 7) || + (groupName == "hours" && value > 23) || + (groupName == "minutes" && value > 59)) + { + await channel.SendMessageAsync($"Invalid {groupName} value.").ConfigureAwait(false); + return; + } + else + namesAndValues[groupName] = value; + output += m.Groups[groupName].Value + " " + groupName + " "; + } + var time = DateTime.Now + new TimeSpan(30 * namesAndValues["months"] + + 7 * namesAndValues["weeks"] + + namesAndValues["days"], + namesAndValues["hours"], + namesAndValues["minutes"], + 0); -// if (string.IsNullOrEmpty(m.Groups[groupName].Value)) -// { -// namesAndValues[groupName] = 0; -// continue; -// } -// else if (value < 1 || -// (groupName == "months" && value > 1) || -// (groupName == "weeks" && value > 4) || -// (groupName == "days" && value >= 7) || -// (groupName == "hours" && value > 23) || -// (groupName == "minutes" && value > 59)) -// { -// await channel.SendMessageAsync($"Invalid {groupName} value.").ConfigureAwait(false); -// return; -// } -// else -// namesAndValues[groupName] = value; -// output += m.Groups[groupName].Value + " " + groupName + " "; -// } -// var time = DateTime.Now + new TimeSpan(30 * namesAndValues["months"] + -// 7 * namesAndValues["weeks"] + -// namesAndValues["days"], -// namesAndValues["hours"], -// namesAndValues["minutes"], -// 0); + var rem = new Reminder + { + ChannelId = ch.Id, + IsPrivate = isPrivate, + When = time, + Message = message, + UserId = imsg.Author.Id, + ServerId = channel.Guild.Id + }; -// var rem = new Reminder -// { -// ChannelId = (long)ch.Id, -// IsPrivate = isPrivate, -// When = time, -// Message = message, -// UserId = (long)imsg.Author.Id, -// ServerId = (long)e.Server.Id -// }; -// DbHandler.Instance.Connection.Insert(rem); + using (var uow = DbHandler.UnitOfWork()) + { + uow.Reminders.Add(rem); + } -// reminders.Add(StartNewReminder(rem)); + await channel.SendMessageAsync($"⏰ I will remind \"{(ch is ITextChannel ? ((ITextChannel)ch).Name : imsg.Author.Username)}\" to \"{message.ToString()}\" in {output}. ({time:d.M.yyyy.} at {time:HH:mm})").ConfigureAwait(false); + } -// await channel.SendMessageAsync($"⏰ I will remind \"{ch.Name}\" to \"{message.ToString()}\" in {output}. ({time:d.M.yyyy.} at {time:HH:mm})").ConfigureAwait(false); -// }); -// cgb.CreateCommand(Module.Prefix + "remindmsg") -// .Description("Sets message for when the remind is triggered. " + -// " Available placeholders are %user% - user who ran the command, %message% -" + -// $" Message specified in the remind, %target% - target channel of the remind. **Bot Owner Only!** | `{Prefix}remindmsg do something else`") -// .Parameter("msg", ParameterType.Unparsed) -// .AddCheck(SimpleCheckers.OwnerOnly()) -// .Do(async e => -// { -// var arg = msg?.Trim(); -// if (string.IsNullOrWhiteSpace(arg)) -// return; + ////todo owner only + //[LocalizedCommand, LocalizedDescription, LocalizedSummary] + //[RequireContext(ContextType.Guild)] + //public async Task RemindTemplate(IMessage imsg, [Remainder] string arg) + //{ + // var channel = (ITextChannel)imsg.Channel; -// NadekoBot.Config.RemindMessageFormat = arg; -// await channel.SendMessageAsync("`New remind message set.`"); -// }); -// } -// } -//} + + // arg = arg?.Trim(); + // if (string.IsNullOrWhiteSpace(arg)) + // return; + + // NadekoBot.Config.RemindMessageFormat = arg; + // await channel.SendMessageAsync("`New remind message set.`"); + //} + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/IUnitOfWork.cs b/src/NadekoBot/Services/Database/IUnitOfWork.cs index 74956906..f2f49a09 100644 --- a/src/NadekoBot/Services/Database/IUnitOfWork.cs +++ b/src/NadekoBot/Services/Database/IUnitOfWork.cs @@ -13,6 +13,7 @@ namespace NadekoBot.Services.Database IConfigRepository GuildConfigs { get; } IDonatorsRepository Donators { get; } IClashOfClansRepository ClashOfClans { get; } + IReminderRepository Reminders { get; } int Complete(); Task CompleteAsync(); diff --git a/src/NadekoBot/Services/Database/Models/Reminder.cs b/src/NadekoBot/Services/Database/Models/Reminder.cs new file mode 100644 index 00000000..693cac31 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/Reminder.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Models +{ + public class Reminder : DbEntity + { + public DateTime When { get; set; } + public ulong ChannelId { get; set; } + public ulong ServerId { get; set; } + public ulong UserId { get; set; } + public string Message { get; set; } + public bool IsPrivate { get; set; } + } +} diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index 4676c3fb..5bc4cc1f 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -15,6 +15,7 @@ namespace NadekoBot.Services.Database public DbSet GuildConfigs { get; set; } public DbSet ClashOfClans { get; set; } public DbSet ClashCallers { get; set; } + public DbSet Reminders { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { diff --git a/src/NadekoBot/Services/Database/Repositories/IReminderRepository.cs b/src/NadekoBot/Services/Database/Repositories/IReminderRepository.cs new file mode 100644 index 00000000..8a1ef365 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/IReminderRepository.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 IReminderRepository : IRepository + { + + } +} diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/ReminderRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/ReminderRepository.cs new file mode 100644 index 00000000..d2e74452 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/Impl/ReminderRepository.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 ReminderRepository : Repository, IReminderRepository + { + public ReminderRepository(DbContext context) : base(context) + { + } + } +} diff --git a/src/NadekoBot/Services/Database/UnitOfWork.cs b/src/NadekoBot/Services/Database/UnitOfWork.cs index 2565a228..ec4858c0 100644 --- a/src/NadekoBot/Services/Database/UnitOfWork.cs +++ b/src/NadekoBot/Services/Database/UnitOfWork.cs @@ -24,6 +24,9 @@ namespace NadekoBot.Services.Database private IClashOfClansRepository _clashOfClans; public IClashOfClansRepository ClashOfClans => _clashOfClans ?? (_clashOfClans = new ClashOfClansRepository(_context)); + private IReminderRepository _reminders; + public IReminderRepository Reminders => _reminders ?? (_reminders = new ReminderRepository(_context)); + public UnitOfWork(NadekoContext context) { _context = context; diff --git a/src/NadekoBot/_Models/DataModels/Reminder.cs b/src/NadekoBot/_Models/DataModels/Reminder.cs deleted file mode 100644 index 043700fd..00000000 --- a/src/NadekoBot/_Models/DataModels/Reminder.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace NadekoBot.DataModels -{ - class Reminder : IDataModel - { - public DateTime When { get; set; } - public long ChannelId { get; set; } - public long ServerId { get; set; } - public long UserId { get; set; } - public string Message { get; set; } - public bool IsPrivate { get; set; } - } -}