Port rank for slash commands

This commit is contained in:
Daan Boerlage 2021-10-31 23:21:15 +01:00
parent 772557978b
commit e20faa43e1
Signed by: daan
GPG key ID: FCE070E1E4956606
5 changed files with 225 additions and 86 deletions

View file

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using Geekbot.Core;
@ -9,10 +6,8 @@ using Geekbot.Core.CommandPreconditions;
using Geekbot.Core.Converters;
using Geekbot.Core.Database;
using Geekbot.Core.ErrorHandling;
using Geekbot.Core.Extensions;
using Geekbot.Core.GuildSettingsManager;
using Geekbot.Core.Highscores;
using Localization = Geekbot.Core.Localization;
namespace Geekbot.Bot.Commands.User.Ranking
{
@ -40,85 +35,9 @@ namespace Geekbot.Bot.Commands.User.Ranking
{
try
{
HighscoreTypes type;
try
{
type = Enum.Parse<HighscoreTypes>(typeUnformated, true);
if (!Enum.IsDefined(typeof(HighscoreTypes), type)) throw new Exception();
}
catch
{
await ReplyAsync(Localization.Rank.InvalidType);
return;
}
var replyBuilder = new StringBuilder();
if (amount > 20)
{
await ReplyAsync(Localization.Rank.LimitingTo20Warning);
amount = 20;
}
var guildId = Context.Guild.Id;
Dictionary<HighscoreUserDto, int> highscoreUsers;
try
{
highscoreUsers = _highscoreManager.GetHighscoresWithUserData(type, guildId, amount, season);
}
catch (HighscoreListEmptyException)
{
await ReplyAsync(string.Format(Localization.Rank.NoTypeFoundForServer, type));
return;
}
var guildMessages = 0;
if (type == HighscoreTypes.messages)
{
guildMessages = _database.Messages
.Where(e => e.GuildId.Equals(Context.Guild.Id.AsLong()))
.Select(e => e.MessageCount)
.Sum();
}
var failedToRetrieveUser = highscoreUsers.Any(e => string.IsNullOrEmpty(e.Key.Username));
if (failedToRetrieveUser) replyBuilder.AppendLine(Localization.Rank.FailedToResolveAllUsernames).AppendLine();
if (type == HighscoreTypes.seasons)
{
if (string.IsNullOrEmpty(season))
{
season = SeasonsUtils.GetCurrentSeason();
}
replyBuilder.AppendLine(string.Format(Localization.Rank.HighscoresFor, $"{type.ToString().CapitalizeFirst()} ({season})", Context.Guild.Name));
}
else
{
replyBuilder.AppendLine(string.Format(Localization.Rank.HighscoresFor, type.ToString().CapitalizeFirst(), Context.Guild.Name));
}
var highscorePlace = 1;
foreach (var (user, value) in highscoreUsers)
{
replyBuilder.Append(highscorePlace < 11
? $"{_emojiConverter.NumberToEmoji(highscorePlace)} "
: $"`{highscorePlace}.` ");
replyBuilder.Append(user.Username != null
? $"**{user.Username}#{user.Discriminator}**"
: $"**{user.Id}**");
replyBuilder.Append(type switch
{
HighscoreTypes.messages => $" - {value} {HighscoreTypes.messages} - {Math.Round((double) (100 * value) / guildMessages, 2)}%\n",
HighscoreTypes.seasons => $" - {value} {HighscoreTypes.messages}\n",
_ => $" - {value} {type}\n"
});
highscorePlace++;
}
await ReplyAsync(replyBuilder.ToString());
var res = new Geekbot.Commands.Rank(_database, _emojiConverter, _highscoreManager)
.Run(typeUnformated, amount, season, Context.Guild.Id, Context.Guild.Name);
await ReplyAsync(res);
}
catch (Exception e)
{

107
src/Commands/Rank.cs Normal file
View file

@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Geekbot.Core.Converters;
using Geekbot.Core.Database;
using Geekbot.Core.Extensions;
using Geekbot.Core.Highscores;
using Localization = Geekbot.Core.Localization;
namespace Geekbot.Commands
{
public class Rank
{
private readonly DatabaseContext _database;
private readonly IEmojiConverter _emojiConverter;
private readonly IHighscoreManager _highscoreManager;
public Rank(DatabaseContext database, IEmojiConverter emojiConverter, IHighscoreManager highscoreManager)
{
_database = database;
_emojiConverter = emojiConverter;
_highscoreManager = highscoreManager;
}
public string Run(string typeUnformated, int amount, string season, ulong guildId, string guildName)
{
HighscoreTypes type;
try
{
type = Enum.Parse<HighscoreTypes>(typeUnformated, true);
if (!Enum.IsDefined(typeof(HighscoreTypes), type)) throw new Exception();
}
catch
{
return Localization.Rank.InvalidType;
}
var replyBuilder = new StringBuilder();
if (amount > 20)
{
replyBuilder.AppendLine(Localization.Rank.LimitingTo20Warning);
amount = 20;
}
Dictionary<HighscoreUserDto, int> highscoreUsers;
try
{
highscoreUsers = _highscoreManager.GetHighscoresWithUserData(type, guildId, amount, season);
}
catch (HighscoreListEmptyException)
{
return string.Format(Core.Localization.Rank.NoTypeFoundForServer, type);
}
var guildMessages = 0;
if (type == HighscoreTypes.messages)
{
guildMessages = _database.Messages
.Where(e => e.GuildId.Equals(guildId.AsLong()))
.Select(e => e.MessageCount)
.Sum();
}
var failedToRetrieveUser = highscoreUsers.Any(e => string.IsNullOrEmpty(e.Key.Username));
if (failedToRetrieveUser) replyBuilder.AppendLine(Core.Localization.Rank.FailedToResolveAllUsernames).AppendLine();
if (type == HighscoreTypes.seasons)
{
if (string.IsNullOrEmpty(season))
{
season = SeasonsUtils.GetCurrentSeason();
}
replyBuilder.AppendLine(string.Format(Core.Localization.Rank.HighscoresFor, $"{type.ToString().CapitalizeFirst()} ({season})", guildName));
}
else
{
replyBuilder.AppendLine(string.Format(Core.Localization.Rank.HighscoresFor, type.ToString().CapitalizeFirst(), guildName));
}
var highscorePlace = 1;
foreach (var (user, value) in highscoreUsers)
{
replyBuilder.Append(highscorePlace < 11
? $"{_emojiConverter.NumberToEmoji(highscorePlace)} "
: $"`{highscorePlace}.` ");
replyBuilder.Append(user.Username != null
? $"**{user.Username}#{user.Discriminator}**"
: $"**{user.Id}**");
replyBuilder.Append(type switch
{
HighscoreTypes.messages => $" - {value} {HighscoreTypes.messages} - {Math.Round((double)(100 * value) / guildMessages, 2)}%\n",
HighscoreTypes.seasons => $" - {value} {HighscoreTypes.messages}\n",
_ => $" - {value} {type}\n"
});
highscorePlace++;
}
return replyBuilder.ToString();
}
}
}

View file

@ -13,5 +13,11 @@ namespace Geekbot.Core.Interactions.ApplicationCommand
/// </summary>
[JsonPropertyName("name")]
public string Name { get; set; }
/// <summary>
/// value of the choice, up to 100 characters if string
/// </summary>
[JsonPropertyName("value")]
public string Value { get; set; }
}
}

102
src/Web/Commands/Rank.cs Normal file
View file

@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Geekbot.Core.Converters;
using Geekbot.Core.Database;
using Geekbot.Core.Highscores;
using Geekbot.Core.Interactions;
using Geekbot.Core.Interactions.ApplicationCommand;
using Geekbot.Core.Interactions.Request;
using Geekbot.Core.Interactions.Response;
namespace Geekbot.Web.Commands
{
public class Rank : InteractionBase
{
private readonly DatabaseContext _database;
private readonly IEmojiConverter _emojiConverter;
private readonly IHighscoreManager _highscoreManager;
public Rank(DatabaseContext database, IEmojiConverter emojiConverter, IHighscoreManager highscoreManager)
{
_database = database;
_emojiConverter = emojiConverter;
_highscoreManager = highscoreManager;
}
private enum Options
{
Counter,
Amount,
Season
}
public override Command GetCommandInfo()
{
return new Command()
{
Name = "rank",
Description = "BETA: Highscores for various counters",
Type = CommandType.ChatInput,
Options = new List<Option>()
{
new ()
{
Name = Options.Counter.ToString().ToLower(),
Description = "The counter to show",
Required = true,
Type = OptionType.String,
Choices = Enumerable.Select(
Enum.GetNames<HighscoreTypes>(),
highscoreType => new OptionChoice()
{
Name = highscoreType,
Value = highscoreType
}).ToList()
},
new ()
{
Name = Options.Amount.ToString().ToLower(),
Description = "Amount of positions to show in the list",
Required = false,
Type = OptionType.Integer
},
new ()
{
Name = Options.Season.ToString().ToLower(),
Description = "Select the season, only applies for the seasons counter",
Required = false,
Type = OptionType.String
}
}
};
}
public override Task<InteractionResponse> Exec(Interaction interaction)
{
var counterTypeOption = interaction.Data.Options.Find(o => o.Name == Options.Counter.ToString().ToLower());
var amountOption = interaction.Data.Options.Find(o => o.Name == Options.Amount.ToString().ToLower());
var seasonOption = interaction.Data.Options.Find(o => o.Name == Options.Season.ToString().ToLower());
var res = new Geekbot.Commands.Rank(_database, _emojiConverter, _highscoreManager)
.Run(
counterTypeOption?.Value.GetString() ?? HighscoreTypes.messages.ToString(),
amountOption?.Value.GetInt32() ?? 10,
seasonOption?.Value.GetString() ?? string.Empty,
ulong.Parse(interaction.GuildId),
"...");
var interactionResponse = new InteractionResponse()
{
Type = InteractionResponseType.ChannelMessageWithSource,
Data = new InteractionResponseData()
{
Content = res
}
};
return Task.FromResult(interactionResponse);
}
}
}

View file

@ -22,6 +22,11 @@ namespace Geekbot.Web.Commands
_randomNumberGenerator = randomNumberGenerator;
}
private enum Options
{
Guess
}
public override Command GetCommandInfo()
{
return new Command()
@ -33,7 +38,7 @@ namespace Geekbot.Web.Commands
{
new Option()
{
Name = "guess",
Name = Options.Guess.ToString().ToLower(),
Description = "A number between 1 and 100 (inclusive)",
Required = true,
Type = OptionType.Integer
@ -44,7 +49,7 @@ namespace Geekbot.Web.Commands
public override async Task<InteractionResponse> Exec(Interaction interaction)
{
var guessOption = interaction.Data.Options.Find(o => o.Name == "guess");
var guessOption = interaction.Data.Options.Find(o => o.Name == Options.Guess.ToString().ToLower());
var guess = guessOption.Value.GetInt32();
var res = await new Geekbot.Commands.Roll.Roll(_kvInMemoryStore, _database, _randomNumberGenerator)