Merge pull request #380 from 13xforever/vnext

Misc improvements
This commit is contained in:
Ilya 2019-08-19 21:30:13 +05:00 committed by GitHub
commit 750baff306
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 135 additions and 52 deletions

View File

@ -1,7 +1,5 @@
using System;
using System.Threading.Tasks;
using System.Threading.Tasks;
using CompatBot.Utils;
using DSharpPlus;
using DSharpPlus.CommandsNext;
using DSharpPlus.CommandsNext.Attributes;
using DSharpPlus.Entities;
@ -24,7 +22,7 @@ namespace CompatBot.Commands.Attributes
public override async Task<bool> ExecuteCheckAsync(CommandContext ctx, bool help)
{
var result = await IsAllowed(ctx, help);
Config.Log.Debug($"Check for {GetType().Name} resulted in {result}");
Config.Log.Debug($"Check for {GetType().Name} and user {ctx.User.Username}#{ctx.User.Discriminator} ({ctx.User.Id}) resulted in {result}");
if (result)
{
if (ReactOnSuccess != null && !help)

View File

@ -304,15 +304,13 @@ namespace CompatBot.Commands
}
else if (txt != null)
{
var newStartTime = FixTimeString(txt.Content);
if (!DateTime.TryParse(newStartTime, out var newTime))
if (!TimeParser.TryParse(txt.Content, out var newTime))
{
errorMsg = $"Couldn't parse `{newStartTime}` as a start date and time";
errorMsg = $"Couldn't parse `{txt.Content}` as a start date and time";
goto step1;
}
var duration = evt.End - evt.Start;
newTime = Normalize(newTime);
evt.Start = newTime.Ticks;
evt.End = evt.Start + duration;
evt.Year = newTime.Year;
@ -487,25 +485,6 @@ namespace CompatBot.Commands
return score > 0.5 ? name : eventName;
}
private static string FixTimeString(string dateTime)
{
return dateTime.ToUpperInvariant()
.Replace("PST", "-08:00")
.Replace("EST", "-05:00")
.Replace("BST", "-03:00")
.Replace("JST", "+09:00")
.Replace("AEST", "+10:00");
}
private static DateTime Normalize(DateTime date)
{
if (date.Kind == DateTimeKind.Utc)
return date;
if (date.Kind == DateTimeKind.Local)
return date.ToUniversalTime();
return date.AsUtc();
}
private static async Task<TimeSpan?> TryParseTimeSpanAsync(CommandContext ctx, string duration, bool react = true)
{
var d = Duration.Match(duration);

View File

@ -87,7 +87,7 @@ namespace CompatBot.Commands
}
await ctx.Client.ReportAsync("👀 Message report", msg, new[] {ctx.Message.Author}, comment, ReportSeverity.Medium).ConfigureAwait(false);
await msg.ReactWithAsync(ctx.Client, Config.Reactions.Moderated).ConfigureAwait(false);
await msg.ReactWithAsync(Config.Reactions.Moderated).ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, "Message reported").ConfigureAwait(false);
}
}

View File

@ -91,7 +91,7 @@ namespace CompatBot.Commands
var prInfo = await githubClient.GetPrInfoAsync(pr, Config.Cts.Token).ConfigureAwait(false);
if (prInfo.Number == 0)
{
await message.ReactWithAsync(client, Config.Reactions.Failure, prInfo.Message ?? "PR not found").ConfigureAwait(false);
await message.ReactWithAsync(Config.Reactions.Failure, prInfo.Message ?? "PR not found").ConfigureAwait(false);
return;
}

View File

@ -85,7 +85,7 @@ namespace CompatBot.Commands
embed.ThumbnailUrl = "https://cdn.discordapp.com/attachments/417347469521715210/516340151589535745/onionoff.png";
}
var sqvat = ctx.Client.GetEmoji(":sqvat:", Config.Reactions.No);
await ctx.Message.ReactWithAsync(ctx.Client, sqvat).ConfigureAwait(false);
await ctx.Message.ReactWithAsync(sqvat).ConfigureAwait(false);
}
if (embeds.Count > 1 || embeds[0].Fields?.Count > 0)
embeds[embeds.Count - 1] = embeds.Last().WithFooter("Note that you need to install all listed updates one by one");

View File

@ -88,7 +88,7 @@ namespace CompatBot.Commands
else
de = DiscordEmoji.FromUnicode(emoji + c);
emoji = "";
await message.ReactWithAsync(ctx.Client, de).ConfigureAwait(false);
await message.ReactWithAsync(de).ConfigureAwait(false);
}
}
catch

View File

@ -28,7 +28,7 @@ namespace CompatBot.EventHandlers
if (matches.Count == 0)
return;
await args.Message.ReactWithAsync(args.Client, Config.Reactions.PleaseWait).ConfigureAwait(false);
await args.Message.ReactWithAsync(Config.Reactions.PleaseWait).ConfigureAwait(false);
try
{

View File

@ -131,7 +131,7 @@ namespace CompatBot.EventHandlers
emoji = ThankYouReactions[rng.Next(ThankYouReactions.Length)];
thankYouMessage = LimitedToSpamChannel.IsSpamChannel(args.Channel) ? ThankYouMessages[rng.Next(ThankYouMessages.Length)] : null;
}
await args.Message.ReactWithAsync(args.Client, emoji, thankYouMessage).ConfigureAwait(false);
await args.Message.ReactWithAsync(emoji, thankYouMessage).ConfigureAwait(false);
}
if (needToSilence)
{
@ -142,7 +142,7 @@ namespace CompatBot.EventHandlers
emoji = SadReactions[rng.Next(SadReactions.Length)];
sadMessage = SadMessages[rng.Next(SadMessages.Length)];
}
await args.Message.ReactWithAsync(args.Client, emoji, sadMessage).ConfigureAwait(false);
await args.Message.ReactWithAsync(emoji, sadMessage).ConfigureAwait(false);
if (args.Author.IsSmartlisted(args.Client, args.Message.Channel.Guild))
{
@ -154,7 +154,7 @@ namespace CompatBot.EventHandlers
await msg.DeleteAsync("asked to shut up").ConfigureAwait(false);
}
else
await args.Message.ReactWithAsync(args.Client, DiscordEmoji.FromUnicode("🙅"), @"No can do, boss ¯\\_(ツ)\_/¯").ConfigureAwait(false);
await args.Message.ReactWithAsync(DiscordEmoji.FromUnicode("🙅"), @"No can do, boss ¯\\_(ツ)\_/¯").ConfigureAwait(false);
}
}
}

View File

@ -111,9 +111,7 @@ namespace CompatBot.EventHandlers
{
Config.Log.Warn(e);
await client.ReportAsync("🛃 An unapproved discord invite", message, "In invalid or expired invite", null, ReportSeverity.Medium).ConfigureAwait(false);
await message.ReactWithAsync(
client,
Config.Reactions.Moderated,
await message.ReactWithAsync(Config.Reactions.Moderated,
$"{message.Author.Mention} please remove this expired or invalid invite, and refrain from posting it again until you have received an approval from a moderator.",
true
).ConfigureAwait(false);

View File

@ -59,7 +59,7 @@ namespace CompatBot.EventHandlers
public static async Task LookupAndPostProductCodeEmbedAsync(DiscordClient client, DiscordMessage message, List<string> codesToLookup)
{
await message.ReactWithAsync(client, Config.Reactions.PleaseWait).ConfigureAwait(false);
await message.ReactWithAsync(Config.Reactions.PleaseWait).ConfigureAwait(false);
try
{
var results = new List<(string code, Task<DiscordEmbedBuilder> task)>(codesToLookup.Count);
@ -149,7 +149,7 @@ namespace CompatBot.EventHandlers
titleInfoEmbed.Title = "How about no (๑•ิཬ•ั๑)";
if (!string.IsNullOrEmpty(titleInfoEmbed.ThumbnailUrl))
titleInfoEmbed.ThumbnailUrl = "https://cdn.discordapp.com/attachments/417347469521715210/516340151589535745/onionoff.png";
await message.ReactWithAsync(client, sqvat).ConfigureAwait(false);
await message.ReactWithAsync(sqvat).ConfigureAwait(false);
}
}
}

View File

@ -173,7 +173,7 @@ namespace CompatBot.EventHandlers
if (reporters.Count < Config.Moderation.StarbucksThreshold)
return;
await message.ReactWithAsync(client, emoji).ConfigureAwait(false);
await message.ReactWithAsync(emoji).ConfigureAwait(false);
await client.ReportAsync(Config.Reactions.Starbucks + " Media talk report", message, reporters, null, ReportSeverity.Medium).ConfigureAwait(false);
}
@ -193,24 +193,26 @@ namespace CompatBot.EventHandlers
}
private static async Task CheckGameFansAsync(DiscordClient client, DiscordChannel channel, DiscordMessage message)
private static Task CheckGameFansAsync(DiscordClient client, DiscordChannel channel, DiscordMessage message)
{
var bot = client.GetMember(channel.Guild, client.CurrentUser);
var ch = channel.IsPrivate ? channel.Users.FirstOrDefault(u => u.Id != client.CurrentUser.Id)?.Username + "'s DM" : "#" + channel.Name;
if (!channel.PermissionsFor(bot).HasPermission(Permissions.AddReactions))
{
Config.Log.Debug($"No permissions to react in #{channel.Name}");
return;
Config.Log.Debug($"No permissions to react in {ch}");
return Task.CompletedTask;
}
var mood = client.GetEmoji(":sqvat:", "😒");
if (message.Reactions.Any(r => r.Emoji == mood && r.IsMe))
return;
return Task.CompletedTask;
var reactionMsg = string.Concat(message.Reactions.Select(r => TextMap.TryGetValue(r.Emoji, out var txt) ? txt : " ")).Trim();
if (string.IsNullOrEmpty(reactionMsg))
return;
return Task.CompletedTask;
Config.Log.Debug("Emoji text: " + reactionMsg);
Config.Log.Debug($"Emoji text: {reactionMsg} (in {ch})");
return Task.CompletedTask;
}
}
}

View File

@ -66,7 +66,7 @@ namespace CompatBot.Utils
}
}
public static async Task ReactWithAsync(this DiscordMessage message, DiscordClient client, DiscordEmoji emoji, string fallbackMessage = null, bool? showBoth = null)
public static async Task ReactWithAsync(this DiscordMessage message, DiscordEmoji emoji, string fallbackMessage = null, bool? showBoth = null)
{
try
{
@ -90,7 +90,7 @@ namespace CompatBot.Utils
public static Task ReactWithAsync(this CommandContext ctx, DiscordEmoji emoji, string fallbackMessage = null, bool? showBoth = null)
{
return ReactWithAsync(ctx.Message, ctx.Client, emoji, fallbackMessage, showBoth ?? (ctx.Prefix == Config.AutoRemoveCommandPrefix));
return ReactWithAsync(ctx.Message, emoji, fallbackMessage, showBoth ?? (ctx.Prefix == Config.AutoRemoveCommandPrefix));
}
public static async Task<IReadOnlyCollection<DiscordMessage>> GetMessagesBeforeAsync(this DiscordChannel channel, ulong beforeMessageId, int limit = 100, DateTime? timeLimit = null)

View File

@ -33,7 +33,7 @@ namespace CompatBot.Utils
{
reactions = reactions.Where(r => r != null).ToArray();
foreach (var emoji in reactions)
await message.ReactWithAsync(interactivity.Client, emoji).ConfigureAwait(false);
await message.ReactWithAsync(emoji).ConfigureAwait(false);
var expectedChannel = message.Channel;
var waitTextResponseTask = interactivity.WaitForMessageAsync(m => m.Author == user && m.Channel == expectedChannel && !string.IsNullOrEmpty(m.Content), timeout);
var waitReactionResponse = interactivity.WaitForReactionAsync(arg => reactions.Contains(arg.Emoji), message, user, timeout);

View File

@ -388,7 +388,7 @@ namespace CompatBot.Utils.ResultFormatters
}
}
private static HashSet<string> DesIds = new HashSet<string>
private static readonly HashSet<string> DesIds = new HashSet<string>
{
"BLES00932", "BLUS30443", "BCJS30022", "BCJS70013",
"NPEB01202", "NPUB30910", "NPJA00102",

View File

@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Remotion.Linq.Clauses;
namespace CompatBot.Utils
{
public static class TimeParser
{
private static readonly Dictionary<string, TimeZoneInfo> TimeZoneMap;
static TimeParser()
{
var tzAcronyms = new Dictionary<string, string[]>
{
["PT"] = new[] { "Pacific Standard Time" },
["PST"] = new[] { "Pacific Standard Time" },
["PDT"] = new[] { "Pacific Standard Time" },
["EST"] = new[] { "Eastern Standard Time" },
["EDT"] = new[] { "Eastern Standard Time" },
["CEST"] = new[] { "Central European Standard Time" },
["BST"] = new[] { "British Summer Time", "GMT Standard Time" },
["JST"] = new[] { "Japan Standard Time", "Tokyo Standard Time" },
};
var uniqueNames = new HashSet<string>(
from tznl in tzAcronyms.Values
from tzn in tznl
select tzn
);
var tzList = TimeZoneInfo.GetSystemTimeZones();
var result = new Dictionary<string, TimeZoneInfo>();
foreach (var tzi in tzList)
{
if (uniqueNames.Contains(tzi.StandardName) || uniqueNames.Contains(tzi.StandardName))
{
var acronyms = from tza in tzAcronyms
where tza.Value.Contains(tzi.StandardName) || tza.Value.Contains(tzi.DaylightName)
select tza.Key;
foreach (var tza in acronyms)
result[tza] = tzi;
}
}
TimeZoneMap = result;
}
public static bool TryParse(string dateTime, out DateTime result)
{
result = default;
if (string.IsNullOrEmpty(dateTime))
return false;
dateTime = dateTime.ToUpperInvariant();
if (char.IsDigit(dateTime[dateTime.Length - 1]))
{
return DateTime.TryParse(dateTime, out result);
}
var cutIdx = dateTime.LastIndexOf(' ');
if (cutIdx < 0)
return false;
var tza = dateTime.Substring(cutIdx + 1);
dateTime = dateTime.Substring(0, cutIdx);
if (TimeZoneMap.TryGetValue(tza, out var tzi))
{
if (!DateTime.TryParse(dateTime, out result))
return false;
result = TimeZoneInfo.ConvertTimeToUtc(result, tzi);
return true;
}
return false;
}
public static DateTime Normalize(this DateTime date)
{
if (date.Kind == DateTimeKind.Utc)
return date;
if (date.Kind == DateTimeKind.Local)
return date.ToUniversalTime();
return date.AsUtc();
}
}
}

View File

@ -9,7 +9,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
</ItemGroup>
<ItemGroup>

20
Tests/TimeParserTests.cs Normal file
View File

@ -0,0 +1,20 @@
using System;
using CompatBot.Utils;
using NUnit.Framework;
namespace Tests
{
[TestFixture]
public class TimeParserTests
{
[TestCase("2019-8-19 6:00 PT", "2019-08-19 13:00")]
[TestCase("2019-8-19 17:00 bst", "2019-08-19 16:00")]
public void TimeZoneConverterTest(string input, string utcInput)
{
var utc = DateTime.Parse(utcInput).Normalize();
Assert.That(TimeParser.TryParse(input, out var result), Is.True);
Assert.That(result, Is.EqualTo(utc));
Assert.That(result.Kind, Is.EqualTo(DateTimeKind.Utc));
}
}
}