bot: add member renaming command
This commit is contained in:
parent
ff78639ac0
commit
9a5a5ce34f
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
|
||||
@ -13,31 +14,57 @@ namespace PluralKit.Bot.Commands
|
||||
|
||||
[Command("new")]
|
||||
[Remarks("member new <name>")]
|
||||
[MustHaveSystem]
|
||||
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 (memberName.Length > Context.SenderSystem.MaxMemberNameLength) {
|
||||
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} Member name too long ({memberName.Length} > {Context.SenderSystem.MaxMemberNameLength} 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?");
|
||||
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.Name}\" (with ID `{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);
|
||||
|
||||
// Send confirmation and space hint
|
||||
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.");
|
||||
}
|
||||
|
||||
[Command("rename")]
|
||||
[Alias("name", "changename", "setname")]
|
||||
[Remarks("member <member> rename <newname>")]
|
||||
[MustPassOwnMember]
|
||||
public async Task RenameMember([Remainder] string newName) {
|
||||
// TODO: this method is pretty much a 1:1 copy/paste of the above creation method, find a way to clean?
|
||||
|
||||
// Warn if member name will be unproxyable (with/without tag)
|
||||
if (newName.Length > Context.SenderSystem.MaxMemberNameLength) {
|
||||
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} New member name too long ({newName.Length} > {Context.SenderSystem.MaxMemberNameLength} characters), this member will be unproxyable. Do you want to change it anyway?");
|
||||
if (!await Context.PromptYesNo(msg)) throw new PKError("Member renaming cancelled.");
|
||||
}
|
||||
|
||||
// Warn if there's already a member by this name
|
||||
var existingMember = await Members.GetByName(Context.SenderSystem, newName);
|
||||
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 rename this member to that name too?");
|
||||
if (!await Context.PromptYesNo(msg)) throw new PKError("Member renaming cancelled.");
|
||||
}
|
||||
|
||||
// Rename the mebmer
|
||||
ContextEntity.Name = newName;
|
||||
await Members.Save(ContextEntity);
|
||||
|
||||
await Context.Channel.SendMessageAsync($"{Emojis.Success} Member renamed.");
|
||||
if (newName.Contains(" ")) await Context.Channel.SendMessageAsync($"{Emojis.Note} Note that this member's name now 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);
|
||||
|
@ -20,7 +20,7 @@ namespace PluralKit.Bot.Commands
|
||||
[Command]
|
||||
public async Task Query(PKSystem system = null) {
|
||||
if (system == null) system = Context.SenderSystem;
|
||||
if (system == null) Context.RaiseNoSystemError();
|
||||
if (system == null) throw Errors.NotOwnSystemError;
|
||||
|
||||
await Context.Channel.SendMessageAsync(embed: await EmbedService.CreateSystemEmbed(system));
|
||||
}
|
||||
@ -29,8 +29,8 @@ namespace PluralKit.Bot.Commands
|
||||
[Remarks("system new <name>")]
|
||||
public async Task New([Remainder] string systemName = null)
|
||||
{
|
||||
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 (ContextEntity != null) throw Errors.NotOwnSystemError;
|
||||
if (Context.SenderSystem != null) throw Errors.NoSystemError;
|
||||
|
||||
var system = await Systems.Create(systemName);
|
||||
await Systems.Link(system, Context.User.Id);
|
||||
@ -39,9 +39,8 @@ namespace PluralKit.Bot.Commands
|
||||
|
||||
[Command("name")]
|
||||
[Remarks("system name <name>")]
|
||||
[MustHaveSystem]
|
||||
public async Task Name([Remainder] string newSystemName = null) {
|
||||
if (ContextEntity != null) RaiseNoContextError();
|
||||
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)");
|
||||
|
||||
Context.SenderSystem.Name = newSystemName;
|
||||
@ -51,9 +50,8 @@ namespace PluralKit.Bot.Commands
|
||||
|
||||
[Command("description")]
|
||||
[Remarks("system description <description>")]
|
||||
[MustHaveSystem]
|
||||
public async Task Description([Remainder] string newDescription = null) {
|
||||
if (ContextEntity != null) RaiseNoContextError();
|
||||
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)");
|
||||
|
||||
Context.SenderSystem.Description = newDescription;
|
||||
@ -63,9 +61,8 @@ namespace PluralKit.Bot.Commands
|
||||
|
||||
[Command("tag")]
|
||||
[Remarks("system tag <tag>")]
|
||||
[MustHaveSystem]
|
||||
public async Task Tag([Remainder] string newTag = null) {
|
||||
if (ContextEntity != null) RaiseNoContextError();
|
||||
if (Context.SenderSystem == null) Context.RaiseNoSystemError();
|
||||
if (newTag.Length > 30) throw new PKError($"Your chosen description is too long. ({newTag.Length} > 30 characters)");
|
||||
|
||||
Context.SenderSystem.Tag = newTag;
|
||||
@ -83,10 +80,8 @@ namespace PluralKit.Bot.Commands
|
||||
|
||||
[Command("delete")]
|
||||
[Remarks("system delete")]
|
||||
[MustHaveSystem]
|
||||
public async Task Delete() {
|
||||
if (ContextEntity != null) RaiseNoContextError();
|
||||
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 reply = await Context.AwaitMessage(Context.Channel, Context.User, timeout: TimeSpan.FromMinutes(1));
|
||||
if (reply.Content != Context.SenderSystem.Hid) throw new PKError($"System deletion cancelled. Note that you must reply with your system ID (`{Context.SenderSystem.Hid}`) *verbatim*.");
|
||||
@ -103,7 +98,7 @@ namespace PluralKit.Bot.Commands
|
||||
[Remarks("system [system] list")]
|
||||
public async Task MemberShortList() {
|
||||
var system = Context.GetContextEntity<PKSystem>() ?? Context.SenderSystem;
|
||||
if (system == null) Context.RaiseNoSystemError();
|
||||
if (system == null) throw Errors.NoSystemError;
|
||||
|
||||
var members = await Members.GetBySystem(system);
|
||||
var embedTitle = system.Name != null ? $"Members of {system.Name} (`{system.Hid}`)" : $"Members of `{system.Hid}`";
|
||||
@ -120,7 +115,7 @@ namespace PluralKit.Bot.Commands
|
||||
[Remarks("system [system] list full")]
|
||||
public async Task MemberLongList() {
|
||||
var system = Context.GetContextEntity<PKSystem>() ?? Context.SenderSystem;
|
||||
if (system == null) Context.RaiseNoSystemError();
|
||||
if (system == null) throw Errors.NoSystemError;
|
||||
|
||||
var members = await Members.GetBySystem(system);
|
||||
var embedTitle = system.Name != null ? $"Members of {system.Name} (`{system.Hid}`)" : $"Members of `{system.Hid}`";
|
||||
|
9
PluralKit/Bot/Errors.cs
Normal file
9
PluralKit/Bot/Errors.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace PluralKit.Bot {
|
||||
public static class Errors {
|
||||
public static PKError NotOwnSystemError => new PKError($"You can only run this command on your own system.");
|
||||
public static PKError NotOwnMemberError => new PKError($"You can only run this command on your own member.");
|
||||
public static PKError NoSystemError => new PKError("You do not have a system registered with PluralKit. To create one, type `pk;system new`.");
|
||||
public static PKError ExistinSystemError => 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`.");
|
||||
public static PKError MissingMemberError => new PKSyntaxError("You need to specify a member to run this command on.");
|
||||
}
|
||||
}
|
34
PluralKit/Bot/Preconditions.cs
Normal file
34
PluralKit/Bot/Preconditions.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
|
||||
namespace PluralKit.Bot {
|
||||
class MustHaveSystem : PreconditionAttribute
|
||||
{
|
||||
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
|
||||
{
|
||||
var c = context as PKCommandContext;
|
||||
if (c == null) return PreconditionResult.FromError("Must be called on a PKCommandContext (should never happen!)");
|
||||
if (c.SenderSystem == null) return PreconditionResult.FromError(Errors.NoSystemError);
|
||||
return PreconditionResult.FromSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
class MustPassOwnMember : PreconditionAttribute
|
||||
{
|
||||
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
|
||||
{
|
||||
// OK when:
|
||||
// - Sender has a system
|
||||
// - Sender passes a member as a context parameter
|
||||
// - Sender owns said member
|
||||
|
||||
var c = context as PKCommandContext;
|
||||
if (c == null)
|
||||
if (c.SenderSystem == null) return PreconditionResult.FromError(Errors.NoSystemError);
|
||||
if (c.GetContextEntity<PKMember>() == null) return PreconditionResult.FromError(Errors.MissingMemberError);
|
||||
if (c.GetContextEntity<PKMember>().System != c.SenderSystem.Id) return PreconditionResult.FromError(Errors.NotOwnMemberError);
|
||||
return PreconditionResult.FromSuccess();
|
||||
}
|
||||
}
|
||||
}
|
@ -114,11 +114,6 @@ namespace PluralKit.Bot
|
||||
public void SetContextEntity(object 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
|
||||
@ -138,42 +133,42 @@ namespace PluralKit.Bot
|
||||
// context, with the context argument removed so it delegates to the subcommand executor
|
||||
builder.AddCommand("", async (ctx, param, services, info) => {
|
||||
var pkCtx = ctx as PKCommandContext;
|
||||
var res = await ReadContextParameterAsync(param[0] as string);
|
||||
pkCtx.SetContextEntity(res);
|
||||
pkCtx.SetContextEntity(param[0] as T);
|
||||
|
||||
await commandService.ExecuteAsync(pkCtx, Prefix + " " + param[1] as string, services);
|
||||
}, (cb) => {
|
||||
cb.WithPriority(-9999);
|
||||
cb.AddPrecondition(new ContextParameterFallbackPreconditionAttribute());
|
||||
cb.AddParameter<string>("contextValue", (pb) => pb.WithDefault(""));
|
||||
cb.AddPrecondition(new MustNotHaveContextPrecondition());
|
||||
cb.AddParameter<T>("contextValue", (pb) => pb.WithDefault(""));
|
||||
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 MustNotHaveContextPrecondition : PreconditionAttribute
|
||||
{
|
||||
public ContextParameterFallbackPreconditionAttribute()
|
||||
public MustNotHaveContextPrecondition()
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
|
||||
{
|
||||
if (context.GetType().Name != "ContextualContext`1") {
|
||||
return PreconditionResult.FromSuccess();
|
||||
} else {
|
||||
return PreconditionResult.FromError("");
|
||||
}
|
||||
if ((context as PKCommandContext)?.GetContextEntity<object>() == null) return PreconditionResult.FromSuccess();
|
||||
return PreconditionResult.FromError("(should not be seen)");
|
||||
}
|
||||
}
|
||||
class PKError : Exception
|
||||
|
||||
public class PKError : Exception
|
||||
{
|
||||
public PKError(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class PKSyntaxError : PKError
|
||||
{
|
||||
public PKSyntaxError(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@ namespace PluralKit
|
||||
public string Token { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
public string UiTz { get; set; }
|
||||
|
||||
public int MaxMemberNameLength => Tag != null ? 32 - Tag.Length - 1 : 32;
|
||||
}
|
||||
|
||||
[Table("members")]
|
||||
|
@ -72,7 +72,8 @@ namespace PluralKit {
|
||||
}
|
||||
|
||||
public async Task<PKMember> GetByName(PKSystem system, string name) {
|
||||
return await conn.QuerySingleOrDefaultAsync<PKMember>("select * from members where lower(name) = @Name and system = @SystemID", new { Name = name, SystemID = system.Id });
|
||||
// QueryFirst, since members can (in rare cases) share names
|
||||
return await conn.QueryFirstOrDefaultAsync<PKMember>("select * from members where lower(name) = @Name and system = @SystemID", new { Name = name, SystemID = system.Id });
|
||||
}
|
||||
|
||||
public async Task<ICollection<PKMember>> GetUnproxyableMembers(PKSystem system) {
|
||||
@ -88,11 +89,11 @@ namespace PluralKit {
|
||||
}
|
||||
|
||||
public async Task Save(PKMember member) {
|
||||
await conn.UpdateAsync(member);
|
||||
await conn.ExecuteAsync("update members set name = @Name, description = @Description, color = @Color, avatar_url = @AvatarUrl, birthday = @Birthday, pronouns = @Pronouns, prefix = @Prefix, suffix = @Suffix where id = @Id", member);
|
||||
}
|
||||
|
||||
public async Task Delete(PKMember member) {
|
||||
await conn.DeleteAsync(member);
|
||||
await conn.ExecuteAsync("delete from members where id = @Id", member);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user