2020-03-04 17:13:36 +00:00
using System.Text.RegularExpressions ;
2020-02-01 12:03:02 +00:00
using System.Threading.Tasks ;
2020-06-17 19:31:39 +00:00
using System ;
2020-02-01 12:03:02 +00:00
2020-06-13 14:03:57 +00:00
using Dapper ;
2020-02-27 23:23:54 +00:00
2020-06-13 14:03:57 +00:00
using DSharpPlus.Entities ;
2020-02-01 12:03:02 +00:00
2020-06-29 11:57:48 +00:00
using NodaTime ;
2020-02-01 12:03:02 +00:00
using PluralKit.Core ;
2020-02-12 14:16:19 +00:00
namespace PluralKit.Bot
2020-02-01 12:03:02 +00:00
{
public class MemberEdit
{
2020-06-13 14:03:57 +00:00
private readonly IDataStore _data ;
2020-06-13 17:36:43 +00:00
private readonly IDatabase _db ;
2020-02-01 12:03:02 +00:00
2020-06-13 17:36:43 +00:00
public MemberEdit ( IDataStore data , IDatabase db )
2020-02-01 12:03:02 +00:00
{
_data = data ;
2020-06-13 14:03:57 +00:00
_db = db ;
2020-02-01 12:03:02 +00:00
}
public async Task Name ( Context ctx , PKMember target ) {
// TODO: this method is pretty much a 1:1 copy/paste of the above creation method, find a way to clean?
if ( ctx . System = = null ) throw Errors . NoSystemError ;
if ( target . System ! = ctx . System . Id ) throw Errors . NotOwnMemberError ;
var newName = ctx . RemainderOrNull ( ) ? ? throw new PKSyntaxError ( "You must pass a new name for the member." ) ;
// Hard name length cap
if ( newName . Length > Limits . MaxMemberNameLength ) throw Errors . MemberNameTooLongError ( newName . Length ) ;
// Warn if there's already a member by this name
var existingMember = await _data . GetMemberByName ( ctx . System , newName ) ;
if ( existingMember ! = null ) {
2020-06-20 15:36:03 +00:00
var msg = await ctx . Reply ( $"{Emojis.Warn} You already have a member in your system with the name \" { existingMember . NameFor ( ctx ) } \ " (`{existingMember.Hid}`). Do you want to rename this member to that name too?" ) ;
2020-02-01 12:03:02 +00:00
if ( ! await ctx . PromptYesNo ( msg ) ) throw new PKError ( "Member renaming cancelled." ) ;
}
// Rename the member
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch { Name = Partial < string > . Present ( newName ) } ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-02-01 12:03:02 +00:00
await ctx . Reply ( $"{Emojis.Success} Member renamed." ) ;
if ( newName . Contains ( " " ) ) await ctx . Reply ( $"{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." ) ;
2020-06-20 15:36:03 +00:00
if ( target . DisplayName ! = null ) await ctx . Reply ( $"{Emojis.Note} Note that this member has a display name set ({target.DisplayName}), and will be proxied using that name instead." ) ;
2020-02-01 12:03:02 +00:00
if ( ctx . Guild ! = null )
{
2020-06-13 14:03:57 +00:00
var memberGuildConfig = await _db . Execute ( c = > c . QueryOrInsertMemberGuildConfig ( ctx . Guild . Id , target . Id ) ) ;
2020-02-01 12:03:02 +00:00
if ( memberGuildConfig . DisplayName ! = null )
2020-06-20 15:36:03 +00:00
await ctx . Reply ( $"{Emojis.Note} Note that this member has a server name set ({memberGuildConfig.DisplayName}) in this server ({ctx.Guild.Name}), and will be proxied using that name here." ) ;
2020-02-01 12:03:02 +00:00
}
}
2020-03-04 17:13:36 +00:00
private void CheckEditMemberPermission ( Context ctx , PKMember target )
{
if ( target . System ! = ctx . System ? . Id ) throw Errors . NotOwnMemberError ;
}
2020-02-01 12:03:02 +00:00
2020-03-04 17:13:36 +00:00
private static bool MatchClear ( Context ctx ) = >
ctx . Match ( "clear" ) | | ctx . MatchFlag ( "c" , "clear" ) ;
2020-02-27 23:23:54 +00:00
2020-03-04 17:13:36 +00:00
public async Task Description ( Context ctx , PKMember target ) {
if ( MatchClear ( ctx ) )
2020-02-27 23:23:54 +00:00
{
2020-03-04 17:13:36 +00:00
CheckEditMemberPermission ( ctx , target ) ;
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch { Description = Partial < string > . Null ( ) } ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-03-04 17:13:36 +00:00
await ctx . Reply ( $"{Emojis.Success} Member description cleared." ) ;
}
else if ( ! ctx . HasNext ( ) )
{
2020-06-17 19:31:39 +00:00
if ( ! target . DescriptionPrivacy . CanAccess ( ctx . LookupContextFor ( target . System ) ) )
throw Errors . LookupNotAllowed ;
2020-02-27 23:23:54 +00:00
if ( target . Description = = null )
2020-03-04 17:13:36 +00:00
if ( ctx . System ? . Id = = target . System )
await ctx . Reply ( $"This member does not have a description set. To set one, type `pk;member {target.Hid} description <description>`." ) ;
2020-02-27 23:23:54 +00:00
else
await ctx . Reply ( "This member does not have a description set." ) ;
else if ( ctx . MatchFlag ( "r" , "raw" ) )
2020-06-20 15:36:03 +00:00
await ctx . Reply ( $"```\n{target.Description}\n```" ) ;
2020-02-27 23:23:54 +00:00
else
2020-04-24 19:50:28 +00:00
await ctx . Reply ( embed : new DiscordEmbedBuilder ( )
2020-02-27 23:23:54 +00:00
. WithTitle ( "Member description" )
. WithDescription ( target . Description )
2020-03-04 17:13:36 +00:00
. AddField ( "\u200B" , $"To print the description with formatting, type `pk;member {target.Hid} description -raw`."
+ ( ctx . System ? . Id = = target . System ? $" To clear it, type `pk;member {target.Hid} description -clear`." : "" ) )
2020-02-27 23:23:54 +00:00
. Build ( ) ) ;
}
2020-03-04 17:13:36 +00:00
else
{
CheckEditMemberPermission ( ctx , target ) ;
2020-02-27 23:23:54 +00:00
2020-03-04 17:13:36 +00:00
var description = ctx . RemainderOrNull ( ) . NormalizeLineEndSpacing ( ) ;
if ( description . IsLongerThan ( Limits . MaxDescriptionLength ) )
throw Errors . DescriptionTooLongError ( description . Length ) ;
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch { Description = Partial < string > . Present ( description ) } ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-06-29 12:15:30 +00:00
2020-03-04 17:13:36 +00:00
await ctx . Reply ( $"{Emojis.Success} Member description changed." ) ;
}
2020-02-01 12:03:02 +00:00
}
public async Task Pronouns ( Context ctx , PKMember target ) {
2020-03-04 17:13:36 +00:00
if ( MatchClear ( ctx ) )
{
CheckEditMemberPermission ( ctx , target ) ;
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch { Pronouns = Partial < string > . Null ( ) } ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-03-04 17:13:36 +00:00
await ctx . Reply ( $"{Emojis.Success} Member pronouns cleared." ) ;
}
else if ( ! ctx . HasNext ( ) )
{
2020-06-17 19:31:39 +00:00
if ( ! target . PronounPrivacy . CanAccess ( ctx . LookupContextFor ( target . System ) ) )
throw Errors . LookupNotAllowed ;
2020-03-04 17:13:36 +00:00
if ( target . Pronouns = = null )
if ( ctx . System ? . Id = = target . System )
await ctx . Reply ( $"This member does not have pronouns set. To set some, type `pk;member {target.Hid} pronouns <pronouns>`." ) ;
else
await ctx . Reply ( "This member does not have pronouns set." ) ;
else
2020-06-20 15:36:03 +00:00
await ctx . Reply ( $"**{target.NameFor(ctx)}**'s pronouns are **{target.Pronouns}**."
2020-03-04 17:13:36 +00:00
+ ( ctx . System ? . Id = = target . System ? $" To clear them, type `pk;member {target.Hid} pronouns -clear`." : "" ) ) ;
}
else
{
CheckEditMemberPermission ( ctx , target ) ;
2020-02-01 12:03:02 +00:00
2020-03-04 17:13:36 +00:00
var pronouns = ctx . RemainderOrNull ( ) . NormalizeLineEndSpacing ( ) ;
if ( pronouns . IsLongerThan ( Limits . MaxPronounsLength ) )
throw Errors . MemberPronounsTooLongError ( pronouns . Length ) ;
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch { Pronouns = Partial < string > . Present ( pronouns ) } ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-03-04 17:13:36 +00:00
await ctx . Reply ( $"{Emojis.Success} Member pronouns changed." ) ;
}
2020-02-01 12:03:02 +00:00
}
public async Task Color ( Context ctx , PKMember target )
{
var color = ctx . RemainderOrNull ( ) ;
2020-03-04 17:13:36 +00:00
if ( MatchClear ( ctx ) )
2020-02-01 12:03:02 +00:00
{
2020-03-04 17:13:36 +00:00
CheckEditMemberPermission ( ctx , target ) ;
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch { Color = Partial < string > . Null ( ) } ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-03-04 17:13:36 +00:00
await ctx . Reply ( $"{Emojis.Success} Member color cleared." ) ;
2020-02-01 12:03:02 +00:00
}
2020-03-04 17:13:36 +00:00
else if ( ! ctx . HasNext ( ) )
{
2020-06-17 19:51:40 +00:00
// if (!target.ColorPrivacy.CanAccess(ctx.LookupContextFor(target.System)))
// throw Errors.LookupNotAllowed;
2020-02-01 12:03:02 +00:00
2020-03-04 17:13:36 +00:00
if ( target . Color = = null )
if ( ctx . System ? . Id = = target . System )
await ctx . Reply (
$"This member does not have a color set. To set one, type `pk;member {target.Hid} color <color>`." ) ;
else
await ctx . Reply ( "This member does not have a color set." ) ;
else
2020-04-24 19:50:28 +00:00
await ctx . Reply ( embed : new DiscordEmbedBuilder ( )
2020-03-04 17:13:36 +00:00
. WithTitle ( "Member color" )
. WithColor ( target . Color . ToDiscordColor ( ) . Value )
2020-06-21 13:34:32 +00:00
. WithThumbnail ( $"https://fakeimg.pl/256x256/{target.Color}/?text=%20" )
2020-03-04 17:13:36 +00:00
. WithDescription ( $"This member's color is **#{target.Color}**."
+ ( ctx . System ? . Id = = target . System ? $" To clear it, type `pk;member {target.Hid} color -clear`." : "" ) )
. Build ( ) ) ;
}
else
{
CheckEditMemberPermission ( ctx , target ) ;
2020-02-01 12:03:02 +00:00
2020-03-04 17:13:36 +00:00
if ( color . StartsWith ( "#" ) ) color = color . Substring ( 1 ) ;
if ( ! Regex . IsMatch ( color , "^[0-9a-fA-F]{6}$" ) ) throw Errors . InvalidColorError ( color ) ;
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch { Color = Partial < string > . Present ( color . ToLowerInvariant ( ) ) } ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-03-04 17:13:36 +00:00
2020-04-24 19:50:28 +00:00
await ctx . Reply ( embed : new DiscordEmbedBuilder ( )
2020-03-04 17:13:36 +00:00
. WithTitle ( $"{Emojis.Success} Member color changed." )
2020-06-29 11:57:48 +00:00
. WithColor ( color . ToDiscordColor ( ) . Value )
2020-06-21 13:34:32 +00:00
. WithThumbnail ( $"https://fakeimg.pl/256x256/{target.Color}/?text=%20" )
2020-03-04 17:13:36 +00:00
. Build ( ) ) ;
}
2020-02-01 12:03:02 +00:00
}
public async Task Birthday ( Context ctx , PKMember target )
{
2020-03-04 17:13:36 +00:00
if ( MatchClear ( ctx ) )
{
CheckEditMemberPermission ( ctx , target ) ;
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch { Birthday = Partial < LocalDate ? > . Null ( ) } ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-03-04 17:13:36 +00:00
await ctx . Reply ( $"{Emojis.Success} Member birthdate cleared." ) ;
}
else if ( ! ctx . HasNext ( ) )
2020-02-01 12:03:02 +00:00
{
2020-06-17 19:31:39 +00:00
if ( ! target . BirthdayPrivacy . CanAccess ( ctx . LookupContextFor ( target . System ) ) )
throw Errors . LookupNotAllowed ;
2020-03-04 17:13:36 +00:00
if ( target . Birthday = = null )
await ctx . Reply ( "This member does not have a birthdate set."
+ ( ctx . System ? . Id = = target . System ? $" To set one, type `pk;member {target.Hid} birthdate <birthdate>`." : "" ) ) ;
else
await ctx . Reply ( $"This member's birthdate is **{target.BirthdayString}**."
+ ( ctx . System ? . Id = = target . System ? $" To clear it, type `pk;member {target.Hid} birthdate -clear`." : "" ) ) ;
}
else
{
CheckEditMemberPermission ( ctx , target ) ;
var birthdayStr = ctx . RemainderOrNull ( ) ;
var birthday = DateUtils . ParseDate ( birthdayStr , true ) ;
if ( birthday = = null ) throw Errors . BirthdayParseError ( birthdayStr ) ;
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch { Birthday = Partial < LocalDate ? > . Present ( birthday ) } ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-03-04 17:13:36 +00:00
await ctx . Reply ( $"{Emojis.Success} Member birthdate changed." ) ;
2020-02-01 12:03:02 +00:00
}
}
2020-03-04 17:13:36 +00:00
2020-04-24 19:50:28 +00:00
private async Task < DiscordEmbedBuilder > CreateMemberNameInfoEmbed ( Context ctx , PKMember target )
2020-03-04 17:13:36 +00:00
{
2020-06-18 15:08:36 +00:00
var lcx = ctx . LookupContextFor ( target ) ;
2020-03-04 17:13:36 +00:00
MemberGuildSettings memberGuildConfig = null ;
if ( ctx . Guild ! = null )
2020-06-13 14:03:57 +00:00
memberGuildConfig = await _db . Execute ( c = > c . QueryOrInsertMemberGuildConfig ( ctx . Guild . Id , target . Id ) ) ;
2020-02-01 12:03:02 +00:00
2020-04-24 19:50:28 +00:00
var eb = new DiscordEmbedBuilder ( ) . WithTitle ( $"Member names" )
2020-03-04 17:13:36 +00:00
. WithFooter ( $"Member ID: {target.Hid} | Active name in bold. Server name overrides display name, which overrides base name." ) ;
2020-02-01 12:03:02 +00:00
2020-03-04 17:13:36 +00:00
if ( target . DisplayName = = null & & memberGuildConfig ? . DisplayName = = null )
2020-06-18 15:08:36 +00:00
eb . AddField ( "Name" , $"**{target.NameFor(ctx)}**" ) ;
2020-03-04 17:13:36 +00:00
else
2020-06-18 15:08:36 +00:00
eb . AddField ( "Name" , target . NameFor ( ctx ) ) ;
if ( target . NamePrivacy . CanAccess ( lcx ) )
{
if ( target . DisplayName ! = null & & memberGuildConfig ? . DisplayName = = null )
eb . AddField ( "Display Name" , $"**{target.DisplayName}**" ) ;
else
eb . AddField ( "Display Name" , target . DisplayName ? ? "*(none)*" ) ;
}
2020-02-01 12:03:02 +00:00
if ( ctx . Guild ! = null )
{
2020-03-04 17:13:36 +00:00
if ( memberGuildConfig ? . DisplayName ! = null )
2020-06-20 15:36:03 +00:00
eb . AddField ( $"Server Name (in {ctx.Guild.Name})" , $"**{memberGuildConfig.DisplayName}**" ) ;
2020-03-04 17:13:36 +00:00
else
2020-06-20 15:36:03 +00:00
eb . AddField ( $"Server Name (in {ctx.Guild.Name})" , memberGuildConfig ? . DisplayName ? ? "*(none)*" ) ;
2020-02-01 12:03:02 +00:00
}
2020-03-04 17:13:36 +00:00
return eb ;
2020-02-01 12:03:02 +00:00
}
2020-03-04 17:13:36 +00:00
public async Task DisplayName ( Context ctx , PKMember target )
2020-02-01 12:03:02 +00:00
{
2020-03-04 17:13:36 +00:00
async Task PrintSuccess ( string text )
{
var successStr = text ;
if ( ctx . Guild ! = null )
{
2020-06-13 14:03:57 +00:00
var memberGuildConfig = await _db . Execute ( c = > c . QueryOrInsertMemberGuildConfig ( ctx . Guild . Id , target . Id ) ) ;
2020-03-04 17:13:36 +00:00
if ( memberGuildConfig . DisplayName ! = null )
2020-06-20 15:36:03 +00:00
successStr + = $" However, this member has a server name set in this server ({ctx.Guild.Name}), and will be proxied using that name, \" { memberGuildConfig . DisplayName } \ ", here." ;
2020-03-04 17:13:36 +00:00
}
await ctx . Reply ( successStr ) ;
}
2020-02-01 12:03:02 +00:00
2020-03-04 17:13:36 +00:00
if ( MatchClear ( ctx ) )
{
CheckEditMemberPermission ( ctx , target ) ;
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch { DisplayName = Partial < string > . Null ( ) } ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-06-20 15:36:03 +00:00
await PrintSuccess ( $"{Emojis.Success} Member display name cleared. This member will now be proxied using their member name \" { target . NameFor ( ctx ) } \ "." ) ;
2020-03-04 17:13:36 +00:00
}
else if ( ! ctx . HasNext ( ) )
{
// No perms check, display name isn't covered by member privacy
var eb = await CreateMemberNameInfoEmbed ( ctx , target ) ;
if ( ctx . System ? . Id = = target . System )
eb . WithDescription ( $"To change display name, type `pk;member {target.Hid} displayname <display name>`.\nTo clear it, type `pk;member {target.Hid} displayname -clear`." ) ;
await ctx . Reply ( embed : eb . Build ( ) ) ;
}
else
{
CheckEditMemberPermission ( ctx , target ) ;
var newDisplayName = ctx . RemainderOrNull ( ) ;
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch { DisplayName = Partial < string > . Present ( newDisplayName ) } ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-03-04 17:13:36 +00:00
2020-06-20 15:36:03 +00:00
await PrintSuccess ( $"{Emojis.Success} Member display name changed. This member will now be proxied using the name \" { newDisplayName } \ "." ) ;
2020-03-04 17:13:36 +00:00
}
}
public async Task ServerName ( Context ctx , PKMember target )
{
2020-02-01 12:03:02 +00:00
ctx . CheckGuildContext ( ) ;
2020-03-04 17:13:36 +00:00
if ( MatchClear ( ctx ) )
{
CheckEditMemberPermission ( ctx , target ) ;
2020-06-13 14:03:57 +00:00
await _db . Execute ( c = >
c . ExecuteAsync ( "update member_guild set display_name = null where member = @member and guild = @guild" ,
new { member = target . Id , guild = ctx . Guild . Id } ) ) ;
2020-02-01 12:03:02 +00:00
2020-03-04 17:13:36 +00:00
if ( target . DisplayName ! = null )
2020-06-20 15:36:03 +00:00
await ctx . Reply ( $"{Emojis.Success} Member server name cleared. This member will now be proxied using their global display name \" { target . DisplayName } \ " in this server ({ctx.Guild.Name})." ) ;
2020-03-04 17:13:36 +00:00
else
2020-06-20 15:36:03 +00:00
await ctx . Reply ( $"{Emojis.Success} Member server name cleared. This member will now be proxied using their member name \" { target . NameFor ( ctx ) } \ " in this server ({ctx.Guild.Name})." ) ;
2020-03-04 17:13:36 +00:00
}
else if ( ! ctx . HasNext ( ) )
{
// No perms check, server name isn't covered by member privacy
var eb = await CreateMemberNameInfoEmbed ( ctx , target ) ;
if ( ctx . System ? . Id = = target . System )
eb . WithDescription ( $"To change server name, type `pk;member {target.Hid} servername <server name>`.\nTo clear it, type `pk;member {target.Hid} servername -clear`." ) ;
await ctx . Reply ( embed : eb . Build ( ) ) ;
}
2020-02-01 12:03:02 +00:00
else
2020-03-04 17:13:36 +00:00
{
CheckEditMemberPermission ( ctx , target ) ;
var newServerName = ctx . RemainderOrNull ( ) ;
2020-06-13 14:03:57 +00:00
await _db . Execute ( c = >
2020-06-25 20:23:15 +00:00
c . ExecuteAsync ( "insert into member_guild(member, guild, display_name) values (@member, @guild, @newServerName) on conflict (member, guild) do update set display_name = @newServerName" ,
2020-06-13 14:03:57 +00:00
new { member = target . Id , guild = ctx . Guild . Id , newServerName } ) ) ;
2020-02-01 12:03:02 +00:00
2020-06-20 15:36:03 +00:00
await ctx . Reply ( $"{Emojis.Success} Member server name changed. This member will now be proxied using the name \" { newServerName } \ " in this server ({ctx.Guild.Name})." ) ;
2020-03-04 17:13:36 +00:00
}
2020-02-01 12:03:02 +00:00
}
public async Task KeepProxy ( Context ctx , PKMember target )
{
if ( ctx . System = = null ) throw Errors . NoSystemError ;
if ( target . System ! = ctx . System . Id ) throw Errors . NotOwnMemberError ;
bool newValue ;
if ( ctx . Match ( "on" , "enabled" , "true" , "yes" ) ) newValue = true ;
else if ( ctx . Match ( "off" , "disabled" , "false" , "no" ) ) newValue = false ;
else if ( ctx . HasNext ( ) ) throw new PKSyntaxError ( "You must pass either \"on\" or \"off\"." ) ;
2020-03-04 17:13:36 +00:00
else
{
if ( target . KeepProxy )
await ctx . Reply ( "This member has keepproxy **enabled**, which means proxy tags will be **included** in the resulting message when proxying." ) ;
else
await ctx . Reply ( "This member has keepproxy **disabled**, which means proxy tags will **not** be included in the resulting message when proxying." ) ;
return ;
} ;
2020-02-01 12:03:02 +00:00
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch { KeepProxy = Partial < bool > . Present ( newValue ) } ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-02-01 12:03:02 +00:00
if ( newValue )
await ctx . Reply ( $"{Emojis.Success} Member proxy tags will now be included in the resulting message when proxying." ) ;
else
await ctx . Reply ( $"{Emojis.Success} Member proxy tags will now not be included in the resulting message when proxying." ) ;
}
2020-06-18 15:08:36 +00:00
private DiscordEmbed CreatePrivacyEmbed ( Context ctx , PKMember member )
2020-06-17 21:06:49 +00:00
{
string PrivacyLevelString ( PrivacyLevel level ) = > level switch
{
PrivacyLevel . Private = > "**Private** (visible only when queried by you)" ,
PrivacyLevel . Public = > "**Public** (visible to everyone)" ,
_ = > throw new ArgumentOutOfRangeException ( nameof ( level ) , level , null )
} ;
var eb = new DiscordEmbedBuilder ( )
2020-06-18 15:08:36 +00:00
. WithTitle ( $"Current privacy settings for {member.NameFor(ctx)}" )
2020-06-17 21:06:49 +00:00
. AddField ( "Name (replaces name with display name if member has one)" , PrivacyLevelString ( member . NamePrivacy ) )
. AddField ( "Description" , PrivacyLevelString ( member . DescriptionPrivacy ) )
2020-06-20 14:00:50 +00:00
. AddField ( "Avatar" , PrivacyLevelString ( member . AvatarPrivacy ) )
2020-06-17 21:06:49 +00:00
. AddField ( "Birthday" , PrivacyLevelString ( member . BirthdayPrivacy ) )
. AddField ( "Pronouns" , PrivacyLevelString ( member . PronounPrivacy ) )
// .AddField("Color", PrivacyLevelString(target.ColorPrivacy))
. AddField ( "Meta (message count, last front, last message)" , PrivacyLevelString ( member . MetadataPrivacy ) )
. AddField ( "Visibility" , PrivacyLevelString ( member . MemberVisibility ) )
2020-06-20 14:00:50 +00:00
. WithDescription ( "To edit privacy settings, use the command:\n`pk;member <member> privacy <subject> <level>`\n\n- `subject` is one of `name`, `description`, `avatar`, `birthday`, `pronouns`, `created`, `messages`, `visibility`, or `all`\n- `level` is either `public` or `private`." ) ;
2020-06-17 21:06:49 +00:00
return eb . Build ( ) ;
}
2020-02-07 21:20:40 +00:00
public async Task Privacy ( Context ctx , PKMember target , PrivacyLevel ? newValueFromCommand )
2020-02-01 12:03:02 +00:00
{
if ( ctx . System = = null ) throw Errors . NoSystemError ;
if ( target . System ! = ctx . System . Id ) throw Errors . NotOwnMemberError ;
2020-06-17 19:31:39 +00:00
// Display privacy settings
if ( ! ctx . HasNext ( ) & & newValueFromCommand = = null )
2020-03-04 17:13:36 +00:00
{
2020-06-18 15:08:36 +00:00
await ctx . Reply ( embed : CreatePrivacyEmbed ( ctx , target ) ) ;
2020-03-04 17:13:36 +00:00
return ;
}
2020-06-20 14:10:36 +00:00
// Get guild settings (mostly for warnings and such)
MemberGuildSettings guildSettings = null ;
if ( ctx . Guild ! = null )
guildSettings = await _db . Execute ( c = > c . QueryOrInsertMemberGuildConfig ( ctx . Guild . Id , target . Id ) ) ;
2020-02-01 12:03:02 +00:00
2020-06-17 19:31:39 +00:00
// Set Privacy Settings
2020-06-17 21:06:49 +00:00
PrivacyLevel PopPrivacyLevel ( string subjectName )
2020-06-17 19:31:39 +00:00
{
if ( ctx . Match ( "public" , "show" , "shown" , "visible" ) )
return PrivacyLevel . Public ;
if ( ctx . Match ( "private" , "hide" , "hidden" ) )
return PrivacyLevel . Private ;
if ( ! ctx . HasNext ( ) )
2020-06-17 21:06:49 +00:00
throw new PKSyntaxError ( $"You must pass a privacy level for `{subjectName}` (`public` or `private`)" ) ;
2020-06-20 15:36:03 +00:00
throw new PKSyntaxError ( $"Invalid privacy level `{ctx.PopArgument()}` (must be `public` or `private`)." ) ;
2020-06-17 19:31:39 +00:00
}
2020-06-17 21:06:49 +00:00
// See if we have a subject given
PrivacyLevel newLevel ;
if ( PrivacyUtils . TryParseMemberPrivacy ( ctx . PeekArgument ( ) , out var subject ) )
2020-06-17 19:31:39 +00:00
{
2020-06-17 21:06:49 +00:00
// We peeked before, pop it now
ctx . PopArgument ( ) ;
// Read the privacy level from args
newLevel = PopPrivacyLevel ( subject . Name ( ) ) ;
// Set the level on the given subject
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch ( ) ;
patch . SetPrivacy ( subject , newLevel ) ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-06-17 21:06:49 +00:00
// Print response
var explanation = ( subject , newLevel ) switch
{
( MemberPrivacySubject . Name , PrivacyLevel . Private ) = > "This member's name is now hidden from other systems, and will be replaced by the member's display name." ,
( MemberPrivacySubject . Description , PrivacyLevel . Private ) = > "This member's description is now hidden from other systems." ,
2020-06-20 14:00:50 +00:00
( MemberPrivacySubject . Avatar , PrivacyLevel . Private ) = > "This member's avatar is now hidden from other systems." ,
2020-06-17 21:06:49 +00:00
( MemberPrivacySubject . Birthday , PrivacyLevel . Private ) = > "This member's birthday is now hidden from other systems." ,
( MemberPrivacySubject . Pronouns , PrivacyLevel . Private ) = > "This member's pronouns are now hidden from other systems." ,
( MemberPrivacySubject . Metadata , PrivacyLevel . Private ) = > "This member's metadata (eg. created timestamp, message count, etc) is now hidden from other systems." ,
( MemberPrivacySubject . Visibility , PrivacyLevel . Private ) = > "This member is now hidden from member lists." ,
( MemberPrivacySubject . Name , PrivacyLevel . Public ) = > "This member's name is no longer hidden from other systems." ,
( MemberPrivacySubject . Description , PrivacyLevel . Public ) = > "This member's description is no longer hidden from other systems." ,
2020-06-20 14:00:50 +00:00
( MemberPrivacySubject . Avatar , PrivacyLevel . Public ) = > "This member's avatar is no longer hidden from other systems." ,
2020-06-17 21:06:49 +00:00
( MemberPrivacySubject . Birthday , PrivacyLevel . Public ) = > "This member's birthday is no longer hidden from other systems." ,
( MemberPrivacySubject . Pronouns , PrivacyLevel . Public ) = > "This member's pronouns are no longer hidden other systems." ,
( MemberPrivacySubject . Metadata , PrivacyLevel . Public ) = > "This member's metadata (eg. created timestamp, message count, etc) is no longer hidden from other systems." ,
( MemberPrivacySubject . Visibility , PrivacyLevel . Public ) = > "This member is no longer hidden from member lists." ,
2020-06-18 15:34:03 +00:00
_ = > throw new InvalidOperationException ( $"Invalid subject/level tuple ({subject}, {newLevel})" )
2020-06-17 21:06:49 +00:00
} ;
2020-06-21 13:51:08 +00:00
await ctx . Reply ( $"{Emojis.Success} {target.NameFor(ctx)}'s {subject.Name()} has been set to **{newLevel.LevelName()}**. {explanation}" ) ;
2020-06-17 19:31:39 +00:00
}
2020-06-17 21:06:49 +00:00
else if ( ctx . Match ( "all" ) | | newValueFromCommand ! = null )
2020-06-17 19:31:39 +00:00
{
2020-06-17 21:06:49 +00:00
newLevel = newValueFromCommand ? ? PopPrivacyLevel ( "all" ) ;
2020-06-29 11:57:48 +00:00
var patch = new MemberPatch ( ) ;
patch . SetAllPrivacy ( newLevel ) ;
await _db . Execute ( conn = > conn . UpdateMember ( target . Id , patch ) ) ;
2020-06-17 21:06:49 +00:00
if ( newLevel = = PrivacyLevel . Private )
2020-06-21 13:51:08 +00:00
await ctx . Reply ( $"All {target.NameFor(ctx)}'s privacy settings have been set to **{newLevel.LevelName()}**. Other accounts will now see nothing on the member card." ) ;
2020-06-17 21:06:49 +00:00
else
2020-06-21 13:51:08 +00:00
await ctx . Reply ( $"All {target.NameFor(ctx)}'s privacy settings have been set to **{newLevel.LevelName()}**. Other accounts will now see everything on the member card." ) ;
2020-06-17 19:31:39 +00:00
}
2020-02-01 12:03:02 +00:00
else
2020-06-17 21:06:49 +00:00
{
2020-06-20 14:00:50 +00:00
var subjectList = "`name`, `description`, `avatar`, `birthday`, `pronouns`, `metadata`, `visibility`, or `all`" ;
2020-06-20 15:36:03 +00:00
throw new PKSyntaxError ( $"Invalid privacy subject `{ctx.PopArgument()}` (must be {subjectList})." ) ;
2020-06-17 21:06:49 +00:00
}
// Name privacy only works given a display name
if ( subject = = MemberPrivacySubject . Name & & newLevel = = PrivacyLevel . Private & & target . DisplayName = = null )
await ctx . Reply ( $"{Emojis.Warn} This member does not have a display name set, and name privacy **will not take effect**." ) ;
2020-06-20 14:10:36 +00:00
// Avatar privacy doesn't apply when proxying if no server avatar is set
if ( subject = = MemberPrivacySubject . Avatar & & newLevel = = PrivacyLevel . Private & &
guildSettings ? . AvatarUrl = = null )
await ctx . Reply ( $"{Emojis.Warn} This member does not have a server avatar set, so *proxying* will **still show the member avatar**. If you want to hide your avatar when proxying here, set a server avatar: `pk;member {target.Hid} serveravatar`" ) ;
2020-02-01 12:03:02 +00:00
}
public async Task Delete ( Context ctx , PKMember target )
{
if ( ctx . System = = null ) throw Errors . NoSystemError ;
if ( target . System ! = ctx . System . Id ) throw Errors . NotOwnMemberError ;
2020-06-20 15:36:03 +00:00
await ctx . Reply ( $"{Emojis.Warn} Are you sure you want to delete \" { target . NameFor ( ctx ) } \ "? If so, reply to this message with the member's ID (`{target.Hid}`). __***This cannot be undone!***__" ) ;
2020-02-01 12:03:02 +00:00
if ( ! await ctx . ConfirmWithReply ( target . Hid ) ) throw Errors . MemberDeleteCancelled ;
2020-06-29 11:57:48 +00:00
await _db . Execute ( conn = > conn . DeleteMember ( target . Id ) ) ;
2020-02-01 12:03:02 +00:00
await ctx . Reply ( $"{Emojis.Success} Member deleted." ) ;
}
}
}