PluralKit/PluralKit.Bot/Commands/MemberProxy.cs

138 lines
6.6 KiB
C#
Raw Normal View History

using System.Linq;
2020-02-01 12:03:02 +00:00
using System.Threading.Tasks;
using Dapper;
using PluralKit.Core;
2020-02-01 12:03:02 +00:00
namespace PluralKit.Bot
2020-02-01 12:03:02 +00:00
{
public class MemberProxy
{
private readonly IDatabase _db;
2020-02-01 12:03:02 +00:00
public MemberProxy(IDatabase db)
2020-02-01 12:03:02 +00:00
{
_db = db;
2020-02-01 12:03:02 +00:00
}
public async Task Proxy(Context ctx, PKMember target)
{
if (ctx.System == null) throw Errors.NoSystemError;
if (target.System != ctx.System.Id) throw Errors.NotOwnMemberError;
ProxyTag ParseProxyTags(string exampleProxy)
{
// // Make sure there's one and only one instance of "text" in the example proxy given
var prefixAndSuffix = exampleProxy.Split("text");
if (prefixAndSuffix.Length < 2) throw Errors.ProxyMustHaveText;
if (prefixAndSuffix.Length > 2) throw Errors.ProxyMultipleText;
return new ProxyTag(prefixAndSuffix[0], prefixAndSuffix[1]);
}
async Task<bool> WarnOnConflict(ProxyTag newTag)
{
var query = "select * from (select *, (unnest(proxy_tags)).prefix as prefix, (unnest(proxy_tags)).suffix as suffix from members where system = @System) as _ where prefix = @Prefix and suffix = @Suffix and id != @Existing";
var conflicts = (await _db.Execute(conn => conn.QueryAsync<PKMember>(query,
new {Prefix = newTag.Prefix, Suffix = newTag.Suffix, Existing = target.Id, system = target.System}))).ToList();
2020-02-01 12:03:02 +00:00
if (conflicts.Count <= 0) return true;
var conflictList = conflicts.Select(m => $"- **{m.NameFor(ctx)}**");
2020-02-01 12:03:02 +00:00
var msg = await ctx.Reply(
$"{Emojis.Warn} The following members have conflicting proxy tags:\n{string.Join('\n', conflictList)}\nDo you want to proceed anyway?");
return await ctx.PromptYesNo(msg);
}
2020-03-04 17:13:36 +00:00
// "Sub"command: clear flag
2020-07-07 22:00:23 +00:00
if (ctx.MatchClear())
2020-02-01 12:03:02 +00:00
{
// If we already have multiple tags, this would clear everything, so prompt that
if (target.ProxyTags.Count > 1)
{
var msg = await ctx.Reply(
$"{Emojis.Warn} You already have multiple proxy tags set: {target.ProxyTagsString()}\nDo you want to clear them all?");
if (!await ctx.PromptYesNo(msg))
throw Errors.GenericCancelled();
}
var patch = new MemberPatch {ProxyTags = Partial<ProxyTag[]>.Present(new ProxyTag[0])};
await _db.Execute(conn => conn.UpdateMember(target.Id, patch));
2020-02-01 12:03:02 +00:00
await ctx.Reply($"{Emojis.Success} Proxy tags cleared.");
}
2020-03-04 17:13:36 +00:00
// "Sub"command: no arguments; will print proxy tags
else if (!ctx.HasNext(skipFlags: false))
{
if (target.ProxyTags.Count == 0)
await ctx.Reply("This member does not have any proxy tags.");
else
{
2020-07-05 10:55:21 +00:00
var tags = string.Join("\n", target.ProxyTags.Select(t => $"``{t.ProxyString.EscapeBacktickPair()}``"));
2020-03-04 17:13:36 +00:00
await ctx.Reply($"This member's proxy tags are:\n{tags}");
}
}
2020-02-01 12:03:02 +00:00
// Subcommand: "add"
2020-02-04 17:16:45 +00:00
else if (ctx.Match("add", "append"))
2020-02-01 12:03:02 +00:00
{
if (!ctx.HasNext(skipFlags: false)) throw new PKSyntaxError("You must pass an example proxy to add (eg. `[text]` or `J:text`).");
2020-02-01 12:03:02 +00:00
var tagToAdd = ParseProxyTags(ctx.RemainderOrNull(skipFlags: false));
2020-02-03 14:11:35 +00:00
if (tagToAdd.IsEmpty) throw Errors.EmptyProxyTags(target);
2020-02-01 12:03:02 +00:00
if (target.ProxyTags.Contains(tagToAdd))
throw Errors.ProxyTagAlreadyExists(tagToAdd, target);
if (!await WarnOnConflict(tagToAdd))
throw Errors.GenericCancelled();
var newTags = target.ProxyTags.ToList();
newTags.Add(tagToAdd);
var patch = new MemberPatch {ProxyTags = Partial<ProxyTag[]>.Present(newTags.ToArray())};
await _db.Execute(conn => conn.UpdateMember(target.Id, patch));
2020-07-05 10:55:21 +00:00
await ctx.Reply($"{Emojis.Success} Added proxy tags ``{tagToAdd.ProxyString.EscapeBacktickPair()}``.");
2020-02-01 12:03:02 +00:00
}
// Subcommand: "remove"
2020-02-04 17:16:45 +00:00
else if (ctx.Match("remove", "delete"))
2020-02-01 12:03:02 +00:00
{
if (!ctx.HasNext(skipFlags: false)) throw new PKSyntaxError("You must pass a proxy tag to remove (eg. `[text]` or `J:text`).");
2020-02-01 12:03:02 +00:00
var tagToRemove = ParseProxyTags(ctx.RemainderOrNull(skipFlags: false));
2020-02-03 14:11:35 +00:00
if (tagToRemove.IsEmpty) throw Errors.EmptyProxyTags(target);
2020-02-01 12:03:02 +00:00
if (!target.ProxyTags.Contains(tagToRemove))
throw Errors.ProxyTagDoesNotExist(tagToRemove, target);
var newTags = target.ProxyTags.ToList();
newTags.Remove(tagToRemove);
var patch = new MemberPatch {ProxyTags = Partial<ProxyTag[]>.Present(newTags.ToArray())};
await _db.Execute(conn => conn.UpdateMember(target.Id, patch));
2020-07-05 10:55:21 +00:00
await ctx.Reply($"{Emojis.Success} Removed proxy tags ``{tagToRemove.ProxyString.EscapeBacktickPair()}``.");
2020-02-01 12:03:02 +00:00
}
// Subcommand: bare proxy tag given
else
{
var requestedTag = ParseProxyTags(ctx.RemainderOrNull(skipFlags: false));
2020-02-03 14:11:35 +00:00
if (requestedTag.IsEmpty) throw Errors.EmptyProxyTags(target);
// This is mostly a legacy command, so it's gonna warn if there's
2020-02-01 12:03:02 +00:00
// already more than one proxy tag.
if (target.ProxyTags.Count > 1)
{
var msg = await ctx.Reply($"This member already has more than one proxy tag set: {target.ProxyTagsString()}\nDo you want to replace them?");
if (!await ctx.PromptYesNo(msg))
throw Errors.GenericCancelled();
}
2020-02-01 12:03:02 +00:00
if (!await WarnOnConflict(requestedTag))
throw Errors.GenericCancelled();
var newTags = new[] {requestedTag};
var patch = new MemberPatch {ProxyTags = Partial<ProxyTag[]>.Present(newTags)};
await _db.Execute(conn => conn.UpdateMember(target.Id, patch));
2020-02-01 12:03:02 +00:00
2020-07-05 10:55:21 +00:00
await ctx.Reply($"{Emojis.Success} Member proxy tags set to ``{requestedTag.ProxyString.EscapeBacktickPair()}``.");
2020-02-01 12:03:02 +00:00
}
}
}
}