bot: finish tag setting command
This commit is contained in:
parent
b8065e2065
commit
b5d87290db
@ -68,7 +68,6 @@ namespace PluralKit.Bot
|
|||||||
.AddSingleton<MessageStore>()
|
.AddSingleton<MessageStore>()
|
||||||
.BuildServiceProvider();
|
.BuildServiceProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
class Bot
|
class Bot
|
||||||
{
|
{
|
||||||
private IServiceProvider _services;
|
private IServiceProvider _services;
|
||||||
@ -117,7 +116,14 @@ namespace PluralKit.Bot
|
|||||||
private async Task CommandExecuted(Optional<CommandInfo> cmd, ICommandContext ctx, IResult _result)
|
private async Task CommandExecuted(Optional<CommandInfo> cmd, ICommandContext ctx, IResult _result)
|
||||||
{
|
{
|
||||||
if (!_result.IsSuccess) {
|
if (!_result.IsSuccess) {
|
||||||
await ctx.Message.Channel.SendMessageAsync("\u274C " + _result.ErrorReason);
|
// If this is a PKError (ie. thrown deliberately), show user facing message
|
||||||
|
// If not, log as error
|
||||||
|
var pkError = (_result as ExecuteResult?)?.Exception as PKError;
|
||||||
|
if (pkError != null) {
|
||||||
|
await ctx.Message.Channel.SendMessageAsync("\u274C " + pkError.Message);
|
||||||
|
} else {
|
||||||
|
HandleRuntimeError(ctx.Message as SocketMessage, (_result as ExecuteResult?)?.Exception);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Dapper;
|
using Dapper;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
@ -13,67 +15,68 @@ namespace PluralKit.Bot.Commands
|
|||||||
public MemberStore Members {get; set;}
|
public MemberStore Members {get; set;}
|
||||||
public EmbedService EmbedService {get; set;}
|
public EmbedService EmbedService {get; set;}
|
||||||
|
|
||||||
private RuntimeResult NO_SYSTEM_ERROR => PKResult.Error($"You do not have a system registered with PluralKit. To create one, type `pk;system new`. If you already have a system registered on another account, type `pk;link {Context.User.Mention}` from that account to link it here.");
|
private PKError NO_SYSTEM_ERROR => new PKError($"You do not have a system registered with PluralKit. To create one, type `pk;system new`. If you already have a system registered on another account, type `pk;link {Context.User.Mention}` from that account to link it here.");
|
||||||
private RuntimeResult OTHER_SYSTEM_CONTEXT_ERROR => PKResult.Error("You can only run this command on your own system.");
|
private PKError OTHER_SYSTEM_CONTEXT_ERROR => new PKError("You can only run this command on your own system.");
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public async Task<RuntimeResult> Query(PKSystem system = null) {
|
public async Task Query(PKSystem system = null) {
|
||||||
if (system == null) system = Context.SenderSystem;
|
if (system == null) system = Context.SenderSystem;
|
||||||
if (system == null) return NO_SYSTEM_ERROR;
|
if (system == null) throw NO_SYSTEM_ERROR;
|
||||||
|
|
||||||
await Context.Channel.SendMessageAsync(embed: await EmbedService.CreateSystemEmbed(system));
|
await Context.Channel.SendMessageAsync(embed: await EmbedService.CreateSystemEmbed(system));
|
||||||
return PKResult.Success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("new")]
|
[Command("new")]
|
||||||
public async Task<RuntimeResult> New([Remainder] string systemName = null)
|
public async Task New([Remainder] string systemName = null)
|
||||||
{
|
{
|
||||||
if (ContextEntity != null) return OTHER_SYSTEM_CONTEXT_ERROR;
|
if (ContextEntity != null) throw OTHER_SYSTEM_CONTEXT_ERROR;
|
||||||
if (Context.SenderSystem != null) return PKResult.Error("You already have a system registered with PluralKit. To view it, type `pk;system`. If you'd like to delete your system and start anew, type `pk;system delete`, or if you'd like to unlink this account from it, type `pk;unlink.");
|
if (Context.SenderSystem != null) throw new PKError("You already have a system registered with PluralKit. To view it, type `pk;system`. If you'd like to delete your system and start anew, type `pk;system delete`, or if you'd like to unlink this account from it, type `pk;unlink.");
|
||||||
|
|
||||||
var system = await Systems.Create(systemName);
|
var system = await Systems.Create(systemName);
|
||||||
await Systems.Link(system, Context.User.Id);
|
await Systems.Link(system, Context.User.Id);
|
||||||
|
|
||||||
await ReplyAsync("Your system has been created. Type `pk;system` to view it, and type `pk;help` for more information about commands you can use now.");
|
await ReplyAsync("Your system has been created. Type `pk;system` to view it, and type `pk;help` for more information about commands you can use now.");
|
||||||
return PKResult.Success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("name")]
|
[Command("name")]
|
||||||
public async Task<RuntimeResult> Name([Remainder] string newSystemName = null) {
|
public async Task Name([Remainder] string newSystemName = null) {
|
||||||
if (ContextEntity != null) return OTHER_SYSTEM_CONTEXT_ERROR;
|
if (ContextEntity != null) throw OTHER_SYSTEM_CONTEXT_ERROR;
|
||||||
if (Context.SenderSystem == null) return NO_SYSTEM_ERROR;
|
if (Context.SenderSystem == null) throw NO_SYSTEM_ERROR;
|
||||||
if (newSystemName != null && newSystemName.Length > 250) return PKResult.Error($"Your chosen system name is too long. ({newSystemName.Length} > 250 characters)");
|
if (newSystemName != null && newSystemName.Length > 250) throw new PKError($"Your chosen system name is too long. ({newSystemName.Length} > 250 characters)");
|
||||||
|
|
||||||
Context.SenderSystem.Name = newSystemName;
|
Context.SenderSystem.Name = newSystemName;
|
||||||
await Systems.Save(Context.SenderSystem);
|
await Systems.Save(Context.SenderSystem);
|
||||||
return PKResult.Success();
|
await Context.Channel.SendMessageAsync($"{Emojis.Success} System name {(newSystemName != null ? "changed" : "cleared")}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("description")]
|
[Command("description")]
|
||||||
public async Task<RuntimeResult> Description([Remainder] string newDescription = null) {
|
public async Task Description([Remainder] string newDescription = null) {
|
||||||
if (ContextEntity != null) return OTHER_SYSTEM_CONTEXT_ERROR;
|
if (ContextEntity != null) throw OTHER_SYSTEM_CONTEXT_ERROR;
|
||||||
if (Context.SenderSystem == null) return NO_SYSTEM_ERROR;
|
if (Context.SenderSystem == null) throw NO_SYSTEM_ERROR;
|
||||||
if (newDescription != null && newDescription.Length > 1000) return PKResult.Error($"Your chosen description is too long. ({newDescription.Length} > 250 characters)");
|
if (newDescription != null && newDescription.Length > 1000) throw new PKError($"Your chosen description is too long. ({newDescription.Length} > 250 characters)");
|
||||||
|
|
||||||
Context.SenderSystem.Description = newDescription;
|
Context.SenderSystem.Description = newDescription;
|
||||||
await Systems.Save(Context.SenderSystem);
|
await Systems.Save(Context.SenderSystem);
|
||||||
return PKResult.Success("uwu");
|
await Context.Channel.SendMessageAsync($"{Emojis.Success} System description {(newDescription != null ? "changed" : "cleared")}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("tag")]
|
[Command("tag")]
|
||||||
public async Task<RuntimeResult> Tag([Remainder] string newTag = null) {
|
public async Task Tag([Remainder] string newTag = null) {
|
||||||
if (ContextEntity != null) return OTHER_SYSTEM_CONTEXT_ERROR;
|
if (ContextEntity != null) throw OTHER_SYSTEM_CONTEXT_ERROR;
|
||||||
if (Context.SenderSystem == null) return NO_SYSTEM_ERROR;
|
if (Context.SenderSystem == null) throw NO_SYSTEM_ERROR;
|
||||||
|
if (newTag.Length > 30) throw new PKError($"Your chosen description is too long. ({newTag.Length} > 30 characters)");
|
||||||
|
|
||||||
Context.SenderSystem.Tag = newTag;
|
Context.SenderSystem.Tag = newTag;
|
||||||
|
|
||||||
|
// Check unproxyable messages *after* changing the tag (so it's seen in the method) but *before* we save to DB (so we can cancel)
|
||||||
var unproxyableMembers = await Members.GetUnproxyableMembers(Context.SenderSystem);
|
var unproxyableMembers = await Members.GetUnproxyableMembers(Context.SenderSystem);
|
||||||
//if (unproxyableMembers.Count > 0) {
|
if (unproxyableMembers.Count > 0) {
|
||||||
throw new Exception("sdjsdflsdf");
|
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} Changing your system tag to '{newTag}' will result in the following members being unproxyable, since the tag would bring their name over 32 characters:\n**{string.Join(", ", unproxyableMembers.Select((m) => m.Name))}**\nDo you want to continue anyway?");
|
||||||
//}
|
if (!await Context.PromptYesNo(msg, TimeSpan.FromMinutes(5))) throw new PKError("Tag change cancelled.");
|
||||||
|
}
|
||||||
|
|
||||||
await Systems.Save(Context.SenderSystem);
|
await Systems.Save(Context.SenderSystem);
|
||||||
return PKResult.Success("uwu");
|
await Context.Channel.SendMessageAsync($"{Emojis.Success} System tag {(newTag != null ? "changed" : "cleared")}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<PKSystem> ReadContextParameterAsync(string value)
|
public override async Task<PKSystem> ReadContextParameterAsync(string value)
|
||||||
|
@ -159,13 +159,43 @@ namespace PluralKit.Bot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PKResult : RuntimeResult
|
public static class ContextExt {
|
||||||
{
|
public static async Task<bool> PromptYesNo(this ICommandContext ctx, IMessage message, TimeSpan? timeout = null) {
|
||||||
public PKResult(CommandError? error, string reason) : base(error, reason)
|
await ctx.Message.AddReactionsAsync(new[] {new Emoji(Emojis.Success), new Emoji(Emojis.Error)});
|
||||||
{
|
var reaction = await ctx.WaitForReaction(ctx.Message, message.Author, (r) => r.Emote.Name == Emojis.Success || r.Emote.Name == Emojis.Error);
|
||||||
|
return reaction.Emote.Name == Emojis.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RuntimeResult Error(string reason) => new PKResult(CommandError.Unsuccessful, reason);
|
public static async Task<SocketReaction> WaitForReaction(this ICommandContext ctx, IUserMessage message, IUser user = null, Func<SocketReaction, bool> predicate = null, TimeSpan? timeout = null) {
|
||||||
public static RuntimeResult Success(string reason = null) => new PKResult(null, reason);
|
var tcs = new TaskCompletionSource<SocketReaction>();
|
||||||
|
|
||||||
|
Task Inner(Cacheable<IUserMessage, ulong> _message, ISocketMessageChannel _channel, SocketReaction reaction) {
|
||||||
|
// Ignore reactions for different messages
|
||||||
|
if (message.Id != _message.Id) return Task.CompletedTask;
|
||||||
|
|
||||||
|
// Ignore messages from other users if a user was defined
|
||||||
|
if (user != null && user.Id != reaction.UserId) return Task.CompletedTask;
|
||||||
|
|
||||||
|
// Check the predicate, if true - accept the reaction
|
||||||
|
if (predicate?.Invoke(reaction) ?? true) {
|
||||||
|
tcs.SetResult(reaction);
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
(ctx as BaseSocketClient).ReactionAdded += Inner;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await (tcs.Task.TimeoutAfter(timeout));
|
||||||
|
} finally {
|
||||||
|
(ctx as BaseSocketClient).ReactionAdded -= Inner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class PKError : Exception
|
||||||
|
{
|
||||||
|
public PKError(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -37,12 +37,12 @@ namespace PluralKit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task Save(PKSystem system) {
|
public async Task Save(PKSystem system) {
|
||||||
await conn.UpdateAsync(system);
|
await conn.ExecuteAsync("update systems set name = @Name, description = @Description, tag = @Tag, avatar_url = @AvatarUrl, token = @Token, ui_tz = @UiTz where id = @Id", system);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(PKSystem system) {
|
public async Task Delete(PKSystem system) {
|
||||||
await conn.DeleteAsync(system);
|
await conn.ExecuteAsync("delete from systems where id = @Id", system);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<ulong>> GetLinkedAccountIds(PKSystem system)
|
public async Task<IEnumerable<ulong>> GetLinkedAccountIds(PKSystem system)
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Dapper;
|
using Dapper;
|
||||||
using Discord;
|
using Discord;
|
||||||
@ -28,5 +29,24 @@ namespace PluralKit
|
|||||||
if (str.Length < maxLength) return str;
|
if (str.Length < maxLength) return str;
|
||||||
return str.Substring(0, maxLength - ellipsis.Length) + ellipsis;
|
return str.Substring(0, maxLength - ellipsis.Length) + ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<TResult> TimeoutAfter<TResult>(this Task<TResult> task, TimeSpan? timeout) {
|
||||||
|
// https://stackoverflow.com/a/22078975
|
||||||
|
using (var timeoutCancellationTokenSource = new CancellationTokenSource()) {
|
||||||
|
var completedTask = await Task.WhenAny(task, Task.Delay(timeout ?? TimeSpan.FromMilliseconds(-1), timeoutCancellationTokenSource.Token));
|
||||||
|
if (completedTask == task) {
|
||||||
|
timeoutCancellationTokenSource.Cancel();
|
||||||
|
return await task; // Very important in order to propagate exceptions
|
||||||
|
} else {
|
||||||
|
throw new TimeoutException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Emojis {
|
||||||
|
public static readonly string Warn = "\u26A0";
|
||||||
|
public static readonly string Success = "\u2705";
|
||||||
|
public static readonly string Error = "\u274C";
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user