Split Geekbot.net into src/Bot, src/Core, and src/Web
This commit is contained in:
parent
7b6dd2d2f9
commit
fc0af492ad
197 changed files with 542 additions and 498 deletions
234
src/Bot/Commands/Admin/Admin.cs
Normal file
234
src/Bot/Commands/Admin/Admin.cs
Normal file
|
@ -0,0 +1,234 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.GuildSettingsManager;
|
||||
using Geekbot.Core.Localization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Admin
|
||||
{
|
||||
[Group("admin")]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
[DisableInDirectMessage]
|
||||
public class Admin : ModuleBase
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IGuildSettingsManager _guildSettingsManager;
|
||||
private readonly ITranslationHandler _translation;
|
||||
|
||||
public Admin(DiscordSocketClient client, IErrorHandler errorHandler, IGuildSettingsManager guildSettingsManager, ITranslationHandler translationHandler)
|
||||
{
|
||||
_client = client;
|
||||
_errorHandler = errorHandler;
|
||||
_guildSettingsManager = guildSettingsManager;
|
||||
_translation = translationHandler;
|
||||
}
|
||||
|
||||
[Command("welcome", RunMode = RunMode.Async)]
|
||||
[Summary("Set a Welcome Message (use '$user' to mention the new joined user).")]
|
||||
public async Task SetWelcomeMessage([Remainder, Summary("message")] string welcomeMessage)
|
||||
{
|
||||
var guild = _guildSettingsManager.GetSettings(Context.Guild.Id);
|
||||
guild.WelcomeMessage = welcomeMessage;
|
||||
await _guildSettingsManager.UpdateSettings(guild);
|
||||
|
||||
var formatedMessage = welcomeMessage.Replace("$user", Context.User.Mention);
|
||||
await ReplyAsync($"Welcome message has been changed\r\nHere is an example of how it would look:\r\n{formatedMessage}");
|
||||
}
|
||||
|
||||
[Command("welcomechannel", RunMode = RunMode.Async)]
|
||||
[Summary("Set a channel for the welcome messages (by default it uses the top most channel)")]
|
||||
public async Task SelectWelcomeChannel([Summary("#Channel")] ISocketMessageChannel channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
var m = await channel.SendMessageAsync("...");
|
||||
|
||||
var guild = _guildSettingsManager.GetSettings(Context.Guild.Id);
|
||||
guild.WelcomeChannel = channel.Id.AsLong();
|
||||
await _guildSettingsManager.UpdateSettings(guild);
|
||||
|
||||
await m.DeleteAsync();
|
||||
|
||||
await ReplyAsync("Successfully saved the welcome channel");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context, "That channel doesn't seem to exist or i don't have write permissions");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("modchannel", RunMode = RunMode.Async)]
|
||||
[Summary("Set a channel for moderation purposes")]
|
||||
public async Task SelectModChannel([Summary("#Channel")] ISocketMessageChannel channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
var m = await channel.SendMessageAsync("verifying...");
|
||||
|
||||
var guild = _guildSettingsManager.GetSettings(Context.Guild.Id);
|
||||
guild.ModChannel = channel.Id.AsLong();
|
||||
await _guildSettingsManager.UpdateSettings(guild);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Successfully saved mod channel, you can now do the following");
|
||||
sb.AppendLine("- `!admin showleave` - send message to mod channel when someone leaves");
|
||||
sb.AppendLine("- `!admin showdel` - send message to mod channel when someone deletes a message");
|
||||
await m.ModifyAsync(e => e.Content = sb.ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context, "That channel doesn't seem to exist or i don't have write permissions");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("showleave", RunMode = RunMode.Async)]
|
||||
[Summary("Toggle - notify modchannel when someone leaves")]
|
||||
public async Task ShowLeave()
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = _guildSettingsManager.GetSettings(Context.Guild.Id);
|
||||
var modChannel = await GetModChannel(guild.ModChannel.AsUlong());
|
||||
if (modChannel == null) return;
|
||||
|
||||
guild.ShowLeave = !guild.ShowLeave;
|
||||
await _guildSettingsManager.UpdateSettings(guild);
|
||||
await modChannel.SendMessageAsync(guild.ShowLeave
|
||||
? "Saved - now sending messages here when someone leaves"
|
||||
: "Saved - stopping sending messages here when someone leaves"
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("showdel", RunMode = RunMode.Async)]
|
||||
[Summary("Toggle - notify modchannel when someone deletes a message")]
|
||||
public async Task ShowDelete()
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = _guildSettingsManager.GetSettings(Context.Guild.Id);
|
||||
var modChannel = await GetModChannel(guild.ModChannel.AsUlong());
|
||||
if (modChannel == null) return;
|
||||
|
||||
guild.ShowDelete = !guild.ShowDelete;
|
||||
await _guildSettingsManager.UpdateSettings(guild);
|
||||
await modChannel.SendMessageAsync(guild.ShowDelete
|
||||
? "Saved - now sending messages here when someone deletes a message"
|
||||
: "Saved - stopping sending messages here when someone deletes a message"
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("setlang", RunMode = RunMode.Async)]
|
||||
[Summary("Change the bots language")]
|
||||
public async Task SetLanguage([Summary("language")] string languageRaw)
|
||||
{
|
||||
try
|
||||
{
|
||||
var language = languageRaw.ToUpper();
|
||||
var success = await _translation.SetLanguage(Context.Guild.Id, language);
|
||||
if (success)
|
||||
{
|
||||
var guild = _guildSettingsManager.GetSettings(Context.Guild.Id);
|
||||
guild.Language = language;
|
||||
await _guildSettingsManager.UpdateSettings(guild);
|
||||
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
await ReplyAsync(transContext.GetString("NewLanguageSet"));
|
||||
return;
|
||||
}
|
||||
|
||||
await ReplyAsync(
|
||||
$"That doesn't seem to be a supported language\r\nSupported Languages are {string.Join(", ", _translation.SupportedLanguages)}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("wiki", RunMode = RunMode.Async)]
|
||||
[Summary("Change the wikipedia instance (use lang code in xx.wikipedia.org)")]
|
||||
public async Task SetWikiLanguage([Summary("language")] string languageRaw)
|
||||
{
|
||||
try
|
||||
{
|
||||
var language = languageRaw.ToLower();
|
||||
var guild = _guildSettingsManager.GetSettings(Context.Guild.Id);
|
||||
guild.WikiLang = language;
|
||||
await _guildSettingsManager.UpdateSettings(guild);
|
||||
|
||||
await ReplyAsync($"Now using the {language} wikipedia");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("ping", RunMode = RunMode.Async)]
|
||||
[Summary("Enable the ping reply.")]
|
||||
public async Task TogglePing()
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = _guildSettingsManager.GetSettings(Context.Guild.Id);
|
||||
guild.Ping = !guild.Ping;
|
||||
await _guildSettingsManager.UpdateSettings(guild);
|
||||
await ReplyAsync(guild.Ping ? "i will reply to ping now" : "No more pongs...");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("hui", RunMode = RunMode.Async)]
|
||||
[Summary("Enable the ping reply.")]
|
||||
public async Task ToggleHui()
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = _guildSettingsManager.GetSettings(Context.Guild.Id);
|
||||
guild.Hui = !guild.Hui;
|
||||
await _guildSettingsManager.UpdateSettings(guild);
|
||||
await ReplyAsync(guild.Hui ? "i will reply to hui now" : "No more hui's...");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ISocketMessageChannel> GetModChannel(ulong channelId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (channelId == ulong.MinValue) throw new Exception();
|
||||
var modChannel = (ISocketMessageChannel) _client.GetChannel(channelId);
|
||||
if (modChannel == null) throw new Exception();
|
||||
return modChannel;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyAsync("Modchannel doesn't seem to exist, please set one with `!admin modchannel [channelId]`");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
38
src/Bot/Commands/Admin/Mod.cs
Normal file
38
src/Bot/Commands/Admin/Mod.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Admin
|
||||
{
|
||||
[Group("mod")]
|
||||
[RequireUserPermission(GuildPermission.KickMembers)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[DisableInDirectMessage]
|
||||
public class Mod : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Mod(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("namehistory", RunMode = RunMode.Async)]
|
||||
[Summary("See past usernames of an user")]
|
||||
public async Task UsernameHistory([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Context.Channel.SendMessageAsync("This command has been removed due to low usage and excessively high database usage");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
126
src/Bot/Commands/Admin/Owner/Owner.cs
Normal file
126
src/Bot/Commands/Admin/Owner/Owner.cs
Normal file
|
@ -0,0 +1,126 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.GlobalSettings;
|
||||
using Geekbot.Core.Logger;
|
||||
using Geekbot.Core.UserRepository;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Admin.Owner
|
||||
{
|
||||
[Group("owner")]
|
||||
[RequireOwner]
|
||||
public class Owner : ModuleBase
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
private readonly IGeekbotLogger _logger;
|
||||
private readonly IUserRepository _userRepository;
|
||||
|
||||
public Owner(DiscordSocketClient client, IGeekbotLogger logger, IUserRepository userRepositry, IErrorHandler errorHandler, IGlobalSettings globalSettings)
|
||||
{
|
||||
_client = client;
|
||||
_logger = logger;
|
||||
_userRepository = userRepositry;
|
||||
_errorHandler = errorHandler;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
[Command("youtubekey", RunMode = RunMode.Async)]
|
||||
[Summary("Set the youtube api key")]
|
||||
public async Task SetYoutubeKey([Summary("API-Key")] string key)
|
||||
{
|
||||
await _globalSettings.SetKey("YoutubeKey", key);
|
||||
await ReplyAsync("Apikey has been set");
|
||||
}
|
||||
|
||||
[Command("game", RunMode = RunMode.Async)]
|
||||
[Summary("Set the game that the bot is playing")]
|
||||
public async Task SetGame([Remainder] [Summary("Game")] string key)
|
||||
{
|
||||
await _globalSettings.SetKey("Game", key);
|
||||
await _client.SetGameAsync(key);
|
||||
_logger.Information(LogSource.Geekbot, $"Changed game to {key}");
|
||||
await ReplyAsync($"Now Playing {key}");
|
||||
}
|
||||
|
||||
[Command("popuserrepo", RunMode = RunMode.Async)]
|
||||
[Summary("Populate user cache")]
|
||||
public async Task PopUserRepoCommand()
|
||||
{
|
||||
var success = 0;
|
||||
var failed = 0;
|
||||
try
|
||||
{
|
||||
_logger.Warning(LogSource.UserRepository, "Populating User Repositry");
|
||||
await ReplyAsync("Starting Population of User Repository");
|
||||
foreach (var guild in _client.Guilds)
|
||||
{
|
||||
_logger.Information(LogSource.UserRepository, $"Populating users from {guild.Name}");
|
||||
foreach (var user in guild.Users)
|
||||
{
|
||||
var succeded = await _userRepository.Update(user);
|
||||
var inc = succeded ? success++ : failed++;
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Warning(LogSource.UserRepository, "Finished Updating User Repositry");
|
||||
await ReplyAsync(
|
||||
$"Successfully Populated User Repository with {success} Users in {_client.Guilds.Count} Guilds (Failed: {failed})");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context,
|
||||
"Couldn't complete User Repository, see console for more info");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("refreshuser", RunMode = RunMode.Async)]
|
||||
[Summary("Refresh a user in the user cache")]
|
||||
public async Task PopUserRepoCommand([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _userRepository.Update(user as SocketUser);
|
||||
await ReplyAsync($"Refreshed: {user.Username}#{user.Discriminator}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("refreshuser", RunMode = RunMode.Async)]
|
||||
[Summary("Refresh a user in the user cache")]
|
||||
public async Task PopUserRepoCommand([Summary("user-id")] ulong userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = _client.GetUser(userId);
|
||||
await _userRepository.Update(user);
|
||||
await ReplyAsync($"Refreshed: {user.Username}#{user.Discriminator}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("error", RunMode = RunMode.Async)]
|
||||
[Summary("Throw an error un purpose")]
|
||||
public async Task PurposefulError()
|
||||
{
|
||||
try
|
||||
{
|
||||
throw new Exception("Error Generated by !owner error");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
196
src/Bot/Commands/Admin/Role.cs
Normal file
196
src/Bot/Commands/Admin/Role.cs
Normal file
|
@ -0,0 +1,196 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Net;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.Database.Models;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.Localization;
|
||||
using Geekbot.Core.ReactionListener;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Admin
|
||||
{
|
||||
[Group("role")]
|
||||
[DisableInDirectMessage]
|
||||
public class Role : ModuleBase
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IReactionListener _reactionListener;
|
||||
private readonly ITranslationHandler _translationHandler;
|
||||
|
||||
public Role(DatabaseContext database, IErrorHandler errorHandler, IReactionListener reactionListener, ITranslationHandler translationHandler)
|
||||
{
|
||||
_database = database;
|
||||
_errorHandler = errorHandler;
|
||||
_reactionListener = reactionListener;
|
||||
_translationHandler = translationHandler;
|
||||
}
|
||||
|
||||
[Command(RunMode = RunMode.Async)]
|
||||
[Summary("Get a list of all available roles.")]
|
||||
public async Task GetAllRoles()
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
var roles = _database.RoleSelfService.Where(g => g.GuildId.Equals(Context.Guild.Id.AsLong())).ToList();
|
||||
if (roles.Count == 0)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("NoRolesConfigured"));
|
||||
return;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(transContext.GetString("ListHeader", Context.Guild.Name));
|
||||
sb.AppendLine(transContext.GetString("ListInstruction"));
|
||||
foreach (var role in roles) sb.AppendLine($"- {role.WhiteListName}");
|
||||
await ReplyAsync(sb.ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command(RunMode = RunMode.Async)]
|
||||
[Summary("Get a role by mentioning it.")]
|
||||
public async Task GiveRole([Summary("role-nickname")] string roleNameRaw)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
var roleName = roleNameRaw.ToLower();
|
||||
var roleFromDb = _database.RoleSelfService.FirstOrDefault(e =>
|
||||
e.GuildId.Equals(Context.Guild.Id.AsLong()) && e.WhiteListName.Equals(roleName));
|
||||
if (roleFromDb != null)
|
||||
{
|
||||
var guildUser = (IGuildUser) Context.User;
|
||||
var role = Context.Guild.Roles.First(r => r.Id == roleFromDb.RoleId.AsUlong());
|
||||
if (role == null)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("RoleNotFound"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (guildUser.RoleIds.Contains(role.Id))
|
||||
{
|
||||
await guildUser.RemoveRoleAsync(role);
|
||||
await ReplyAsync(transContext.GetString("RemovedUserFromRole", role.Name));
|
||||
return;
|
||||
}
|
||||
|
||||
await guildUser.AddRoleAsync(role);
|
||||
await ReplyAsync(transContext.GetString("AddedUserFromRole", role.Name));
|
||||
return;
|
||||
}
|
||||
|
||||
await ReplyAsync(transContext.GetString("RoleNotFound"));
|
||||
}
|
||||
catch (HttpException e)
|
||||
{
|
||||
await _errorHandler.HandleHttpException(e, Context);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[Command("add", RunMode = RunMode.Async)]
|
||||
[Summary("Add a role to the whitelist.")]
|
||||
public async Task AddRole([Summary("@role")] IRole role, [Summary("alias")] string roleName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
if (role.IsManaged)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotAddManagedRole"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (role.Permissions.ManageRoles
|
||||
|| role.Permissions.Administrator
|
||||
|| role.Permissions.ManageGuild
|
||||
|| role.Permissions.BanMembers
|
||||
|| role.Permissions.KickMembers)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotAddDangerousRole"));
|
||||
return;
|
||||
}
|
||||
|
||||
_database.RoleSelfService.Add(new RoleSelfServiceModel
|
||||
{
|
||||
GuildId = Context.Guild.Id.AsLong(),
|
||||
RoleId = role.Id.AsLong(),
|
||||
WhiteListName = roleName
|
||||
});
|
||||
await _database.SaveChangesAsync();
|
||||
await ReplyAsync(transContext.GetString("AddedRoleToWhitelist", role.Name));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[Command("remove", RunMode = RunMode.Async)]
|
||||
[Summary("Remove a role from the whitelist.")]
|
||||
public async Task RemoveRole([Summary("role-nickname")] string roleName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
var roleFromDb = _database.RoleSelfService.FirstOrDefault(e =>
|
||||
e.GuildId.Equals(Context.Guild.Id.AsLong()) && e.WhiteListName.Equals(roleName));
|
||||
if (roleFromDb != null)
|
||||
{
|
||||
_database.RoleSelfService.Remove(roleFromDb);
|
||||
await _database.SaveChangesAsync();
|
||||
await ReplyAsync(transContext.GetString("RemovedRoleFromWhitelist", roleName));
|
||||
return;
|
||||
}
|
||||
|
||||
await ReplyAsync(transContext.GetString("RoleNotFound"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[Summary("Give a role by clicking on an emoji")]
|
||||
[Command("listen", RunMode = RunMode.Async)]
|
||||
public async Task AddListener([Summary("message-ID")] string messageIdStr, [Summary("Emoji")] string emoji, [Summary("@role")] IRole role)
|
||||
{
|
||||
try
|
||||
{
|
||||
var messageId = ulong.Parse(messageIdStr);
|
||||
var message = (IUserMessage) await Context.Channel.GetMessageAsync(messageId);
|
||||
var emote = _reactionListener.ConvertStringToEmote(emoji);
|
||||
|
||||
await message.AddReactionAsync(emote);
|
||||
await _reactionListener.AddRoleToListener(messageId, Context.Guild.Id, emoji, role);
|
||||
await Context.Message.DeleteAsync();
|
||||
}
|
||||
catch (HttpException e)
|
||||
{
|
||||
await Context.Channel.SendMessageAsync("Custom emojis from other servers are not supported");
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
76
src/Bot/Commands/Games/Pokedex.cs
Normal file
76
src/Bot/Commands/Games/Pokedex.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using PokeAPI;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Games
|
||||
{
|
||||
public class Pokedex : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Pokedex(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("pokedex", RunMode = RunMode.Async)]
|
||||
[Summary("A Pokedex Tool")]
|
||||
public async Task GetPokemon([Summary("pokemon-name")] string pokemonName)
|
||||
{
|
||||
try
|
||||
{
|
||||
DataFetcher.ShouldCacheData = true;
|
||||
Pokemon pokemon;
|
||||
try
|
||||
{
|
||||
pokemon = await DataFetcher.GetNamedApiObject<Pokemon>(pokemonName.ToLower());
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyAsync("I couldn't find that pokemon :confused:");
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = await PokemonEmbedBuilder(pokemon);
|
||||
await ReplyAsync("", false, embed.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<EmbedBuilder> PokemonEmbedBuilder(Pokemon pokemon)
|
||||
{
|
||||
var eb = new EmbedBuilder();
|
||||
var species = await DataFetcher.GetApiObject<PokemonSpecies>(pokemon.ID);
|
||||
eb.Title = $"#{pokemon.ID} {ToUpper(pokemon.Name)}";
|
||||
eb.Description = species.FlavorTexts[1].FlavorText;
|
||||
eb.ThumbnailUrl = pokemon.Sprites.FrontMale ?? pokemon.Sprites.FrontFemale;
|
||||
eb.AddInlineField(GetSingularOrPlural(pokemon.Types.Length, "Type"),
|
||||
string.Join(", ", pokemon.Types.Select(t => ToUpper(t.Type.Name))));
|
||||
eb.AddInlineField(GetSingularOrPlural(pokemon.Abilities.Length, "Ability"),
|
||||
string.Join(", ", pokemon.Abilities.Select(t => ToUpper(t.Ability.Name))));
|
||||
eb.AddInlineField("Height", pokemon.Height);
|
||||
eb.AddInlineField("Weight", pokemon.Mass);
|
||||
return eb;
|
||||
}
|
||||
|
||||
private string GetSingularOrPlural(int lenght, string word)
|
||||
{
|
||||
if (lenght == 1) return word;
|
||||
return word.EndsWith("y") ? $"{word.Remove(word.Length - 1)}ies" : $"{word}s";
|
||||
}
|
||||
|
||||
private string ToUpper(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s)) return string.Empty;
|
||||
return char.ToUpper(s[0]) + s.Substring(1);
|
||||
}
|
||||
}
|
||||
}
|
98
src/Bot/Commands/Games/Roll/Roll.cs
Normal file
98
src/Bot/Commands/Games/Roll/Roll.cs
Normal file
|
@ -0,0 +1,98 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.Database.Models;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.KvInMemoryStore;
|
||||
using Geekbot.Core.Localization;
|
||||
using Geekbot.Core.RandomNumberGenerator;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Games.Roll
|
||||
{
|
||||
public class Roll : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IKvInMemoryStore _kvInMemoryStore;
|
||||
private readonly ITranslationHandler _translation;
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IRandomNumberGenerator _randomNumberGenerator;
|
||||
|
||||
public Roll(IKvInMemoryStore kvInMemoryStore,IErrorHandler errorHandler, ITranslationHandler translation, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator)
|
||||
{
|
||||
_kvInMemoryStore = kvInMemoryStore;
|
||||
_translation = translation;
|
||||
_database = database;
|
||||
_randomNumberGenerator = randomNumberGenerator;
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("roll", RunMode = RunMode.Async)]
|
||||
[Summary("Guess which number the bot will roll (1-100")]
|
||||
public async Task RollCommand([Remainder] [Summary("guess")] string stuff = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var number = _randomNumberGenerator.Next(1, 100);
|
||||
int.TryParse(stuff, out var guess);
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
if (guess <= 100 && guess > 0)
|
||||
{
|
||||
var kvKey = $"{Context.Guild.Id}:{Context.User.Id}:RollsPrevious";
|
||||
|
||||
var prevRoll = _kvInMemoryStore.Get<RollTimeout>(kvKey);
|
||||
|
||||
if (prevRoll?.LastGuess == guess && prevRoll?.GuessedOn.AddDays(1) > DateTime.Now)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString(
|
||||
"NoPrevGuess",
|
||||
Context.Message.Author.Mention,
|
||||
transContext.FormatDateTimeAsRemaining(prevRoll.GuessedOn.AddDays(1))));
|
||||
return;
|
||||
}
|
||||
|
||||
_kvInMemoryStore.Set(kvKey, new RollTimeout { LastGuess = guess, GuessedOn = DateTime.Now });
|
||||
|
||||
await ReplyAsync(transContext.GetString("Rolled", Context.Message.Author.Mention, number, guess));
|
||||
if (guess == number)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("Gratz", Context.Message.Author));
|
||||
var user = await GetUser(Context.User.Id);
|
||||
user.Rolls += 1;
|
||||
_database.Rolls.Update(user);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("RolledNoGuess", Context.Message.Author.Mention, number));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<RollsModel> GetUser(ulong userId)
|
||||
{
|
||||
var user = _database.Rolls.FirstOrDefault(u =>u.GuildId.Equals(Context.Guild.Id.AsLong()) && u.UserId.Equals(userId.AsLong())) ?? await CreateNewRow(userId);
|
||||
return user;
|
||||
}
|
||||
|
||||
private async Task<RollsModel> CreateNewRow(ulong userId)
|
||||
{
|
||||
var user = new RollsModel()
|
||||
{
|
||||
GuildId = Context.Guild.Id.AsLong(),
|
||||
UserId = userId.AsLong(),
|
||||
Rolls = 0
|
||||
};
|
||||
var newUser = _database.Rolls.Add(user).Entity;
|
||||
await _database.SaveChangesAsync();
|
||||
return newUser;
|
||||
}
|
||||
}
|
||||
}
|
10
src/Bot/Commands/Games/Roll/RollTimeout.cs
Normal file
10
src/Bot/Commands/Games/Roll/RollTimeout.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Games.Roll
|
||||
{
|
||||
public class RollTimeout
|
||||
{
|
||||
public int LastGuess { get; set; }
|
||||
public DateTime GuessedOn { get; set; }
|
||||
}
|
||||
}
|
61
src/Bot/Commands/Integrations/LolMmr/LolMmr.cs
Normal file
61
src/Bot/Commands/Integrations/LolMmr/LolMmr.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Integrations.LolMmr
|
||||
{
|
||||
public class LolMmr : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public LolMmr(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("mmr", RunMode = RunMode.Async)]
|
||||
[Summary("Get the League of Legends MMR for a specified summoner")]
|
||||
public async Task GetMmr([Remainder] [Summary("summoner")] string summonerName)
|
||||
{
|
||||
try
|
||||
{
|
||||
LolMmrDto data;
|
||||
try
|
||||
{
|
||||
var name = HttpUtility.UrlEncode(summonerName.ToLower());
|
||||
var httpClient = HttpAbstractions.CreateDefaultClient();
|
||||
// setting the user agent in accordance with the whatismymmr.com api rules
|
||||
httpClient.DefaultRequestHeaders.Remove("User-Agent");
|
||||
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Linux:rocks.pizzaandcoffee.geekbot:v0.0.0");
|
||||
data = await HttpAbstractions.Get<LolMmrDto>(new Uri($"https://euw.whatismymmr.com/api/v1/summoner?name={name}"), httpClient);
|
||||
}
|
||||
catch (HttpRequestException e)
|
||||
{
|
||||
if (e.StatusCode != HttpStatusCode.NotFound) throw e;
|
||||
|
||||
await Context.Channel.SendMessageAsync("Player not found");
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"**MMR for {summonerName}**");
|
||||
sb.AppendLine($"Normal: {data.Normal.Avg}");
|
||||
sb.AppendLine($"Ranked: {data.Ranked.Avg}");
|
||||
sb.AppendLine($"ARAM: {data.ARAM.Avg}");
|
||||
|
||||
await Context.Channel.SendMessageAsync(sb.ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
src/Bot/Commands/Integrations/LolMmr/LolMmrDto.cs
Normal file
9
src/Bot/Commands/Integrations/LolMmr/LolMmrDto.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Geekbot.Bot.Commands.Integrations.LolMmr
|
||||
{
|
||||
public class LolMmrDto
|
||||
{
|
||||
public LolMrrInfoDto Ranked { get; set; }
|
||||
public LolMrrInfoDto Normal { get; set; }
|
||||
public LolMrrInfoDto ARAM { get; set; }
|
||||
}
|
||||
}
|
10
src/Bot/Commands/Integrations/LolMmr/LolMrrInfoDto.cs
Normal file
10
src/Bot/Commands/Integrations/LolMmr/LolMrrInfoDto.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Integrations.LolMmr
|
||||
{
|
||||
public class LolMrrInfoDto
|
||||
{
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public decimal Avg { get; set; } = 0;
|
||||
}
|
||||
}
|
96
src/Bot/Commands/Integrations/MagicTheGathering.cs
Normal file
96
src/Bot/Commands/Integrations/MagicTheGathering.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.Converters;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using MtgApiManager.Lib.Service;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Integrations
|
||||
{
|
||||
public class MagicTheGathering : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IMtgManaConverter _manaConverter;
|
||||
|
||||
public MagicTheGathering(IErrorHandler errorHandler, IMtgManaConverter manaConverter)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_manaConverter = manaConverter;
|
||||
}
|
||||
|
||||
[Command("mtg", RunMode = RunMode.Async)]
|
||||
[Summary("Find a Magic The Gathering Card.")]
|
||||
public async Task GetCard([Remainder] [Summary("card-name")] string cardName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var message = await Context.Channel.SendMessageAsync($":mag: Looking up\"{cardName}\", please wait...");
|
||||
|
||||
var service = new CardService();
|
||||
var result = service
|
||||
.Where(x => x.Name, cardName)
|
||||
// fewer cards less risk of deserialization problems, don't need more than one anyways...
|
||||
.Where(x => x.PageSize, 1);
|
||||
|
||||
var card = result.All().Value.FirstOrDefault();
|
||||
if (card == null)
|
||||
{
|
||||
await message.ModifyAsync(properties => properties.Content = ":red_circle: I couldn't find a card with that name...");
|
||||
return;
|
||||
}
|
||||
|
||||
var eb = new EmbedBuilder
|
||||
{
|
||||
Title = card.Name,
|
||||
Description = card.Type
|
||||
};
|
||||
|
||||
if (card.Colors != null) eb.WithColor(GetColor(card.Colors));
|
||||
|
||||
if (card.ImageUrl != null) eb.ImageUrl = card.ImageUrl.ToString();
|
||||
|
||||
if (!string.IsNullOrEmpty(card.Text)) eb.AddField("Text", _manaConverter.ConvertMana(card.Text));
|
||||
|
||||
if (!string.IsNullOrEmpty(card.Flavor)) eb.AddField("Flavor", card.Flavor);
|
||||
if (!string.IsNullOrEmpty(card.SetName)) eb.AddInlineField("Set", card.SetName);
|
||||
if (!string.IsNullOrEmpty(card.Power)) eb.AddInlineField("Power", card.Power);
|
||||
if (!string.IsNullOrEmpty(card.Loyalty)) eb.AddInlineField("Loyality", card.Loyalty);
|
||||
if (!string.IsNullOrEmpty(card.Toughness)) eb.AddInlineField("Thoughness", card.Toughness);
|
||||
|
||||
if (!string.IsNullOrEmpty(card.ManaCost)) eb.AddInlineField("Cost", _manaConverter.ConvertMana(card.ManaCost));
|
||||
if (!string.IsNullOrEmpty(card.Rarity)) eb.AddInlineField("Rarity", card.Rarity);
|
||||
|
||||
if (card.Legalities != null && card.Legalities.Count > 0)
|
||||
eb.AddField("Legality", string.Join(", ", card.Legalities.Select(e => e.Format)));
|
||||
|
||||
await message.ModifyAsync(properties =>
|
||||
{
|
||||
properties.Content = string.Empty;
|
||||
properties.Embed = eb.Build();
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private Color GetColor(IEnumerable<string> colors)
|
||||
{
|
||||
var color = colors.FirstOrDefault();
|
||||
return color switch
|
||||
{
|
||||
"Black" => new Color(203, 194, 191),
|
||||
"White" => new Color(255, 251, 213),
|
||||
"Blue" => new Color(170, 224, 250),
|
||||
"Red" => new Color(250, 170, 143),
|
||||
"Green" => new Color(155, 211, 174),
|
||||
_ => new Color(204, 194, 212)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
128
src/Bot/Commands/Integrations/Mal.cs
Normal file
128
src/Bot/Commands/Integrations/Mal.cs
Normal file
|
@ -0,0 +1,128 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.MalClient;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Integrations
|
||||
{
|
||||
public class Mal : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IMalClient _malClient;
|
||||
|
||||
public Mal(IMalClient malClient, IErrorHandler errorHandler)
|
||||
{
|
||||
_malClient = malClient;
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("anime", RunMode = RunMode.Async)]
|
||||
[Summary("Show Info about an Anime.")]
|
||||
public async Task SearchAnime([Remainder] [Summary("anime-name")] string animeName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_malClient.IsLoggedIn())
|
||||
{
|
||||
var anime = await _malClient.GetAnime(animeName);
|
||||
if (anime != null)
|
||||
{
|
||||
var eb = new EmbedBuilder();
|
||||
|
||||
var description = HttpUtility.HtmlDecode(anime.Synopsis)
|
||||
.Replace("<br />", "")
|
||||
.Replace("[i]", "*")
|
||||
.Replace("[/i]", "*");
|
||||
|
||||
eb.Title = anime.Title;
|
||||
eb.Description = description;
|
||||
eb.ImageUrl = anime.Image;
|
||||
eb.AddInlineField("Premiered", $"{anime.StartDate}");
|
||||
eb.AddInlineField("Ended", anime.EndDate == "0000-00-00" ? "???" : anime.EndDate);
|
||||
eb.AddInlineField("Status", anime.Status);
|
||||
eb.AddInlineField("Episodes", anime.Episodes);
|
||||
eb.AddInlineField("MAL Score", anime.Score);
|
||||
eb.AddInlineField("Type", anime.Type);
|
||||
eb.AddField("MAL Link", $"https://myanimelist.net/anime/{anime.Id}");
|
||||
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync("No anime found with that name...");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync(
|
||||
"Unfortunally i'm not connected to MyAnimeList.net, please tell my senpai to connect me");
|
||||
}
|
||||
}
|
||||
catch (XmlException e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context, "The MyAnimeList.net API refused to answer");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("manga", RunMode = RunMode.Async)]
|
||||
[Summary("Show Info about a Manga.")]
|
||||
public async Task SearchManga([Remainder] [Summary("manga-name")] string mangaName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_malClient.IsLoggedIn())
|
||||
{
|
||||
var manga = await _malClient.GetManga(mangaName);
|
||||
if (manga != null)
|
||||
{
|
||||
var eb = new EmbedBuilder();
|
||||
|
||||
var description = HttpUtility.HtmlDecode(manga.Synopsis)
|
||||
.Replace("<br />", "")
|
||||
.Replace("[i]", "*")
|
||||
.Replace("[/i]", "*");
|
||||
|
||||
eb.Title = manga.Title;
|
||||
eb.Description = description;
|
||||
eb.ImageUrl = manga.Image;
|
||||
eb.AddInlineField("Premiered", $"{manga.StartDate}");
|
||||
eb.AddInlineField("Ended", manga.EndDate == "0000-00-00" ? "???" : manga.EndDate);
|
||||
eb.AddInlineField("Status", manga.Status);
|
||||
eb.AddInlineField("Volumes", manga.Volumes);
|
||||
eb.AddInlineField("Chapters", manga.Chapters);
|
||||
eb.AddInlineField("MAL Score", manga.Score);
|
||||
eb.AddField("MAL Link", $"https://myanimelist.net/manga/{manga.Id}");
|
||||
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync("No manga found with that name...");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync(
|
||||
"Unfortunally i'm not connected to MyAnimeList.net, please tell my senpai to connect me");
|
||||
}
|
||||
}
|
||||
catch (XmlException e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context, "The MyAnimeList.net API refused to answer");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
namespace Geekbot.Bot.Commands.Integrations.UbranDictionary
|
||||
{
|
||||
internal class UrbanListItemDto
|
||||
{
|
||||
public string Definition { get; set; }
|
||||
public string Permalink { get; set; }
|
||||
public string ThumbsUp { get; set; }
|
||||
public string Word { get; set; }
|
||||
public string Example { get; set; }
|
||||
public string ThumbsDown { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Integrations.UbranDictionary
|
||||
{
|
||||
internal class UrbanResponseDto
|
||||
{
|
||||
public string[] Tags { get; set; }
|
||||
public List<UrbanListItemDto> List { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Integrations.UbranDictionary
|
||||
{
|
||||
public class UrbanDictionary : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public UrbanDictionary(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("urban", RunMode = RunMode.Async)]
|
||||
[Summary("Lookup something on urban dictionary")]
|
||||
public async Task UrbanDefine([Remainder] [Summary("word")] string word)
|
||||
{
|
||||
try
|
||||
{
|
||||
var definitions = await HttpAbstractions.Get<UrbanResponseDto>(new Uri($"https://api.urbandictionary.com/v0/define?term={word}"));
|
||||
if (definitions.List.Count == 0)
|
||||
{
|
||||
await ReplyAsync("That word hasn't been defined...");
|
||||
return;
|
||||
}
|
||||
|
||||
var definition = definitions.List.First(e => !string.IsNullOrWhiteSpace(e.Example));
|
||||
|
||||
var description = definition.Definition;
|
||||
if (description.Length > 1801)
|
||||
{
|
||||
description = description.Substring(0, 1800) + " [...]";
|
||||
}
|
||||
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithAuthor(new EmbedAuthorBuilder
|
||||
{
|
||||
Name = definition.Word,
|
||||
Url = definition.Permalink
|
||||
});
|
||||
eb.WithColor(new Color(239, 255, 0));
|
||||
if (!string.IsNullOrEmpty(definition.Definition)) eb.Description = description;
|
||||
if (!string.IsNullOrEmpty(definition.Example)) eb.AddField("Example", definition.Example ?? "(no example given...)");
|
||||
if (!string.IsNullOrEmpty(definition.ThumbsUp)) eb.AddInlineField("Upvotes", definition.ThumbsUp);
|
||||
if (!string.IsNullOrEmpty(definition.ThumbsDown)) eb.AddInlineField("Downvotes", definition.ThumbsDown);
|
||||
if (definitions.Tags?.Length > 0) eb.AddField("Tags", string.Join(", ", definitions.Tags));
|
||||
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
112
src/Bot/Commands/Integrations/Wikipedia.cs
Normal file
112
src/Bot/Commands/Integrations/Wikipedia.cs
Normal file
|
@ -0,0 +1,112 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.WikipediaClient;
|
||||
using Geekbot.Core.WikipediaClient.Page;
|
||||
using HtmlAgilityPack;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Integrations
|
||||
{
|
||||
public class Wikipedia : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IWikipediaClient _wikipediaClient;
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
public Wikipedia(IErrorHandler errorHandler, IWikipediaClient wikipediaClient, DatabaseContext database)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_wikipediaClient = wikipediaClient;
|
||||
_database = database;
|
||||
}
|
||||
|
||||
[Command("wiki", RunMode = RunMode.Async)]
|
||||
[Summary("Get an article from wikipedia.")]
|
||||
public async Task GetPreview([Remainder] [Summary("article")] string articleName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var wikiLang = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(Context.Guild.Id.AsLong()))?.WikiLang;
|
||||
if (string.IsNullOrEmpty(wikiLang))
|
||||
{
|
||||
wikiLang = "en";
|
||||
}
|
||||
var article = await _wikipediaClient.GetPreview(articleName.Replace(" ", "_"), wikiLang);
|
||||
|
||||
if (article.Type != PageTypes.Standard)
|
||||
{
|
||||
switch (article.Type)
|
||||
{
|
||||
case PageTypes.Disambiguation:
|
||||
await ReplyAsync($"**__Disambiguation__**\r\n{DisambiguationExtractor(article.ExtractHtml)}");
|
||||
break;
|
||||
case PageTypes.MainPage:
|
||||
await ReplyAsync("The main page is not supported");
|
||||
break;
|
||||
case PageTypes.NoExtract:
|
||||
await ReplyAsync($"This page has no summary, here is the link: {article.ContentUrls.Desktop.Page}");
|
||||
break;
|
||||
case PageTypes.Standard:
|
||||
break;
|
||||
default:
|
||||
await ReplyAsync($"This page type is currently not supported, here is the link: {article.ContentUrls.Desktop.Page}");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var eb = new EmbedBuilder
|
||||
{
|
||||
Title = article.Title,
|
||||
Description = article.Description,
|
||||
ImageUrl = article.Thumbnail?.Source.ToString(),
|
||||
Url = article.ContentUrls.Desktop.Page.ToString(),
|
||||
Color = new Color(246,246,246),
|
||||
Timestamp = article.Timestamp,
|
||||
Footer = new EmbedFooterBuilder
|
||||
{
|
||||
Text = "Last Edit",
|
||||
IconUrl = "http://icons.iconarchive.com/icons/sykonist/popular-sites/256/Wikipedia-icon.png"
|
||||
}
|
||||
};
|
||||
|
||||
eb.AddField("Description", article.Extract);
|
||||
if (article.Coordinates != null) eb.AddField("Coordinates", $"{article.Coordinates.Lat} Lat {article.Coordinates.Lon} Lon");
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
await ReplyAsync("I couldn't find that article");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private string DisambiguationExtractor(string extractHtml)
|
||||
{
|
||||
var doc = new HtmlDocument();
|
||||
doc.LoadHtml(extractHtml);
|
||||
var nodes = doc.DocumentNode.SelectNodes("//li");
|
||||
if (nodes == null) return "(List is to long to show)";
|
||||
var sb = new StringBuilder();
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
var split = node.InnerText.Split(',');
|
||||
var title = split.First();
|
||||
var desc = string.Join(",", split.Skip(1));
|
||||
sb.AppendLine($"• **{title}** -{desc}");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
58
src/Bot/Commands/Integrations/Youtube.cs
Normal file
58
src/Bot/Commands/Integrations/Youtube.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.GlobalSettings;
|
||||
using Google.Apis.Services;
|
||||
using Google.Apis.YouTube.v3;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Integrations
|
||||
{
|
||||
public class Youtube : ModuleBase
|
||||
{
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Youtube(IGlobalSettings globalSettings, IErrorHandler errorHandler)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("yt", RunMode = RunMode.Async)]
|
||||
[Summary("Search for something on youtube.")]
|
||||
public async Task Yt([Remainder] [Summary("title")] string searchQuery)
|
||||
{
|
||||
var key = _globalSettings.GetKey("YoutubeKey");
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
await ReplyAsync("No youtube key set, please tell my senpai to set one");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var youtubeService = new YouTubeService(new BaseClientService.Initializer
|
||||
{
|
||||
ApiKey = key,
|
||||
ApplicationName = GetType().ToString()
|
||||
});
|
||||
|
||||
var searchListRequest = youtubeService.Search.List("snippet");
|
||||
searchListRequest.Q = searchQuery;
|
||||
searchListRequest.MaxResults = 2;
|
||||
|
||||
var searchListResponse = await searchListRequest.ExecuteAsync();
|
||||
|
||||
var result = searchListResponse.Items[0];
|
||||
|
||||
await ReplyAsync(
|
||||
$"\"{result.Snippet.Title}\" from \"{result.Snippet.ChannelTitle}\" https://youtu.be/{result.Id.VideoId}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.RandomNumberGenerator;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness
|
||||
{
|
||||
public class BenedictCumberbatchNameGenerator : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IRandomNumberGenerator _randomNumberGenerator;
|
||||
|
||||
public BenedictCumberbatchNameGenerator(IErrorHandler errorHandler, IRandomNumberGenerator randomNumberGenerator)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_randomNumberGenerator = randomNumberGenerator;
|
||||
}
|
||||
|
||||
[Command("bdcb", RunMode = RunMode.Async)]
|
||||
[Summary("Benedict Cumberbatch Name Generator")]
|
||||
public async Task GetQuote()
|
||||
{
|
||||
try
|
||||
{
|
||||
var firstnameList = new List<string>
|
||||
{
|
||||
"Bumblebee", "Bandersnatch", "Broccoli", "Rinkydink", "Bombadil", "Boilerdang", "Bandicoot", "Fragglerock", "Muffintop", "Congleton", "Blubberdick", "Buffalo", "Benadryl",
|
||||
"Butterfree", "Burberry", "Whippersnatch", "Buttermilk", "Beezlebub", "Budapest", "Boilerdang", "Blubberwhale", "Bumberstump", "Bulbasaur", "Cogglesnatch", "Liverswort",
|
||||
"Bodybuild", "Johnnycash", "Bendydick", "Burgerking", "Bonaparte", "Bunsenburner", "Billiardball", "Bukkake", "Baseballmitt", "Blubberbutt", "Baseballbat", "Rumblesack",
|
||||
"Barister", "Danglerack", "Rinkydink", "Bombadil", "Honkytonk", "Billyray", "Bumbleshack", "Snorkeldink", "Beetlejuice", "Bedlington", "Bandicoot", "Boobytrap", "Blenderdick",
|
||||
"Bentobox", "Pallettown", "Wimbledon", "Buttercup", "Blasphemy", "Syphilis", "Snorkeldink", "Brandenburg", "Barbituate", "Snozzlebert", "Tiddleywomp", "Bouillabaisse",
|
||||
"Wellington", "Benetton", "Bendandsnap", "Timothy", "Brewery", "Bentobox", "Brandybuck", "Benjamin", "Buckminster", "Bourgeoisie", "Bakery", "Oscarbait", "Buckyball",
|
||||
"Bourgeoisie", "Burlington", "Buckingham", "Barnoldswick", "Bumblesniff", "Butercup", "Bubblebath", "Fiddlestick", "Bulbasaur", "Bumblebee", "Bettyboop", "Botany", "Cadbury",
|
||||
"Brendadirk", "Buckingham", "Barnabus", "Barnacle", "Billybong", "Botany", "Benddadick", "Benderchick"
|
||||
};
|
||||
|
||||
var lastnameList = new List<string>
|
||||
{
|
||||
"Coddleswort", "Crumplesack", "Curdlesnoot", "Calldispatch", "Humperdinck", "Rivendell", "Cuttlefish", "Lingerie", "Vegemite", "Ampersand", "Cumberbund", "Candycrush",
|
||||
"Clombyclomp", "Cragglethatch", "Nottinghill", "Cabbagepatch", "Camouflage", "Creamsicle", "Curdlemilk", "Upperclass", "Frumblesnatch", "Crumplehorn", "Talisman", "Candlestick",
|
||||
"Chesterfield", "Bumbersplat", "Scratchnsniff", "Snugglesnatch", "Charizard", "Carrotstick", "Cumbercooch", "Crackerjack", "Crucifix", "Cuckatoo", "Cockletit", "Collywog",
|
||||
"Capncrunch", "Covergirl", "Cumbersnatch", "Countryside", "Coggleswort", "Splishnsplash", "Copperwire", "Animorph", "Curdledmilk", "Cheddarcheese", "Cottagecheese", "Crumplehorn",
|
||||
"Snickersbar", "Banglesnatch", "Stinkyrash", "Cameltoe", "Chickenbroth", "Concubine", "Candygram", "Moldyspore", "Chuckecheese", "Cankersore", "Crimpysnitch", "Wafflesmack",
|
||||
"Chowderpants", "Toodlesnoot", "Clavichord", "Cuckooclock", "Oxfordshire", "Cumbersome", "Chickenstrips", "Battleship", "Commonwealth", "Cunningsnatch", "Custardbath",
|
||||
"Kryptonite", "Curdlesnoot", "Cummerbund", "Coochyrash", "Crackerdong", "Crackerdong", "Curdledong", "Crackersprout", "Crumplebutt", "Colonist", "Coochierash", "Anglerfish",
|
||||
"Cumbersniff", "Charmander", "Scratch-n-sniff", "Cumberbitch", "Pumpkinpatch", "Cramplesnutch", "Lumberjack", "Bonaparte", "Cul-de-sac", "Cankersore", "Cucumbercatch", "Contradict"
|
||||
};
|
||||
|
||||
var lastname = lastnameList[_randomNumberGenerator.Next(0, lastnameList.Count - 1)];
|
||||
var firstname = firstnameList[_randomNumberGenerator.Next(0, firstnameList.Count - 1)];
|
||||
|
||||
await ReplyAsync($"{firstname} {lastname}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
38
src/Bot/Commands/Randomness/Cat/Cat.cs
Normal file
38
src/Bot/Commands/Randomness/Cat/Cat.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Cat
|
||||
{
|
||||
public class Cat : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Cat(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("cat", RunMode = RunMode.Async)]
|
||||
[Summary("Return a random image of a cat.")]
|
||||
public async Task Say()
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await HttpAbstractions.Get<CatResponseDto>(new Uri("https://aws.random.cat/meow"));
|
||||
var eb = new EmbedBuilder
|
||||
{
|
||||
ImageUrl = response.File
|
||||
};
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
src/Bot/Commands/Randomness/Cat/CatResponseDto.cs
Normal file
7
src/Bot/Commands/Randomness/Cat/CatResponseDto.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Geekbot.Bot.Commands.Randomness.Cat
|
||||
{
|
||||
internal class CatResponseDto
|
||||
{
|
||||
public string File { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace Geekbot.Bot.Commands.Randomness.Chuck
|
||||
{
|
||||
internal class ChuckNorrisJokeResponseDto
|
||||
{
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
41
src/Bot/Commands/Randomness/Chuck/ChuckNorrisJokes.cs
Normal file
41
src/Bot/Commands/Randomness/Chuck/ChuckNorrisJokes.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Chuck
|
||||
{
|
||||
public class ChuckNorrisJokes : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public ChuckNorrisJokes(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("chuck", RunMode = RunMode.Async)]
|
||||
[Summary("A random chuck norris joke")]
|
||||
public async Task Say()
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await HttpAbstractions.Get<ChuckNorrisJokeResponseDto>(new Uri("https://api.chucknorris.io/jokes/random"));
|
||||
await ReplyAsync(response.Value);
|
||||
}
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
await ReplyAsync("Api down...");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
src/Bot/Commands/Randomness/Dad/DadJokeResponseDto.cs
Normal file
7
src/Bot/Commands/Randomness/Dad/DadJokeResponseDto.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Geekbot.Bot.Commands.Randomness.Dad
|
||||
{
|
||||
internal class DadJokeResponseDto
|
||||
{
|
||||
public string Joke { get; set; }
|
||||
}
|
||||
}
|
33
src/Bot/Commands/Randomness/Dad/DadJokes.cs
Normal file
33
src/Bot/Commands/Randomness/Dad/DadJokes.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Dad
|
||||
{
|
||||
public class DadJokes : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public DadJokes(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("dad", RunMode = RunMode.Async)]
|
||||
[Summary("A random dad joke")]
|
||||
public async Task Say()
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await HttpAbstractions.Get<DadJokeResponseDto>(new Uri("https://icanhazdadjoke.com/"));
|
||||
await ReplyAsync(response.Joke);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
38
src/Bot/Commands/Randomness/Dog/Dog.cs
Normal file
38
src/Bot/Commands/Randomness/Dog/Dog.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Dog
|
||||
{
|
||||
public class Dog : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Dog(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("dog", RunMode = RunMode.Async)]
|
||||
[Summary("Return a random image of a dog.")]
|
||||
public async Task Say()
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await HttpAbstractions.Get<DogResponseDto>(new Uri("http://random.dog/woof.json"));
|
||||
var eb = new EmbedBuilder
|
||||
{
|
||||
ImageUrl = response.Url
|
||||
};
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
src/Bot/Commands/Randomness/Dog/DogResponseDto.cs
Normal file
7
src/Bot/Commands/Randomness/Dog/DogResponseDto.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Geekbot.Bot.Commands.Randomness.Dog
|
||||
{
|
||||
internal class DogResponseDto
|
||||
{
|
||||
public string Url { get; set; }
|
||||
}
|
||||
}
|
57
src/Bot/Commands/Randomness/EightBall.cs
Normal file
57
src/Bot/Commands/Randomness/EightBall.cs
Normal file
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness
|
||||
{
|
||||
public class EightBall : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public EightBall(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("8ball", RunMode = RunMode.Async)]
|
||||
[Summary("Ask 8Ball a Question.")]
|
||||
public async Task Ball([Remainder] [Summary("question")] string echo)
|
||||
{
|
||||
try
|
||||
{
|
||||
var replies = new List<string>
|
||||
{
|
||||
"It is certain",
|
||||
"It is decidedly so",
|
||||
"Without a doubt",
|
||||
"Yes, definitely",
|
||||
"You may rely on it",
|
||||
"As I see it, yes",
|
||||
"Most likely",
|
||||
"Outlook good",
|
||||
"Yes",
|
||||
"Signs point to yes",
|
||||
"Reply hazy try again",
|
||||
"Ask again later",
|
||||
"Better not tell you now",
|
||||
"Cannot predict now",
|
||||
"Concentrate and ask again",
|
||||
"Don't count on it",
|
||||
"My reply is no",
|
||||
"My sources say no",
|
||||
"Outlook not so good",
|
||||
"Very doubtful"
|
||||
};
|
||||
|
||||
var answer = new Random().Next(replies.Count);
|
||||
await ReplyAsync(replies[answer]);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
src/Bot/Commands/Randomness/Fortune.cs
Normal file
23
src/Bot/Commands/Randomness/Fortune.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.Media;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness
|
||||
{
|
||||
public class Fortune : ModuleBase
|
||||
{
|
||||
private readonly IFortunesProvider _fortunes;
|
||||
|
||||
public Fortune(IFortunesProvider fortunes)
|
||||
{
|
||||
_fortunes = fortunes;
|
||||
}
|
||||
|
||||
[Command("fortune", RunMode = RunMode.Async)]
|
||||
[Summary("Get a random fortune")]
|
||||
public async Task GetAFortune()
|
||||
{
|
||||
await ReplyAsync(_fortunes.GetRandomFortune());
|
||||
}
|
||||
}
|
||||
}
|
36
src/Bot/Commands/Randomness/Gdq.cs
Normal file
36
src/Bot/Commands/Randomness/Gdq.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness
|
||||
{
|
||||
public class Gdq : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Gdq(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("gdq", RunMode = RunMode.Async)]
|
||||
[Summary("Get a quote from the GDQ donation generator.")]
|
||||
public async Task GetQuote()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var client = new WebClient();
|
||||
var url = new Uri("http://taskinoz.com/gdq/api/");
|
||||
var response = client.DownloadString(url);
|
||||
|
||||
await ReplyAsync(response);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
src/Bot/Commands/Randomness/Greetings/GreetingBaseDto.cs
Normal file
11
src/Bot/Commands/Randomness/Greetings/GreetingBaseDto.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Geekbot.Bot.Commands.Randomness.Greetings
|
||||
{
|
||||
public class GreetingBaseDto
|
||||
{
|
||||
public string Language { get; set; }
|
||||
public string LanguageNative { get; set; }
|
||||
public string LanguageCode { get; set; }
|
||||
public string Script { get; set; }
|
||||
public GreetingDto Primary { get; set; }
|
||||
}
|
||||
}
|
10
src/Bot/Commands/Randomness/Greetings/GreetingDto.cs
Normal file
10
src/Bot/Commands/Randomness/Greetings/GreetingDto.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace Geekbot.Bot.Commands.Randomness.Greetings
|
||||
{
|
||||
public class GreetingDto
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public string Dialect { get; set; }
|
||||
public string Romanization { get; set; }
|
||||
public string[] Use { get; set; }
|
||||
}
|
||||
}
|
51
src/Bot/Commands/Randomness/Greetings/Greetings.cs
Normal file
51
src/Bot/Commands/Randomness/Greetings/Greetings.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Greetings
|
||||
{
|
||||
public class Greetings : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Greetings(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("hello", RunMode = RunMode.Async)]
|
||||
[Alias("greeting", "hi", "hallo")]
|
||||
[Summary("Say hello to the bot and get a reply in a random language")]
|
||||
public async Task GetGreeting()
|
||||
{
|
||||
try
|
||||
{
|
||||
var greeting = await HttpAbstractions.Get<GreetingBaseDto>(new Uri("https://api.greetings.dev/v1/greeting"));
|
||||
|
||||
var eb = new EmbedBuilder();
|
||||
eb.Title = greeting.Primary.Text;
|
||||
eb.AddInlineField("Language", greeting.Language);
|
||||
|
||||
if (greeting.Primary.Dialect != null)
|
||||
{
|
||||
eb.AddInlineField("Dialect", greeting.Primary.Dialect);
|
||||
}
|
||||
|
||||
if (greeting.Primary.Romanization != null)
|
||||
{
|
||||
eb.AddInlineField("Roman", greeting.Primary.Romanization);
|
||||
}
|
||||
|
||||
await ReplyAsync(string.Empty, false, eb.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
src/Bot/Commands/Randomness/Kanye/Kanye.cs
Normal file
33
src/Bot/Commands/Randomness/Kanye/Kanye.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Kanye
|
||||
{
|
||||
public class Kanye : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Kanye(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("kanye", RunMode = RunMode.Async)]
|
||||
[Summary("A random kayne west quote")]
|
||||
public async Task Say()
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await HttpAbstractions.Get<KanyeResponseDto>(new Uri("https://api.kanye.rest/"));
|
||||
await ReplyAsync(response.Quote);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
8
src/Bot/Commands/Randomness/Kanye/KanyeResponseDto.cs
Normal file
8
src/Bot/Commands/Randomness/Kanye/KanyeResponseDto.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Geekbot.Bot.Commands.Randomness.Kanye
|
||||
{
|
||||
public class KanyeResponseDto
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Quote { get; set; }
|
||||
}
|
||||
}
|
80
src/Bot/Commands/Randomness/RandomAnimals.cs
Normal file
80
src/Bot/Commands/Randomness/RandomAnimals.cs
Normal file
|
@ -0,0 +1,80 @@
|
|||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.Media;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness
|
||||
{
|
||||
public class RandomAnimals : ModuleBase
|
||||
{
|
||||
private readonly IMediaProvider _mediaProvider;
|
||||
|
||||
public RandomAnimals(IMediaProvider mediaProvider)
|
||||
{
|
||||
_mediaProvider = mediaProvider;
|
||||
}
|
||||
|
||||
[Command("panda", RunMode = RunMode.Async)]
|
||||
[Summary("Get a random panda image")]
|
||||
public async Task Panda()
|
||||
{
|
||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Panda)));
|
||||
}
|
||||
|
||||
[Command("croissant", RunMode = RunMode.Async)]
|
||||
[Alias("gipfeli")]
|
||||
[Summary("Get a random croissant image")]
|
||||
public async Task Croissant()
|
||||
{
|
||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Croissant)));
|
||||
}
|
||||
|
||||
[Command("pumpkin", RunMode = RunMode.Async)]
|
||||
[Summary("Get a random pumpkin image")]
|
||||
public async Task Pumpkin()
|
||||
{
|
||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Pumpkin)));
|
||||
}
|
||||
|
||||
[Command("squirrel", RunMode = RunMode.Async)]
|
||||
[Summary("Get a random squirrel image")]
|
||||
public async Task Squirrel()
|
||||
{
|
||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Squirrel)));
|
||||
}
|
||||
|
||||
[Command("turtle", RunMode = RunMode.Async)]
|
||||
[Summary("Get a random turtle image")]
|
||||
public async Task Turtle()
|
||||
{
|
||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Turtle)));
|
||||
}
|
||||
|
||||
[Command("penguin", RunMode = RunMode.Async)]
|
||||
[Alias("pengu")]
|
||||
[Summary("Get a random penguin image")]
|
||||
public async Task Penguin()
|
||||
{
|
||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Penguin)));
|
||||
}
|
||||
|
||||
[Command("fox", RunMode = RunMode.Async)]
|
||||
[Summary("Get a random fox image")]
|
||||
public async Task Fox()
|
||||
{
|
||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Fox)));
|
||||
}
|
||||
|
||||
[Command("dab", RunMode = RunMode.Async)]
|
||||
[Summary("Get a random dab image")]
|
||||
public async Task Dab()
|
||||
{
|
||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Dab)));
|
||||
}
|
||||
|
||||
private static Embed Eb(string image)
|
||||
{
|
||||
return new EmbedBuilder {ImageUrl = image}.Build();
|
||||
}
|
||||
}
|
||||
}
|
107
src/Bot/Commands/Randomness/Ship.cs
Normal file
107
src/Bot/Commands/Randomness/Ship.cs
Normal file
|
@ -0,0 +1,107 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.Database.Models;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.Localization;
|
||||
using Geekbot.Core.RandomNumberGenerator;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness
|
||||
{
|
||||
public class Ship : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IRandomNumberGenerator _randomNumberGenerator;
|
||||
private readonly ITranslationHandler _translation;
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
public Ship(DatabaseContext database, IErrorHandler errorHandler, IRandomNumberGenerator randomNumberGenerator, ITranslationHandler translation)
|
||||
{
|
||||
_database = database;
|
||||
_errorHandler = errorHandler;
|
||||
_randomNumberGenerator = randomNumberGenerator;
|
||||
_translation = translation;
|
||||
}
|
||||
|
||||
[Command("Ship", RunMode = RunMode.Async)]
|
||||
[Summary("Ask the Shipping meter")]
|
||||
public async Task Command([Summary("@user1")] IUser user1, [Summary("@user2")] IUser user2)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userKeys = user1.Id < user2.Id
|
||||
? new Tuple<long, long>(user1.Id.AsLong(), user2.Id.AsLong())
|
||||
: new Tuple<long, long>(user2.Id.AsLong(), user1.Id.AsLong());
|
||||
|
||||
var dbval = _database.Ships.FirstOrDefault(s =>
|
||||
s.FirstUserId.Equals(userKeys.Item1) &&
|
||||
s.SecondUserId.Equals(userKeys.Item2));
|
||||
|
||||
var shippingRate = 0;
|
||||
if (dbval == null)
|
||||
{
|
||||
shippingRate = _randomNumberGenerator.Next(1, 100);
|
||||
_database.Ships.Add(new ShipsModel()
|
||||
{
|
||||
FirstUserId = userKeys.Item1,
|
||||
SecondUserId = userKeys.Item2,
|
||||
Strength = shippingRate
|
||||
});
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
shippingRate = dbval.Strength;
|
||||
}
|
||||
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
|
||||
var reply = $":heartpulse: **{transContext.GetString("Matchmaking")}** :heartpulse:\r\n";
|
||||
reply += $":two_hearts: {user1.Mention} :heart: {user2.Mention} :two_hearts:\r\n";
|
||||
reply += $"0% [{BlockCounter(shippingRate)}] 100% - {DeterminateSuccess(shippingRate, transContext)}";
|
||||
await ReplyAsync(reply);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private string DeterminateSuccess(int rate, TranslationGuildContext transContext)
|
||||
{
|
||||
return (rate / 20) switch
|
||||
{
|
||||
0 => transContext.GetString("NotGonnaToHappen"),
|
||||
1 => transContext.GetString("NotSuchAGoodIdea"),
|
||||
2 => transContext.GetString("ThereMightBeAChance"),
|
||||
3 => transContext.GetString("CouldWork"),
|
||||
4 => transContext.GetString("ItsAMatch"),
|
||||
_ => "nope"
|
||||
};
|
||||
}
|
||||
|
||||
private string BlockCounter(int rate)
|
||||
{
|
||||
var amount = rate / 10;
|
||||
Console.WriteLine(amount);
|
||||
var blocks = "";
|
||||
for (var i = 1; i <= 10; i++)
|
||||
if (i <= amount)
|
||||
{
|
||||
blocks += ":white_medium_small_square:";
|
||||
if (i == amount)
|
||||
blocks += $" {rate}% ";
|
||||
}
|
||||
else
|
||||
{
|
||||
blocks += ":black_medium_small_square:";
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
}
|
||||
}
|
130
src/Bot/Commands/Randomness/Slap.cs
Normal file
130
src/Bot/Commands/Randomness/Slap.cs
Normal file
|
@ -0,0 +1,130 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.Database.Models;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness
|
||||
{
|
||||
public class Slap : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
public Slap(IErrorHandler errorHandler, DatabaseContext database)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_database = database;
|
||||
}
|
||||
|
||||
[Command("slap", RunMode = RunMode.Async)]
|
||||
[Summary("slap someone")]
|
||||
public async Task Slapper([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (user.Id == Context.User.Id)
|
||||
{
|
||||
await ReplyAsync("Why would you slap yourself?");
|
||||
return;
|
||||
}
|
||||
|
||||
var things = new List<string>
|
||||
{
|
||||
"thing",
|
||||
"rubber chicken",
|
||||
"leek stick",
|
||||
"large trout",
|
||||
"flat hand",
|
||||
"strip of bacon",
|
||||
"feather",
|
||||
"piece of pizza",
|
||||
"moldy banana",
|
||||
"sharp retort",
|
||||
"printed version of wikipedia",
|
||||
"panda paw",
|
||||
"spiked sledgehammer",
|
||||
"monstertruck",
|
||||
"dirty toilet brush",
|
||||
"sleeping seagull",
|
||||
"sunflower",
|
||||
"mousepad",
|
||||
"lolipop",
|
||||
"bottle of rum",
|
||||
"cheese slice",
|
||||
"critical 1",
|
||||
"natural 20",
|
||||
"mjölnir (aka mewmew)",
|
||||
"kamehameha",
|
||||
"copy of Twilight",
|
||||
"med pack (get ready for the end boss)",
|
||||
"derp",
|
||||
"condom (used)",
|
||||
"gremlin fed after midnight",
|
||||
"wet baguette",
|
||||
"exploding kitten",
|
||||
"shiny piece of shit",
|
||||
"mismatched pair of socks",
|
||||
"horcrux",
|
||||
"tuna",
|
||||
"suggestion",
|
||||
"teapot",
|
||||
"candle",
|
||||
"dictionary",
|
||||
"powerless banhammer"
|
||||
};
|
||||
|
||||
await ReplyAsync($"{Context.User.Username} slapped {user.Username} with a {things[new Random().Next(things.Count - 1)]}");
|
||||
|
||||
await UpdateRecieved(user.Id);
|
||||
await UpdateGiven(Context.User.Id);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateGiven(ulong userId)
|
||||
{
|
||||
var user = await GetUser(userId);
|
||||
user.Given++;
|
||||
_database.Slaps.Update(user);
|
||||
}
|
||||
|
||||
private async Task UpdateRecieved(ulong userId)
|
||||
{
|
||||
var user = await GetUser(userId);
|
||||
user.Recieved++;
|
||||
_database.Slaps.Update(user);
|
||||
}
|
||||
|
||||
private async Task<SlapsModel> GetUser(ulong userId)
|
||||
{
|
||||
var user = _database.Slaps.FirstOrDefault(e =>
|
||||
e.GuildId.Equals(Context.Guild.Id.AsLong()) &&
|
||||
e.UserId.Equals(userId.AsLong())
|
||||
);
|
||||
|
||||
if (user != null) return user;
|
||||
|
||||
_database.Slaps.Add(new SlapsModel
|
||||
{
|
||||
GuildId = Context.Guild.Id.AsLong(),
|
||||
UserId = userId.AsLong(),
|
||||
Recieved = 0,
|
||||
Given = 0
|
||||
});
|
||||
await _database.SaveChangesAsync();
|
||||
return _database.Slaps.FirstOrDefault(e =>
|
||||
e.GuildId.Equals(Context.Guild.Id.AsLong()) &&
|
||||
e.UserId.Equals(userId.AsLong()));
|
||||
}
|
||||
}
|
||||
}
|
161
src/Bot/Commands/Rpg/Cookies.cs
Normal file
161
src/Bot/Commands/Rpg/Cookies.cs
Normal file
|
@ -0,0 +1,161 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.Database.Models;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.Localization;
|
||||
using Geekbot.Core.RandomNumberGenerator;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Rpg
|
||||
{
|
||||
[DisableInDirectMessage]
|
||||
[Group("cookies")]
|
||||
[Alias("cookie")]
|
||||
public class Cookies : ModuleBase
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly ITranslationHandler _translation;
|
||||
private readonly IRandomNumberGenerator _randomNumberGenerator;
|
||||
|
||||
public Cookies(DatabaseContext database, IErrorHandler errorHandler, ITranslationHandler translation , IRandomNumberGenerator randomNumberGenerator)
|
||||
{
|
||||
_database = database;
|
||||
_errorHandler = errorHandler;
|
||||
_translation = translation;
|
||||
_randomNumberGenerator = randomNumberGenerator;
|
||||
}
|
||||
|
||||
[Command("get", RunMode = RunMode.Async)]
|
||||
[Summary("Get a cookie every 24 hours")]
|
||||
public async Task GetCookies()
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
var actor = await GetUser(Context.User.Id);
|
||||
if (actor.LastPayout.Value.AddDays(1).Date > DateTime.Now.Date)
|
||||
{
|
||||
var formatedWaitTime = transContext.FormatDateTimeAsRemaining(DateTimeOffset.Now.AddDays(1).Date);
|
||||
await ReplyAsync(transContext.GetString("WaitForMoreCookies", formatedWaitTime));
|
||||
return;
|
||||
}
|
||||
actor.Cookies += 10;
|
||||
actor.LastPayout = DateTimeOffset.Now;
|
||||
await SetUser(actor);
|
||||
await ReplyAsync(transContext.GetString("GetCookies", 10, actor.Cookies));
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("jar", RunMode = RunMode.Async)]
|
||||
[Summary("Look at your cookie jar")]
|
||||
public async Task PeekIntoCookieJar()
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
var actor = await GetUser(Context.User.Id);
|
||||
await ReplyAsync(transContext.GetString("InYourJar", actor.Cookies));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("give", RunMode = RunMode.Async)]
|
||||
[Summary("Give cookies to someone")]
|
||||
public async Task GiveACookie([Summary("@someone")] IUser user, [Summary("amount")] int amount = 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
var giver = await GetUser(Context.User.Id);
|
||||
|
||||
if (giver.Cookies < amount)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("NotEnoughToGive"));
|
||||
return;
|
||||
}
|
||||
|
||||
var taker = await GetUser(user.Id);
|
||||
|
||||
giver.Cookies -= amount;
|
||||
taker.Cookies += amount;
|
||||
|
||||
await SetUser(giver);
|
||||
await SetUser(taker);
|
||||
|
||||
await ReplyAsync(transContext.GetString("Given", amount, user.Username));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("eat", RunMode = RunMode.Async)]
|
||||
[Summary("Eat a cookie")]
|
||||
public async Task EatACookie()
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
var actor = await GetUser(Context.User.Id);
|
||||
|
||||
if (actor.Cookies < 5)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("NotEnoughCookiesToEat"));
|
||||
return;
|
||||
}
|
||||
|
||||
var amount = _randomNumberGenerator.Next(1, 5);
|
||||
actor.Cookies -= amount;
|
||||
|
||||
await SetUser(actor);
|
||||
|
||||
await ReplyAsync(transContext.GetString("AteCookies", amount, actor.Cookies));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<CookiesModel> GetUser(ulong userId)
|
||||
{
|
||||
var user = _database.Cookies.FirstOrDefault(u =>u.GuildId.Equals(Context.Guild.Id.AsLong()) && u.UserId.Equals(userId.AsLong())) ?? await CreateNewRow(userId);
|
||||
return user;
|
||||
}
|
||||
|
||||
private async Task SetUser(CookiesModel user)
|
||||
{
|
||||
_database.Cookies.Update(user);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task<CookiesModel> CreateNewRow(ulong userId)
|
||||
{
|
||||
var user = new CookiesModel()
|
||||
{
|
||||
GuildId = Context.Guild.Id.AsLong(),
|
||||
UserId = userId.AsLong(),
|
||||
Cookies = 0,
|
||||
LastPayout = DateTimeOffset.MinValue
|
||||
};
|
||||
var newUser = _database.Cookies.Add(user).Entity;
|
||||
await _database.SaveChangesAsync();
|
||||
return newUser;
|
||||
}
|
||||
}
|
||||
}
|
60
src/Bot/Commands/User/GuildInfo.cs
Normal file
60
src/Bot/Commands/User/GuildInfo.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.Levels;
|
||||
|
||||
namespace Geekbot.Bot.Commands.User
|
||||
{
|
||||
public class GuildInfo : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly ILevelCalc _levelCalc;
|
||||
|
||||
public GuildInfo(DatabaseContext database, ILevelCalc levelCalc, IErrorHandler errorHandler)
|
||||
{
|
||||
_database = database;
|
||||
_levelCalc = levelCalc;
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("serverstats", RunMode = RunMode.Async)]
|
||||
[Summary("Show some info about the bot.")]
|
||||
[DisableInDirectMessage]
|
||||
public async Task GetInfo()
|
||||
{
|
||||
try
|
||||
{
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithAuthor(new EmbedAuthorBuilder()
|
||||
.WithIconUrl(Context.Guild.IconUrl)
|
||||
.WithName(Context.Guild.Name));
|
||||
eb.WithColor(new Color(110, 204, 147));
|
||||
|
||||
var created = Context.Guild.CreatedAt;
|
||||
var age = Math.Floor((DateTime.Now - created).TotalDays);
|
||||
|
||||
var messages = _database.Messages
|
||||
.Where(e => e.GuildId == Context.Guild.Id.AsLong())
|
||||
.Sum(e => e.MessageCount);
|
||||
var level = _levelCalc.GetLevel(messages);
|
||||
|
||||
eb.AddField("Server Age", $"{created.Day}/{created.Month}/{created.Year} ({age} days)");
|
||||
eb.AddInlineField("Level", level)
|
||||
.AddInlineField("Messages", messages);
|
||||
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
153
src/Bot/Commands/User/Karma.cs
Normal file
153
src/Bot/Commands/User/Karma.cs
Normal file
|
@ -0,0 +1,153 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.Database.Models;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.Localization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.User
|
||||
{
|
||||
[DisableInDirectMessage]
|
||||
public class Karma : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly ITranslationHandler _translation;
|
||||
|
||||
public Karma(DatabaseContext database, IErrorHandler errorHandler, ITranslationHandler translation)
|
||||
{
|
||||
_database = database;
|
||||
_errorHandler = errorHandler;
|
||||
_translation = translation;
|
||||
}
|
||||
|
||||
[Command("good", RunMode = RunMode.Async)]
|
||||
[Summary("Increase Someones Karma")]
|
||||
public async Task Good([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
var actor = await GetUser(Context.User.Id);
|
||||
if (user.Id == Context.User.Id)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotChangeOwn", Context.User.Username));
|
||||
}
|
||||
else if (TimeoutFinished(actor.TimeOut))
|
||||
{
|
||||
var formatedWaitTime = transContext.FormatDateTimeAsRemaining(actor.TimeOut.AddMinutes(3));
|
||||
await ReplyAsync(transContext.GetString("WaitUntill", Context.User.Username, formatedWaitTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
var target = await GetUser(user.Id);
|
||||
target.Karma += 1;
|
||||
SetUser(target);
|
||||
|
||||
actor.TimeOut = DateTimeOffset.Now;
|
||||
SetUser(actor);
|
||||
|
||||
await _database.SaveChangesAsync();
|
||||
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithAuthor(new EmbedAuthorBuilder()
|
||||
.WithIconUrl(user.GetAvatarUrl())
|
||||
.WithName(user.Username));
|
||||
|
||||
eb.WithColor(new Color(138, 219, 146));
|
||||
eb.Title = transContext.GetString("Increased");
|
||||
eb.AddInlineField(transContext.GetString("By"), Context.User.Username);
|
||||
eb.AddInlineField(transContext.GetString("Amount"), "+1");
|
||||
eb.AddInlineField(transContext.GetString("Current"), target.Karma);
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("bad", RunMode = RunMode.Async)]
|
||||
[Summary("Decrease Someones Karma")]
|
||||
public async Task Bad([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
var actor = await GetUser(Context.User.Id);
|
||||
if (user.Id == Context.User.Id)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotChangeOwn", Context.User.Username));
|
||||
}
|
||||
else if (TimeoutFinished(actor.TimeOut))
|
||||
{
|
||||
var formatedWaitTime = transContext.FormatDateTimeAsRemaining(actor.TimeOut.AddMinutes(3));
|
||||
await ReplyAsync(transContext.GetString("WaitUntill", Context.User.Username, formatedWaitTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
var target = await GetUser(user.Id);
|
||||
target.Karma -= 1;
|
||||
SetUser(target);
|
||||
|
||||
actor.TimeOut = DateTimeOffset.Now;
|
||||
SetUser(actor);
|
||||
|
||||
await _database.SaveChangesAsync();
|
||||
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithAuthor(new EmbedAuthorBuilder()
|
||||
.WithIconUrl(user.GetAvatarUrl())
|
||||
.WithName(user.Username));
|
||||
|
||||
eb.WithColor(new Color(138, 219, 146));
|
||||
eb.Title = transContext.GetString("Decreased");
|
||||
eb.AddInlineField(transContext.GetString("By"), Context.User.Username);
|
||||
eb.AddInlineField(transContext.GetString("Amount"), "-1");
|
||||
eb.AddInlineField(transContext.GetString("Current"), target.Karma);
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TimeoutFinished(DateTimeOffset lastKarma)
|
||||
{
|
||||
return lastKarma.AddMinutes(3) > DateTimeOffset.Now;
|
||||
}
|
||||
|
||||
private async Task<KarmaModel> GetUser(ulong userId)
|
||||
{
|
||||
var user = _database.Karma.FirstOrDefault(u =>u.GuildId.Equals(Context.Guild.Id.AsLong()) && u.UserId.Equals(userId.AsLong())) ?? await CreateNewRow(userId);
|
||||
return user;
|
||||
}
|
||||
|
||||
private void SetUser(KarmaModel user)
|
||||
{
|
||||
_database.Karma.Update(user);
|
||||
}
|
||||
|
||||
private async Task<KarmaModel> CreateNewRow(ulong userId)
|
||||
{
|
||||
var user = new KarmaModel()
|
||||
{
|
||||
GuildId = Context.Guild.Id.AsLong(),
|
||||
UserId = userId.AsLong(),
|
||||
Karma = 0,
|
||||
TimeOut = DateTimeOffset.MinValue
|
||||
};
|
||||
var newUser = _database.Karma.Add(user).Entity;
|
||||
await _database.SaveChangesAsync();
|
||||
return newUser;
|
||||
}
|
||||
}
|
||||
}
|
116
src/Bot/Commands/User/Ranking/Rank.cs
Normal file
116
src/Bot/Commands/User/Ranking/Rank.cs
Normal file
|
@ -0,0 +1,116 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.Converters;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.Highscores;
|
||||
using Geekbot.Core.Localization;
|
||||
using Geekbot.Core.UserRepository;
|
||||
|
||||
namespace Geekbot.Bot.Commands.User.Ranking
|
||||
{
|
||||
public class Rank : ModuleBase
|
||||
{
|
||||
private readonly IEmojiConverter _emojiConverter;
|
||||
private readonly IHighscoreManager _highscoreManager;
|
||||
private readonly ITranslationHandler _translationHandler;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IUserRepository _userRepository;
|
||||
|
||||
public Rank(DatabaseContext database, IErrorHandler errorHandler, IUserRepository userRepository,
|
||||
IEmojiConverter emojiConverter, IHighscoreManager highscoreManager, ITranslationHandler translationHandler)
|
||||
{
|
||||
_database = database;
|
||||
_errorHandler = errorHandler;
|
||||
_userRepository = userRepository;
|
||||
_emojiConverter = emojiConverter;
|
||||
_highscoreManager = highscoreManager;
|
||||
_translationHandler = translationHandler;
|
||||
}
|
||||
|
||||
[Command("rank", RunMode = RunMode.Async)]
|
||||
[Summary("get user top 10 in messages or karma")]
|
||||
[DisableInDirectMessage]
|
||||
public async Task RankCmd([Summary("type")] string typeUnformated = "messages", [Summary("amount")] int amount = 10)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
HighscoreTypes type;
|
||||
try
|
||||
{
|
||||
type = Enum.Parse<HighscoreTypes>(typeUnformated, true);
|
||||
if (!Enum.IsDefined(typeof(HighscoreTypes), type)) throw new Exception();
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("InvalidType"));
|
||||
return;
|
||||
}
|
||||
|
||||
var replyBuilder = new StringBuilder();
|
||||
if (amount > 20)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("LimitingTo20Warning"));
|
||||
amount = 20;
|
||||
}
|
||||
|
||||
var guildId = Context.Guild.Id;
|
||||
Dictionary<HighscoreUserDto, int> highscoreUsers;
|
||||
try
|
||||
{
|
||||
highscoreUsers = _highscoreManager.GetHighscoresWithUserData(type, guildId, amount);
|
||||
}
|
||||
catch (HighscoreListEmptyException)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("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(transContext.GetString("FailedToResolveAllUsernames"));
|
||||
replyBuilder.AppendLine(transContext.GetString("HighscoresFor", type.ToString().CapitalizeFirst(), Context.Guild.Name));
|
||||
var highscorePlace = 1;
|
||||
foreach (var user in highscoreUsers)
|
||||
{
|
||||
replyBuilder.Append(highscorePlace < 11
|
||||
? $"{_emojiConverter.NumberToEmoji(highscorePlace)} "
|
||||
: $"`{highscorePlace}.` ");
|
||||
|
||||
replyBuilder.Append(user.Key.Username != null
|
||||
? $"**{user.Key.Username}#{user.Key.Discriminator}**"
|
||||
: $"**{user.Key.Id}**");
|
||||
|
||||
replyBuilder.Append(type == HighscoreTypes.messages
|
||||
? $" - {user.Value} {type} - {Math.Round((double) (100 * user.Value) / guildMessages, 2)}%\n"
|
||||
: $" - {user.Value} {type}\n");
|
||||
|
||||
highscorePlace++;
|
||||
}
|
||||
|
||||
await ReplyAsync(replyBuilder.ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
90
src/Bot/Commands/User/Stats.cs
Normal file
90
src/Bot/Commands/User/Stats.cs
Normal file
|
@ -0,0 +1,90 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.Levels;
|
||||
|
||||
namespace Geekbot.Bot.Commands.User
|
||||
{
|
||||
public class Stats : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly ILevelCalc _levelCalc;
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
public Stats(DatabaseContext database, IErrorHandler errorHandler, ILevelCalc levelCalc)
|
||||
{
|
||||
_database = database;
|
||||
_errorHandler = errorHandler;
|
||||
_levelCalc = levelCalc;
|
||||
}
|
||||
|
||||
[Command("stats", RunMode = RunMode.Async)]
|
||||
[Summary("Get information about this user")]
|
||||
[DisableInDirectMessage]
|
||||
public async Task User([Summary("@someone")] IUser user = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userInfo = user ?? Context.Message.Author;
|
||||
var userGuildInfo = (IGuildUser) userInfo;
|
||||
var createdAt = userInfo.CreatedAt;
|
||||
var joinedAt = userGuildInfo.JoinedAt.Value;
|
||||
var age = Math.Floor((DateTime.Now - createdAt).TotalDays);
|
||||
var joinedDayAgo = Math.Floor((DateTime.Now - joinedAt).TotalDays);
|
||||
|
||||
var messages = _database.Messages
|
||||
?.FirstOrDefault(e => e.GuildId.Equals(Context.Guild.Id.AsLong()) && e.UserId.Equals(userInfo.Id.AsLong()))
|
||||
?.MessageCount ?? 0;
|
||||
var guildMessages = _database.Messages
|
||||
?.Where(e => e.GuildId.Equals(Context.Guild.Id.AsLong()))
|
||||
.Select(e => e.MessageCount)
|
||||
.Sum() ?? 0;
|
||||
|
||||
var level = _levelCalc.GetLevel(messages);
|
||||
|
||||
var percent = Math.Round((double) (100 * messages) / guildMessages, 2);
|
||||
|
||||
var cookies = _database.Cookies
|
||||
?.FirstOrDefault(e => e.GuildId.Equals(Context.Guild.Id.AsLong()) && e.UserId.Equals(userInfo.Id.AsLong()))
|
||||
?.Cookies ?? 0;
|
||||
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithAuthor(new EmbedAuthorBuilder()
|
||||
.WithIconUrl(userInfo.GetAvatarUrl())
|
||||
.WithName(userInfo.Username));
|
||||
eb.WithColor(new Color(221, 255, 119));
|
||||
|
||||
var karma = _database.Karma.FirstOrDefault(e =>
|
||||
e.GuildId.Equals(Context.Guild.Id.AsLong()) &&
|
||||
e.UserId.Equals(userInfo.Id.AsLong()));
|
||||
var correctRolls = _database.Rolls.FirstOrDefault(e =>
|
||||
e.GuildId.Equals(Context.Guild.Id.AsLong()) &&
|
||||
e.UserId.Equals(userInfo.Id.AsLong()));
|
||||
|
||||
eb.AddInlineField("Discordian Since",
|
||||
$"{createdAt.Day}.{createdAt.Month}.{createdAt.Year} ({age} days)")
|
||||
.AddInlineField("Joined Server",
|
||||
$"{joinedAt.Day}.{joinedAt.Month}.{joinedAt.Year} ({joinedDayAgo} days)")
|
||||
.AddInlineField("Karma", karma?.Karma ?? 0)
|
||||
.AddInlineField("Level", level)
|
||||
.AddInlineField("Messages Sent", messages)
|
||||
.AddInlineField("Server Total", $"{percent}%");
|
||||
|
||||
if (correctRolls != null) eb.AddInlineField("Guessed Rolls", correctRolls.Rolls);
|
||||
if (cookies > 0) eb.AddInlineField("Cookies", cookies);
|
||||
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
src/Bot/Commands/Utils/AvatarGetter.cs
Normal file
34
src/Bot/Commands/Utils/AvatarGetter.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
public class AvatarGetter : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public AvatarGetter(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("avatar", RunMode = RunMode.Async)]
|
||||
[Summary("Get someones avatar")]
|
||||
public async Task GetAvatar([Remainder, Summary("@someone")] IUser user = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (user == null) user = Context.User;
|
||||
var url = user.GetAvatarUrl().Replace("128", "1024");
|
||||
await ReplyAsync(url);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
57
src/Bot/Commands/Utils/Changelog/Changelog.cs
Normal file
57
src/Bot/Commands/Utils/Changelog/Changelog.cs
Normal file
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils.Changelog
|
||||
{
|
||||
public class Changelog : ModuleBase
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Changelog(IErrorHandler errorHandler, DiscordSocketClient client)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
[Command("changelog", RunMode = RunMode.Async)]
|
||||
[Summary("Show the latest 10 updates")]
|
||||
public async Task GetChangelog()
|
||||
{
|
||||
try
|
||||
{
|
||||
var commits = await HttpAbstractions.Get<List<CommitDto>>(new Uri("https://api.github.com/repos/pizzaandcoffee/geekbot.net/commits"));
|
||||
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithColor(new Color(143, 165, 102));
|
||||
eb.WithAuthor(new EmbedAuthorBuilder
|
||||
{
|
||||
IconUrl = _client.CurrentUser.GetAvatarUrl(),
|
||||
Name = "Latest Updates",
|
||||
Url = "https://geekbot.pizzaandcoffee.rocks/updates"
|
||||
});
|
||||
var sb = new StringBuilder();
|
||||
foreach (var commit in commits.Take(10))
|
||||
sb.AppendLine($"- {commit.Commit.Message} ({commit.Commit.Author.Date:yyyy-MM-dd})");
|
||||
eb.Description = sb.ToString();
|
||||
eb.WithFooter(new EmbedFooterBuilder
|
||||
{
|
||||
Text = $"List generated from github commits on {DateTime.Now:yyyy-MM-dd}"
|
||||
});
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
src/Bot/Commands/Utils/Changelog/CommitAuthorDto.cs
Normal file
11
src/Bot/Commands/Utils/Changelog/CommitAuthorDto.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils.Changelog
|
||||
{
|
||||
public class CommitAuthorDto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Email { get; set; }
|
||||
public DateTimeOffset Date { get; set; }
|
||||
}
|
||||
}
|
7
src/Bot/Commands/Utils/Changelog/CommitDto.cs
Normal file
7
src/Bot/Commands/Utils/Changelog/CommitDto.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Geekbot.Bot.Commands.Utils.Changelog
|
||||
{
|
||||
public class CommitDto
|
||||
{
|
||||
public CommitInfoDto Commit { get; set; }
|
||||
}
|
||||
}
|
8
src/Bot/Commands/Utils/Changelog/CommitInfoDto.cs
Normal file
8
src/Bot/Commands/Utils/Changelog/CommitInfoDto.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Geekbot.Bot.Commands.Utils.Changelog
|
||||
{
|
||||
public class CommitInfoDto
|
||||
{
|
||||
public CommitAuthorDto Author { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
}
|
38
src/Bot/Commands/Utils/Choose.cs
Normal file
38
src/Bot/Commands/Utils/Choose.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Localization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
public class Choose : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly ITranslationHandler _translation;
|
||||
|
||||
public Choose(IErrorHandler errorHandler, ITranslationHandler translation)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_translation = translation;
|
||||
}
|
||||
|
||||
[Command("choose", RunMode = RunMode.Async)]
|
||||
[Summary("Let the bot choose for you, seperate options with a semicolon.")]
|
||||
public async Task Command([Remainder] [Summary("option1;option2")]
|
||||
string choices)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
var choicesArray = choices.Split(';');
|
||||
var choice = new Random().Next(choicesArray.Length);
|
||||
await ReplyAsync(transContext.GetString("Choice", choicesArray[choice].Trim()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
src/Bot/Commands/Utils/Corona/CoronaStats.cs
Normal file
66
src/Bot/Commands/Utils/Corona/CoronaStats.cs
Normal file
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils.Corona
|
||||
{
|
||||
public class CoronaStats : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public CoronaStats(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("corona", RunMode = RunMode.Async)]
|
||||
[Summary("Get the latest worldwide corona statistics")]
|
||||
public async Task Summary()
|
||||
{
|
||||
try
|
||||
{
|
||||
var summary = await HttpAbstractions.Get<CoronaSummaryDto>(new Uri("https://api.covid19api.com/world/total"));
|
||||
var activeCases = summary.TotalConfirmed - (summary.TotalRecovered + summary.TotalDeaths);
|
||||
|
||||
string CalculatePercentage(decimal i) => (i / summary.TotalConfirmed).ToString("#0.##%");
|
||||
var activePercent = CalculatePercentage(activeCases);
|
||||
var recoveredPercentage = CalculatePercentage(summary.TotalRecovered);
|
||||
var deathsPercentage = CalculatePercentage(summary.TotalDeaths);
|
||||
|
||||
var numberFormat = "#,#";
|
||||
var totalFormatted = summary.TotalConfirmed.ToString(numberFormat);
|
||||
var activeFormatted = activeCases.ToString(numberFormat);
|
||||
var recoveredFormatted = summary.TotalRecovered.ToString(numberFormat);
|
||||
var deathsFormatted = summary.TotalDeaths.ToString(numberFormat);
|
||||
|
||||
var eb = new EmbedBuilder
|
||||
{
|
||||
Author = new EmbedAuthorBuilder
|
||||
{
|
||||
Name = "Confirmed Corona Cases",
|
||||
IconUrl = "https://www.redcross.org/content/dam/icons/disasters/virus/Virus-1000x1000-R-Pl.png"
|
||||
},
|
||||
Footer = new EmbedFooterBuilder
|
||||
{
|
||||
Text = "Source: covid19api.com",
|
||||
},
|
||||
Color = Color.Red
|
||||
};
|
||||
eb.AddField("Total", totalFormatted);
|
||||
eb.AddInlineField("Active", $"{activeFormatted} ({activePercent})");
|
||||
eb.AddInlineField("Recovered", $"{recoveredFormatted} ({recoveredPercentage})");
|
||||
eb.AddInlineField("Deaths", $"{deathsFormatted} ({deathsPercentage})");
|
||||
|
||||
await Context.Channel.SendMessageAsync(String.Empty, false, eb.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
src/Bot/Commands/Utils/Corona/CoronaSummaryDto.cs
Normal file
9
src/Bot/Commands/Utils/Corona/CoronaSummaryDto.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Geekbot.Bot.Commands.Utils.Corona
|
||||
{
|
||||
public class CoronaSummaryDto
|
||||
{
|
||||
public decimal TotalConfirmed { get; set; }
|
||||
public decimal TotalDeaths { get; set; }
|
||||
public decimal TotalRecovered { get; set; }
|
||||
}
|
||||
}
|
107
src/Bot/Commands/Utils/Dice.cs
Normal file
107
src/Bot/Commands/Utils/Dice.cs
Normal file
|
@ -0,0 +1,107 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.DiceParser;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
public class Dice : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IDiceParser _diceParser;
|
||||
|
||||
public Dice(IErrorHandler errorHandler, IDiceParser diceParser)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_diceParser = diceParser;
|
||||
}
|
||||
|
||||
// ToDo: Separate representation and logic
|
||||
// ToDo: Translate
|
||||
[Command("dice", RunMode = RunMode.Async)]
|
||||
[Summary("Roll a dice. (use '!dice help' for a manual)")]
|
||||
public async Task RollCommand([Remainder] [Summary("input")] string diceInput = "1d20")
|
||||
{
|
||||
try
|
||||
{
|
||||
if (diceInput == "help")
|
||||
{
|
||||
await ShowDiceHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
var parsed = _diceParser.Parse(diceInput);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"{Context.User.Mention} :game_die:");
|
||||
foreach (var die in parsed.Dice)
|
||||
{
|
||||
sb.AppendLine($"**{die.DiceName}**");
|
||||
var diceResultList = new List<string>();
|
||||
var total = 0;
|
||||
|
||||
foreach (var roll in die.Roll())
|
||||
{
|
||||
diceResultList.Add(roll.ToString());
|
||||
total += roll.Result;
|
||||
}
|
||||
|
||||
sb.AppendLine(string.Join(" | ", diceResultList));
|
||||
|
||||
if (parsed.SkillModifier != 0)
|
||||
{
|
||||
sb.AppendLine($"Skill: {parsed.SkillModifier}");
|
||||
}
|
||||
|
||||
if (parsed.Options.ShowTotal)
|
||||
{
|
||||
var totalLine = $"Total: {total}";
|
||||
if (parsed.SkillModifier > 0)
|
||||
{
|
||||
totalLine += ($" (+{parsed.SkillModifier} = {total + parsed.SkillModifier})");
|
||||
}
|
||||
|
||||
if (parsed.SkillModifier < 0)
|
||||
{
|
||||
totalLine += ($" ({parsed.SkillModifier} = {total - parsed.SkillModifier})");
|
||||
}
|
||||
|
||||
sb.AppendLine(totalLine);
|
||||
}
|
||||
}
|
||||
|
||||
await Context.Channel.SendMessageAsync(sb.ToString());
|
||||
}
|
||||
catch (DiceException e)
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"**:warning: {e.DiceName} is invalid:** {e.Message}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ShowDiceHelp()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("**__Examples__**");
|
||||
sb.AppendLine("```");
|
||||
sb.AppendLine("!dice - throw a 1d20");
|
||||
sb.AppendLine("!dice 1d12 - throw a 1d12");
|
||||
sb.AppendLine("!dice +1d20 - throw with advantage");
|
||||
sb.AppendLine("!dice -1d20 - throw with disadvantage");
|
||||
sb.AppendLine("!dice 1d20 +2 - throw with a +2 skill bonus");
|
||||
sb.AppendLine("!dice 1d20 -2 - throw with a -2 skill bonus");
|
||||
sb.AppendLine("!dice 8d6 - throw a fireball 🔥");
|
||||
sb.AppendLine("!dice 8d6 total - calculate the total");
|
||||
sb.AppendLine("!dice 2d20 6d6 2d12 - drop your dice pouch");
|
||||
sb.AppendLine("```");
|
||||
|
||||
await Context.Channel.SendMessageAsync(sb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
42
src/Bot/Commands/Utils/Emojify.cs
Normal file
42
src/Bot/Commands/Utils/Emojify.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.Converters;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
public class Emojify : ModuleBase
|
||||
{
|
||||
private readonly IEmojiConverter _emojiConverter;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Emojify(IErrorHandler errorHandler, IEmojiConverter emojiConverter)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_emojiConverter = emojiConverter;
|
||||
}
|
||||
|
||||
[Command("emojify", RunMode = RunMode.Async)]
|
||||
[Summary("Emojify text")]
|
||||
public async Task Dflt([Remainder] [Summary("text")] string text)
|
||||
{
|
||||
try
|
||||
{
|
||||
var emojis = _emojiConverter.TextToEmoji(text);
|
||||
if (emojis.Length > 1999)
|
||||
{
|
||||
await ReplyAsync("I can't take that much at once!");
|
||||
return;
|
||||
}
|
||||
|
||||
await ReplyAsync($"{Context.User.Username}#{Context.User.Discriminator} said:");
|
||||
await ReplyAsync(emojis);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
39
src/Bot/Commands/Utils/Help.cs
Normal file
39
src/Bot/Commands/Utils/Help.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
public class Help : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Help(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("help", RunMode = RunMode.Async)]
|
||||
[Summary("List all Commands")]
|
||||
public async Task GetHelp()
|
||||
{
|
||||
try
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine("For a list of all commands, please visit the following page");
|
||||
sb.AppendLine("https://geekbot.pizzaandcoffee.rocks/commands");
|
||||
var dm = await Context.User.GetOrCreateDMChannelAsync();
|
||||
await dm.SendMessageAsync(sb.ToString());
|
||||
await Context.Message.AddReactionAsync(new Emoji("✅"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
73
src/Bot/Commands/Utils/Info.cs
Normal file
73
src/Bot/Commands/Utils/Info.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
public class Info : ModuleBase
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly CommandService _commands;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Info(IErrorHandler errorHandler, DiscordSocketClient client, CommandService commands)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_client = client;
|
||||
_commands = commands;
|
||||
}
|
||||
|
||||
[Command("info", RunMode = RunMode.Async)]
|
||||
[Summary("Get Information about the bot")]
|
||||
public async Task BotInfo()
|
||||
{
|
||||
try
|
||||
{
|
||||
var eb = new EmbedBuilder();
|
||||
|
||||
var appInfo = await _client.GetApplicationInfoAsync();
|
||||
|
||||
eb.WithAuthor(new EmbedAuthorBuilder()
|
||||
.WithIconUrl(appInfo.IconUrl)
|
||||
.WithName($"{Constants.Name} V{Constants.BotVersion()}"));
|
||||
var uptime = DateTime.Now.Subtract(Process.GetCurrentProcess().StartTime);
|
||||
|
||||
eb.AddInlineField("Bot Name", _client.CurrentUser.Username);
|
||||
eb.AddInlineField("Bot Owner", $"{appInfo.Owner.Username}#{appInfo.Owner.Discriminator}");
|
||||
eb.AddInlineField("Library", $"Discord.NET {Constants.LibraryVersion()}");
|
||||
eb.AddInlineField("Uptime", $"{uptime.Days}D {uptime.Hours}H {uptime.Minutes}M {uptime.Seconds}S");
|
||||
eb.AddInlineField("Servers", Context.Client.GetGuildsAsync().Result.Count);
|
||||
eb.AddInlineField("Total Commands", _commands.Commands.Count());
|
||||
eb.AddField("Website", "https://geekbot.pizzaandcoffee.rocks/");
|
||||
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("uptime", RunMode = RunMode.Async)]
|
||||
[Summary("Get the Bot Uptime")]
|
||||
public async Task BotUptime()
|
||||
{
|
||||
try
|
||||
{
|
||||
var uptime = DateTime.Now.Subtract(Process.GetCurrentProcess().StartTime);
|
||||
await ReplyAsync($"{uptime.Days}D {uptime.Hours}H {uptime.Minutes}M {uptime.Seconds}S");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
src/Bot/Commands/Utils/Lmgtfy.cs
Normal file
33
src/Bot/Commands/Utils/Lmgtfy.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
public class Lmgtfy : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Lmgtfy(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("lmgtfy", RunMode = RunMode.Async)]
|
||||
[Summary("Get a 'Let me google that for you' link")]
|
||||
public async Task GetUrl([Remainder] [Summary("question")] string question)
|
||||
{
|
||||
try
|
||||
{
|
||||
var encoded = HttpUtility.UrlEncode(question).Replace("%20", "+");
|
||||
await Context.Channel.SendMessageAsync($"<https://lmgtfy.com/?q={encoded}>");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
src/Bot/Commands/Utils/Ping.cs
Normal file
15
src/Bot/Commands/Utils/Ping.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
public class Ping : ModuleBase
|
||||
{
|
||||
[Command("👀", RunMode = RunMode.Async)]
|
||||
[Summary("Look at the bot.")]
|
||||
public async Task Eyes()
|
||||
{
|
||||
await ReplyAsync("S... Stop looking at me... baka!");
|
||||
}
|
||||
}
|
||||
}
|
313
src/Bot/Commands/Utils/Quote/Quote.cs
Normal file
313
src/Bot/Commands/Utils/Quote/Quote.cs
Normal file
|
@ -0,0 +1,313 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.Database.Models;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.Localization;
|
||||
using Geekbot.Core.Polyfills;
|
||||
using Geekbot.Core.RandomNumberGenerator;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils.Quote
|
||||
{
|
||||
[Group("quote")]
|
||||
[DisableInDirectMessage]
|
||||
public class Quote : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IRandomNumberGenerator _randomNumberGenerator;
|
||||
private readonly ITranslationHandler _translationHandler;
|
||||
|
||||
public Quote(IErrorHandler errorHandler, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator, ITranslationHandler translationHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_database = database;
|
||||
_randomNumberGenerator = randomNumberGenerator;
|
||||
_translationHandler = translationHandler;
|
||||
}
|
||||
|
||||
[Command]
|
||||
[Summary("Return a random quoute from the database")]
|
||||
public async Task GetRandomQuote()
|
||||
{
|
||||
try
|
||||
{
|
||||
var s = _database.Quotes.Where(e => e.GuildId.Equals(Context.Guild.Id.AsLong())).ToList();
|
||||
|
||||
if (!s.Any())
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
await ReplyAsync(transContext.GetString("NoQuotesFound"));
|
||||
return;
|
||||
}
|
||||
|
||||
var random = _randomNumberGenerator.Next(0, s.Count);
|
||||
var quote = s[random];
|
||||
|
||||
var embed = QuoteBuilder(quote);
|
||||
await ReplyAsync("", false, embed.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context, "Whoops, seems like the quote was to edgy to return");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("save")]
|
||||
[Summary("Save a quote from the last sent message by @user")]
|
||||
public async Task SaveQuote([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
if (user.Id == Context.Message.Author.Id)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotSaveOwnQuotes"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.IsBot)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotQuoteBots"));
|
||||
return;
|
||||
}
|
||||
|
||||
var lastMessage = await GetLastMessageByUser(user);
|
||||
if (lastMessage == null) return;
|
||||
|
||||
var quote = CreateQuoteObject(lastMessage);
|
||||
_database.Quotes.Add(quote);
|
||||
await _database.SaveChangesAsync();
|
||||
|
||||
var embed = QuoteBuilder(quote);
|
||||
await ReplyAsync(transContext.GetString("QuoteAdded"), false, embed.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context,
|
||||
"I counldn't find a quote from that user :disappointed:");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("save")]
|
||||
[Summary("Save a quote from a message id")]
|
||||
public async Task SaveQuote([Summary("message-ID")] ulong messageId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
var message = await Context.Channel.GetMessageAsync(messageId);
|
||||
if (message.Author.Id == Context.Message.Author.Id)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotSaveOwnQuotes"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.Author.IsBot)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotQuoteBots"));
|
||||
return;
|
||||
}
|
||||
|
||||
var quote = CreateQuoteObject(message);
|
||||
_database.Quotes.Add(quote);
|
||||
await _database.SaveChangesAsync();
|
||||
|
||||
var embed = QuoteBuilder(quote);
|
||||
await ReplyAsync(transContext.GetString("QuoteAdded"), false, embed.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context,
|
||||
"I couldn't find a message with that id :disappointed:");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("make")]
|
||||
[Summary("Create a quote from the last sent message by @user")]
|
||||
public async Task ReturnSpecifiedQuote([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var lastMessage = await GetLastMessageByUser(user);
|
||||
if (lastMessage == null) return;
|
||||
var quote = CreateQuoteObject(lastMessage);
|
||||
var embed = QuoteBuilder(quote);
|
||||
await ReplyAsync("", false, embed.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context,
|
||||
"I counldn't find a quote from that user :disappointed:");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("make")]
|
||||
[Summary("Create a quote from a message id")]
|
||||
public async Task ReturnSpecifiedQuote([Summary("message-ID")] ulong messageId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var message = await Context.Channel.GetMessageAsync(messageId);
|
||||
var quote = CreateQuoteObject(message);
|
||||
var embed = QuoteBuilder(quote);
|
||||
await ReplyAsync("", false, embed.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context,
|
||||
"I couldn't find a message with that id :disappointed:");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("remove")]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
[Summary("Remove a quote (user needs the 'ManageMessages' permission)")]
|
||||
public async Task RemoveQuote([Summary("quote-ID")] int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
var quote = _database.Quotes.Where(e => e.GuildId == Context.Guild.Id.AsLong() && e.InternalId == id)?.FirstOrDefault();
|
||||
if (quote != null)
|
||||
{
|
||||
_database.Quotes.Remove(quote);
|
||||
await _database.SaveChangesAsync();
|
||||
var embed = QuoteBuilder(quote);
|
||||
await ReplyAsync(transContext.GetString("Removed", id), false, embed.Build());
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("NotFoundWithId"));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context, "I couldn't find a quote with that id :disappointed:");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("stats")]
|
||||
[Summary("Show quote stats for this server")]
|
||||
public async Task GetQuoteStatsForServer()
|
||||
{
|
||||
try
|
||||
{
|
||||
// setup
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
var eb = new EmbedBuilder();
|
||||
eb.Author = new EmbedAuthorBuilder()
|
||||
{
|
||||
IconUrl = Context.Guild.IconUrl,
|
||||
Name = $"{Context.Guild.Name} - {transContext.GetString("QuoteStats")}"
|
||||
};
|
||||
|
||||
// gather data
|
||||
var totalQuotes = _database.Quotes.Count(row => row.GuildId == Context.Guild.Id.AsLong());
|
||||
if (totalQuotes == 0)
|
||||
{
|
||||
// no quotes, no stats, end of the road
|
||||
await ReplyAsync(transContext.GetString("NoQuotesFound"));
|
||||
return;
|
||||
}
|
||||
|
||||
var mostQuotedPerson = _database.Quotes
|
||||
.Where(row => row.GuildId == Context.Guild.Id.AsLong())
|
||||
.GroupBy(row => row.UserId)
|
||||
.Select(row => new { userId = row.Key, amount = row.Count()})
|
||||
.OrderBy(row => row.amount)
|
||||
.Last();
|
||||
var mostQuotedPersonUser = Context.Client.GetUserAsync(mostQuotedPerson.userId.AsUlong()).Result ?? new UserPolyfillDto {Username = "Unknown User"};
|
||||
|
||||
var quotesByYear = _database.Quotes
|
||||
.Where(row => row.GuildId == Context.Guild.Id.AsLong())
|
||||
.GroupBy(row => row.Time.Year)
|
||||
.Select(row => new { year = row.Key, amount = row.Count()})
|
||||
.OrderBy(row => row.year);
|
||||
|
||||
// add data to the embed
|
||||
eb.AddField(transContext.GetString("MostQuotesPerson"), $"{mostQuotedPersonUser.Username} ({mostQuotedPerson.amount})");
|
||||
eb.AddInlineField(transContext.GetString("TotalQuotes"), totalQuotes);
|
||||
|
||||
foreach (var year in quotesByYear)
|
||||
{
|
||||
eb.AddInlineField(year.year.ToString(), year.amount);
|
||||
}
|
||||
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IMessage> GetLastMessageByUser(IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var list = Context.Channel.GetMessagesAsync().Flatten();
|
||||
return await list.FirstOrDefaultAsync(msg =>
|
||||
msg.Author.Id == user.Id &&
|
||||
msg.Embeds.Count == 0 &&
|
||||
msg.Id != Context.Message.Id &&
|
||||
!msg.Content.ToLower().StartsWith("!"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyAsync($"No quoteable message have been sent by {user.Username} in this channel");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private EmbedBuilder QuoteBuilder(QuoteModel quote)
|
||||
{
|
||||
var user = Context.Client.GetUserAsync(quote.UserId.AsUlong()).Result ?? new UserPolyfillDto { Username = "Unknown User" };
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithColor(new Color(143, 167, 232));
|
||||
if (quote.InternalId == 0)
|
||||
{
|
||||
eb.Title = $"{user.Username} @ {quote.Time.Day}.{quote.Time.Month}.{quote.Time.Year}";
|
||||
}
|
||||
else
|
||||
{
|
||||
eb.Title = $"#{quote.InternalId} | {user.Username} @ {quote.Time.Day}.{quote.Time.Month}.{quote.Time.Year}";
|
||||
}
|
||||
eb.Description = quote.Quote;
|
||||
eb.ThumbnailUrl = user.GetAvatarUrl();
|
||||
if (quote.Image != null) eb.ImageUrl = quote.Image;
|
||||
return eb;
|
||||
}
|
||||
|
||||
private QuoteModel CreateQuoteObject(IMessage message)
|
||||
{
|
||||
string image;
|
||||
try
|
||||
{
|
||||
image = message.Attachments.First().Url;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
image = null;
|
||||
}
|
||||
|
||||
var last = _database.Quotes.Where(e => e.GuildId.Equals(Context.Guild.Id.AsLong())).OrderByDescending(e => e.InternalId).FirstOrDefault();
|
||||
var internalId = 0;
|
||||
if (last != null) internalId = last.InternalId + 1;
|
||||
return new QuoteModel()
|
||||
{
|
||||
InternalId = internalId,
|
||||
GuildId = Context.Guild.Id.AsLong(),
|
||||
UserId = message.Author.Id.AsLong(),
|
||||
Time = message.Timestamp.DateTime,
|
||||
Quote = message.Content,
|
||||
Image = image
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
12
src/Bot/Commands/Utils/Quote/QuoteObjectDto.cs
Normal file
12
src/Bot/Commands/Utils/Quote/QuoteObjectDto.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils.Quote
|
||||
{
|
||||
internal class QuoteObjectDto
|
||||
{
|
||||
public ulong UserId { get; set; }
|
||||
public string Quote { get; set; }
|
||||
public DateTime Time { get; set; }
|
||||
public string Image { get; set; }
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue