bot: add member creation command
This commit is contained in:
parent
876dcc0145
commit
8359df09e9
@ -118,17 +118,24 @@ 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)
|
||||||
{
|
{
|
||||||
|
// TODO: refactor this entire block, it's fugly.
|
||||||
if (!_result.IsSuccess) {
|
if (!_result.IsSuccess) {
|
||||||
|
if (_result.Error == CommandError.Unsuccessful || _result.Error == CommandError.Exception) {
|
||||||
// If this is a PKError (ie. thrown deliberately), show user facing message
|
// If this is a PKError (ie. thrown deliberately), show user facing message
|
||||||
// If not, log as error
|
// If not, log as error
|
||||||
var exception = (_result as ExecuteResult?)?.Exception;
|
var exception = (_result as ExecuteResult?)?.Exception;
|
||||||
if (exception is PKError) {
|
if (exception is PKError) {
|
||||||
await ctx.Message.Channel.SendMessageAsync($"{Emojis.Error} {exception.Message}");
|
await ctx.Message.Channel.SendMessageAsync($"{Emojis.Error} {exception.Message}");
|
||||||
} else if (exception is TimeoutException) {
|
} else if (exception is TimeoutException) {
|
||||||
await ctx.Message.Channel.SendMessageAsync($"{Emojis.Error} Operation timed out. Try being faster");
|
await ctx.Message.Channel.SendMessageAsync($"{Emojis.Error} Operation timed out. Try being faster next time :)");
|
||||||
} else {
|
} else {
|
||||||
HandleRuntimeError(ctx.Message as SocketMessage, (_result as ExecuteResult?)?.Exception);
|
HandleRuntimeError(ctx.Message as SocketMessage, (_result as ExecuteResult?)?.Exception);
|
||||||
}
|
}
|
||||||
|
} else if ((_result.Error == CommandError.BadArgCount || _result.Error == CommandError.MultipleMatches) && cmd.IsSpecified) {
|
||||||
|
await ctx.Message.Channel.SendMessageAsync($"{Emojis.Error} {_result.ErrorReason}\n**Usage: **pk;{cmd.Value.Remarks}");
|
||||||
|
} else if (_result.Error == CommandError.UnknownCommand || _result.Error == CommandError.UnmetPrecondition) {
|
||||||
|
await ctx.Message.Channel.SendMessageAsync($"{Emojis.Error} {_result.ErrorReason}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
47
PluralKit/Bot/Commands/MemberCommands.cs
Normal file
47
PluralKit/Bot/Commands/MemberCommands.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
|
||||||
|
namespace PluralKit.Bot.Commands
|
||||||
|
{
|
||||||
|
[Group("member")]
|
||||||
|
public class MemberCommands : ContextParameterModuleBase<PKMember>
|
||||||
|
{
|
||||||
|
public MemberStore Members { get; set; }
|
||||||
|
|
||||||
|
public override string Prefix => "member";
|
||||||
|
public override string ContextNoun => "member";
|
||||||
|
|
||||||
|
[Command("new")]
|
||||||
|
[Remarks("member new <name>")]
|
||||||
|
public async Task NewMember([Remainder] string memberName) {
|
||||||
|
if (Context.SenderSystem == null) Context.RaiseNoSystemError();
|
||||||
|
if (ContextEntity != null) RaiseNoContextError();
|
||||||
|
|
||||||
|
// Warn if member name will be unproxyable (with/without tag)
|
||||||
|
var maxLength = Context.SenderSystem.Tag != null ? 32 - Context.SenderSystem.Tag.Length - 1 : 32;
|
||||||
|
if (memberName.Length > maxLength) {
|
||||||
|
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} Member name too long ({memberName.Length} > {maxLength} characters), this member will be unproxyable. Do you want to create it anyway? (You can change the name later)");
|
||||||
|
if (!await Context.PromptYesNo(msg)) throw new PKError("Member creation cancelled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn if there's already a member by this name
|
||||||
|
var existingMember = await Members.GetByName(Context.SenderSystem, memberName);
|
||||||
|
if (existingMember != null) {
|
||||||
|
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.Name}\" (`{existingMember.Hid}`). Do you want to create another member with the same name?");
|
||||||
|
if (!await Context.PromptYesNo(msg)) throw new PKError("Member creation cancelled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the member
|
||||||
|
var member = await Members.Create(Context.SenderSystem, memberName);
|
||||||
|
|
||||||
|
await Context.Channel.SendMessageAsync($"{Emojis.Success} Member \"{memberName}\" (`{member.Hid}`) registered! Type `pk;help member` for a list of commands to edit this member.");
|
||||||
|
if (memberName.Contains(" ")) await Context.Channel.SendMessageAsync($"{Emojis.Note} Note that this member's name contains spaces. You will need to surround it with \"double quotes\" when using commands referring to it.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<PKMember> ReadContextParameterAsync(string value)
|
||||||
|
{
|
||||||
|
var res = await new PKMemberTypeReader().ReadAsync(Context, value, _services);
|
||||||
|
return res.IsSuccess ? res.BestMatch as PKMember : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,17 +11,16 @@ namespace PluralKit.Bot.Commands
|
|||||||
public class SystemCommands : ContextParameterModuleBase<PKSystem>
|
public class SystemCommands : ContextParameterModuleBase<PKSystem>
|
||||||
{
|
{
|
||||||
public override string Prefix => "system";
|
public override string Prefix => "system";
|
||||||
|
public override string ContextNoun => "system";
|
||||||
|
|
||||||
public SystemStore Systems {get; set;}
|
public SystemStore Systems {get; set;}
|
||||||
public MemberStore Members {get; set;}
|
public MemberStore Members {get; set;}
|
||||||
public EmbedService EmbedService {get; set;}
|
public EmbedService EmbedService {get; set;}
|
||||||
|
|
||||||
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 PKError OTHER_SYSTEM_CONTEXT_ERROR => new PKError("You can only run this command on your own system.");
|
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public async Task 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) throw NO_SYSTEM_ERROR;
|
if (system == null) Context.RaiseNoSystemError();
|
||||||
|
|
||||||
await Context.Channel.SendMessageAsync(embed: await EmbedService.CreateSystemEmbed(system));
|
await Context.Channel.SendMessageAsync(embed: await EmbedService.CreateSystemEmbed(system));
|
||||||
}
|
}
|
||||||
@ -29,19 +28,19 @@ namespace PluralKit.Bot.Commands
|
|||||||
[Command("new")]
|
[Command("new")]
|
||||||
public async Task New([Remainder] string systemName = null)
|
public async Task New([Remainder] string systemName = null)
|
||||||
{
|
{
|
||||||
if (ContextEntity != null) throw OTHER_SYSTEM_CONTEXT_ERROR;
|
if (ContextEntity != null) RaiseNoContextError();
|
||||||
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`.");
|
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 Context.Channel.SendMessageAsync($"{Emojis.Success} Your system has been created. Type `pk;system` to view it, and type `pk;help` for more information about commands you can use now.");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("name")]
|
[Command("name")]
|
||||||
public async Task Name([Remainder] string newSystemName = null) {
|
public async Task Name([Remainder] string newSystemName = null) {
|
||||||
if (ContextEntity != null) throw OTHER_SYSTEM_CONTEXT_ERROR;
|
if (ContextEntity != null) RaiseNoContextError();
|
||||||
if (Context.SenderSystem == null) throw NO_SYSTEM_ERROR;
|
if (Context.SenderSystem == null) Context.RaiseNoSystemError();
|
||||||
if (newSystemName != null && newSystemName.Length > 250) throw new PKError($"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;
|
||||||
@ -51,8 +50,8 @@ namespace PluralKit.Bot.Commands
|
|||||||
|
|
||||||
[Command("description")]
|
[Command("description")]
|
||||||
public async Task Description([Remainder] string newDescription = null) {
|
public async Task Description([Remainder] string newDescription = null) {
|
||||||
if (ContextEntity != null) throw OTHER_SYSTEM_CONTEXT_ERROR;
|
if (ContextEntity != null) RaiseNoContextError();
|
||||||
if (Context.SenderSystem == null) throw NO_SYSTEM_ERROR;
|
if (Context.SenderSystem == null) Context.RaiseNoSystemError();
|
||||||
if (newDescription != null && newDescription.Length > 1000) throw new PKError($"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;
|
||||||
@ -62,8 +61,8 @@ namespace PluralKit.Bot.Commands
|
|||||||
|
|
||||||
[Command("tag")]
|
[Command("tag")]
|
||||||
public async Task Tag([Remainder] string newTag = null) {
|
public async Task Tag([Remainder] string newTag = null) {
|
||||||
if (ContextEntity != null) throw OTHER_SYSTEM_CONTEXT_ERROR;
|
if (ContextEntity != null) RaiseNoContextError();
|
||||||
if (Context.SenderSystem == null) throw NO_SYSTEM_ERROR;
|
if (Context.SenderSystem == null) Context.RaiseNoSystemError();
|
||||||
if (newTag.Length > 30) throw new PKError($"Your chosen description is too long. ({newTag.Length} > 30 characters)");
|
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;
|
||||||
@ -72,7 +71,7 @@ namespace PluralKit.Bot.Commands
|
|||||||
var unproxyableMembers = await Members.GetUnproxyableMembers(Context.SenderSystem);
|
var unproxyableMembers = await Members.GetUnproxyableMembers(Context.SenderSystem);
|
||||||
if (unproxyableMembers.Count > 0) {
|
if (unproxyableMembers.Count > 0) {
|
||||||
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?");
|
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.");
|
if (!await Context.PromptYesNo(msg)) throw new PKError("Tag change cancelled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
await Systems.Save(Context.SenderSystem);
|
await Systems.Save(Context.SenderSystem);
|
||||||
@ -81,8 +80,8 @@ namespace PluralKit.Bot.Commands
|
|||||||
|
|
||||||
[Command("delete")]
|
[Command("delete")]
|
||||||
public async Task Delete() {
|
public async Task Delete() {
|
||||||
if (ContextEntity != null) throw OTHER_SYSTEM_CONTEXT_ERROR;
|
if (ContextEntity != null) RaiseNoContextError();
|
||||||
if (Context.SenderSystem == null) throw NO_SYSTEM_ERROR;
|
if (Context.SenderSystem == null) Context.RaiseNoSystemError();
|
||||||
|
|
||||||
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} Are you sure you want to delete your system? If so, reply to this message with your system's ID (`{Context.SenderSystem.Hid}`).\n**Note: this action is permanent.**");
|
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} Are you sure you want to delete your system? If so, reply to this message with your system's ID (`{Context.SenderSystem.Hid}`).\n**Note: this action is permanent.**");
|
||||||
var reply = await Context.AwaitMessage(Context.Channel, Context.User, timeout: TimeSpan.FromMinutes(1));
|
var reply = await Context.AwaitMessage(Context.Channel, Context.User, timeout: TimeSpan.FromMinutes(1));
|
||||||
|
@ -112,6 +112,11 @@ namespace PluralKit.Bot
|
|||||||
public void SetContextEntity(object entity) {
|
public void SetContextEntity(object entity) {
|
||||||
_entity = entity;
|
_entity = entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RaiseNoSystemError()
|
||||||
|
{
|
||||||
|
throw 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 {User.Mention}` from that account to link it here.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class ContextParameterModuleBase<T> : ModuleBase<PKCommandContext> where T: class
|
public abstract class ContextParameterModuleBase<T> : ModuleBase<PKCommandContext> where T: class
|
||||||
@ -120,6 +125,7 @@ namespace PluralKit.Bot
|
|||||||
public CommandService _commands { get; set; }
|
public CommandService _commands { get; set; }
|
||||||
|
|
||||||
public abstract string Prefix { get; }
|
public abstract string Prefix { get; }
|
||||||
|
public abstract string ContextNoun { get; }
|
||||||
public abstract Task<T> ReadContextParameterAsync(string value);
|
public abstract Task<T> ReadContextParameterAsync(string value);
|
||||||
|
|
||||||
public T ContextEntity => Context.GetContextEntity<T>();
|
public T ContextEntity => Context.GetContextEntity<T>();
|
||||||
@ -141,6 +147,10 @@ namespace PluralKit.Bot
|
|||||||
cb.AddParameter<string>("rest", (pb) => pb.WithDefault("").WithIsRemainder(true));
|
cb.AddParameter<string>("rest", (pb) => pb.WithDefault("").WithIsRemainder(true));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RaiseNoContextError() {
|
||||||
|
throw new PKError($"You can only run this command on your own {ContextNoun}.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ContextParameterFallbackPreconditionAttribute : PreconditionAttribute
|
public class ContextParameterFallbackPreconditionAttribute : PreconditionAttribute
|
||||||
@ -160,9 +170,9 @@ namespace PluralKit.Bot
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class ContextExt {
|
public static class ContextExt {
|
||||||
public static async Task<bool> PromptYesNo(this ICommandContext ctx, IMessage message, TimeSpan? timeout = null) {
|
public static async Task<bool> PromptYesNo(this ICommandContext ctx, IUserMessage message, TimeSpan? timeout = null) {
|
||||||
await ctx.Message.AddReactionsAsync(new[] {new Emoji(Emojis.Success), new Emoji(Emojis.Error)});
|
await message.AddReactionsAsync(new[] {new Emoji(Emojis.Success), new Emoji(Emojis.Error)});
|
||||||
var reaction = await ctx.AwaitReaction(ctx.Message, message.Author, (r) => r.Emote.Name == Emojis.Success || r.Emote.Name == Emojis.Error, timeout);
|
var reaction = await ctx.AwaitReaction(message, ctx.User, (r) => r.Emote.Name == Emojis.Success || r.Emote.Name == Emojis.Error, timeout ?? TimeSpan.FromMinutes(1));
|
||||||
return reaction.Emote.Name == Emojis.Success;
|
return reaction.Emote.Name == Emojis.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ namespace PluralKit {
|
|||||||
public async Task<PKMember> Create(PKSystem system, string name) {
|
public async Task<PKMember> Create(PKSystem system, string name) {
|
||||||
// TODO: handle collision
|
// TODO: handle collision
|
||||||
var hid = Utils.GenerateHid();
|
var hid = Utils.GenerateHid();
|
||||||
return await conn.QuerySingleAsync("insert into members (hid, system, name) values (@Hid, @SystemId, @Name) returning *", new {
|
return await conn.QuerySingleAsync<PKMember>("insert into members (hid, system, name) values (@Hid, @SystemId, @Name) returning *", new {
|
||||||
Hid = hid,
|
Hid = hid,
|
||||||
SystemID = system.Id,
|
SystemID = system.Id,
|
||||||
Name = name
|
Name = name
|
||||||
@ -68,15 +68,11 @@ namespace PluralKit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PKMember> GetByHid(string hid) {
|
public async Task<PKMember> GetByHid(string hid) {
|
||||||
return await conn.QuerySingleAsync("select * from members where hid = @Hid", new { Hid = hid.ToLower() });
|
return await conn.QuerySingleOrDefaultAsync<PKMember>("select * from members where hid = @Hid", new { Hid = hid.ToLower() });
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PKMember> GetByName(string name) {
|
public async Task<PKMember> GetByName(PKSystem system, string name) {
|
||||||
return await conn.QuerySingleAsync("select * from members where lower(name) = lower(@Name)", new { Name = name });
|
return await conn.QuerySingleOrDefaultAsync<PKMember>("select * from members where lower(name) = @Name and system = @SystemID", new { Name = name, SystemID = system.Id });
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<PKMember> GetByNameConstrained(PKSystem system, string name) {
|
|
||||||
return await conn.QuerySingleAsync("select * from members where lower(name) = @Name and system = @SystemID", new { Name = name, SystemID = system.Id });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<PKMember>> GetUnproxyableMembers(PKSystem system) {
|
public async Task<ICollection<PKMember>> GetUnproxyableMembers(PKSystem system) {
|
||||||
|
@ -48,5 +48,6 @@ namespace PluralKit
|
|||||||
public static readonly string Warn = "\u26A0";
|
public static readonly string Warn = "\u26A0";
|
||||||
public static readonly string Success = "\u2705";
|
public static readonly string Success = "\u2705";
|
||||||
public static readonly string Error = "\u274C";
|
public static readonly string Error = "\u274C";
|
||||||
|
public static readonly string Note = "\u2757";
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user