2020-02-12 14:16:19 +00:00
using System.Linq ;
2020-02-01 12:03:02 +00:00
using System.Threading.Tasks ;
2020-06-29 11:57:48 +00:00
using Dapper ;
2020-02-12 14:16:19 +00:00
using PluralKit.Core ;
2020-02-01 12:03:02 +00:00
2020-02-12 14:16:19 +00:00
namespace PluralKit.Bot
2020-02-01 12:03:02 +00:00
{
public class MemberProxy
{
2020-06-29 11:57:48 +00:00
private readonly IDatabase _db ;
2020-02-01 12:03:02 +00:00
2020-06-29 11:57:48 +00:00
public MemberProxy ( IDatabase db )
2020-02-01 12:03:02 +00:00
{
2020-06-29 11:57:48 +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 )
{
2020-06-29 11:57:48 +00:00
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 ,
2020-07-03 10:00:59 +00:00
new { Prefix = newTag . Prefix , Suffix = newTag . Suffix , Existing = target . Id , system = target . System } ) ) ) . ToList ( ) ;
2020-06-29 11:57:48 +00:00
2020-02-01 12:03:02 +00:00
if ( conflicts . Count < = 0 ) return true ;
2020-06-18 15:08:36 +00:00
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-03-04 23:07:42 +00:00
if ( ctx . Match ( "clear" , "purge" , "clean" , "removeall" ) | | ctx . MatchFlag ( "c" , "clear" ) )
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 ( ) ;
}
2020-06-29 11:57:48 +00:00
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
{
2020-02-22 14:21:48 +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
2020-02-20 22:53:05 +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 ( ) ;
2020-06-29 11:57:48 +00:00
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
{
2020-02-22 14:21:48 +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
2020-02-20 22:53:05 +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 ) ;
2020-06-29 11:57:48 +00:00
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
{
2020-02-20 22:53:05 +00:00
var requestedTag = ParseProxyTags ( ctx . RemainderOrNull ( skipFlags : false ) ) ;
2020-02-03 14:11:35 +00:00
if ( requestedTag . IsEmpty ) throw Errors . EmptyProxyTags ( target ) ;
2020-02-05 22:44:03 +00:00
// 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 )
2020-02-05 22:44:03 +00:00
{
2020-06-20 15:36:03 +00:00
var msg = await ctx . Reply ( $"This member already has more than one proxy tag set: {target.ProxyTagsString()}\nDo you want to replace them?" ) ;
2020-02-05 22:44:03 +00:00
if ( ! await ctx . PromptYesNo ( msg ) )
throw Errors . GenericCancelled ( ) ;
}
2020-02-01 12:03:02 +00:00
if ( ! await WarnOnConflict ( requestedTag ) )
throw Errors . GenericCancelled ( ) ;
2020-06-29 11:57:48 +00:00
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
}
}
}
}