2018-11-30 21:42:01 +01:00
import discord
2019-03-08 16:07:05 +01:00
import math
2018-09-16 19:36:50 +02:00
import humanize
2019-03-08 14:48:33 +01:00
from typing import Tuple , List
2018-09-01 19:41:35 +02:00
2018-12-05 11:44:10 +01:00
from pluralkit import db
2018-09-16 19:36:50 +02:00
from pluralkit . bot . utils import escape
from pluralkit . member import Member
2018-10-11 12:54:40 +02:00
from pluralkit . switch import Switch
2018-09-16 19:36:50 +02:00
from pluralkit . system import System
2018-12-05 11:44:10 +01:00
from pluralkit . utils import get_fronters , display_relative
2018-09-16 19:36:50 +02:00
2018-11-30 21:42:01 +01:00
2018-11-23 21:55:47 +01:00
def truncate_field_name ( s : str ) - > str :
return s [ : 256 ]
2018-11-30 21:42:01 +01:00
2018-11-23 21:55:47 +01:00
def truncate_field_body ( s : str ) - > str :
2019-03-10 22:52:43 +01:00
if len ( s ) > 1024 :
return s [ : 1024 - 3 ] + " ... "
return s
2018-11-23 21:55:47 +01:00
2018-11-30 21:42:01 +01:00
2018-11-23 21:55:47 +01:00
def truncate_description ( s : str ) - > str :
return s [ : 2048 ]
2018-11-30 21:42:01 +01:00
2019-03-23 21:13:43 +09:30
def truncate_description_list ( s : str ) - > str :
if len ( s ) > 512 :
return s [ : 512 - 45 ] + " ... "
return s
2018-11-23 21:55:47 +01:00
def truncate_title ( s : str ) - > str :
return s [ : 256 ]
2018-09-01 19:41:35 +02:00
2018-09-15 14:52:24 +02:00
def success ( text : str ) - > discord . Embed :
2018-09-01 19:41:35 +02:00
embed = discord . Embed ( )
2018-11-23 21:55:47 +01:00
embed . description = truncate_description ( text )
2018-09-01 19:41:35 +02:00
embed . colour = discord . Colour . green ( )
return embed
2018-09-15 14:52:24 +02:00
def error ( text : str , help : Tuple [ str , str ] = None ) - > discord . Embed :
2018-09-01 19:41:35 +02:00
embed = discord . Embed ( )
2018-11-30 21:42:01 +01:00
embed . description = truncate_description ( text )
2018-09-01 19:41:35 +02:00
embed . colour = discord . Colour . dark_red ( )
if help :
help_title , help_text = help
2018-11-23 21:55:47 +01:00
embed . add_field ( name = truncate_field_name ( help_title ) , value = truncate_field_body ( help_text ) )
2018-09-01 19:41:35 +02:00
return embed
2018-09-15 14:52:24 +02:00
def status ( text : str ) - > discord . Embed :
2018-09-01 19:41:35 +02:00
embed = discord . Embed ( )
2018-11-23 21:55:47 +01:00
embed . description = truncate_description ( text )
2018-09-01 19:41:35 +02:00
embed . colour = discord . Colour . blue ( )
2018-09-15 14:52:24 +02:00
return embed
2018-09-16 13:46:22 +02:00
2018-12-05 11:44:10 +01:00
def exception_log ( message_content , author_name , author_discriminator , author_id , server_id ,
channel_id ) - > discord . Embed :
2018-09-15 14:52:24 +02:00
embed = discord . Embed ( )
embed . colour = discord . Colour . dark_red ( )
2018-11-23 21:55:47 +01:00
embed . title = truncate_title ( message_content )
2018-09-15 14:52:24 +02:00
2018-10-27 23:30:12 +02:00
embed . set_footer ( text = " Sender: {} # {} ( {} ) | Server: {} | Channel: {} " . format (
author_name , author_discriminator , author_id ,
2018-09-15 14:52:24 +02:00
server_id if server_id else " (DMs) " ,
channel_id
) )
2018-09-16 19:36:50 +02:00
return embed
2019-03-08 14:48:33 +01:00
async def system_card ( conn , client : discord . Client , system : System , is_own_system : bool = True ) - > discord . Embed :
2018-09-16 19:36:50 +02:00
card = discord . Embed ( )
card . colour = discord . Colour . blue ( )
if system . name :
2018-11-23 21:55:47 +01:00
card . title = truncate_title ( system . name )
2018-09-16 19:36:50 +02:00
if system . avatar_url :
card . set_thumbnail ( url = system . avatar_url )
if system . tag :
2018-11-23 21:55:47 +01:00
card . add_field ( name = " Tag " , value = truncate_field_body ( system . tag ) )
2018-09-16 19:36:50 +02:00
fronters , switch_time = await get_fronters ( conn , system . id )
if fronters :
names = " , " . join ( [ member . name for member in fronters ] )
fronter_val = " {} (for {} ) " . format ( names , humanize . naturaldelta ( switch_time ) )
2018-12-05 11:44:10 +01:00
card . add_field ( name = " Current fronter " if len ( fronters ) == 1 else " Current fronters " ,
value = truncate_field_body ( fronter_val ) )
2018-09-16 19:36:50 +02:00
account_names = [ ]
2018-09-16 19:43:13 +02:00
for account_id in await system . get_linked_account_ids ( conn ) :
2018-10-27 23:30:12 +02:00
account = await client . get_user_info ( account_id )
2018-09-16 19:36:50 +02:00
account_names . append ( " {} # {} " . format ( account . name , account . discriminator ) )
2018-09-16 19:43:13 +02:00
2018-11-23 21:55:47 +01:00
card . add_field ( name = " Linked accounts " , value = truncate_field_body ( " \n " . join ( account_names ) ) )
2018-09-16 19:36:50 +02:00
if system . description :
card . add_field ( name = " Description " ,
2018-11-23 21:55:47 +01:00
value = truncate_field_body ( system . description ) , inline = False )
2018-09-16 19:36:50 +02:00
2019-04-13 06:24:42 -04:00
card . add_field ( name = " Members " , value = " *See `pk;system {0} list`for the short list, or `pk;system {0} list full` for the detailed list* " . format ( system . hid ) if not is_own_system else " *See `pk;system list` for the short list, or `pk;system list full` for the detailed list* " )
2018-09-16 19:36:50 +02:00
card . set_footer ( text = " System ID: {} " . format ( system . hid ) )
return card
async def member_card ( conn , member : Member ) - > discord . Embed :
2018-09-16 19:43:13 +02:00
system = await member . fetch_system ( conn )
2018-09-16 19:36:50 +02:00
card = discord . Embed ( )
card . colour = discord . Colour . blue ( )
name_and_system = member . name
if system . name :
name_and_system + = " ( {} ) " . format ( system . name )
2018-11-23 21:55:47 +01:00
card . set_author ( name = truncate_field_name ( name_and_system ) , icon_url = member . avatar_url or discord . Embed . Empty )
2018-09-16 19:36:50 +02:00
if member . avatar_url :
card . set_thumbnail ( url = member . avatar_url )
if member . color :
card . colour = int ( member . color , 16 )
if member . birthday :
2019-03-09 12:56:07 +01:00
card . add_field ( name = " Birthdate " , value = member . birthday_string ( ) )
2018-09-16 19:36:50 +02:00
if member . pronouns :
2018-11-23 21:55:47 +01:00
card . add_field ( name = " Pronouns " , value = truncate_field_body ( member . pronouns ) )
2018-09-16 19:36:50 +02:00
2018-09-16 19:43:13 +02:00
message_count = await member . message_count ( conn )
2018-09-16 19:36:50 +02:00
if message_count > 0 :
card . add_field ( name = " Message Count " , value = str ( message_count ) , inline = True )
if member . prefix or member . suffix :
prefix = member . prefix or " "
suffix = member . suffix or " "
card . add_field ( name = " Proxy Tags " ,
2018-11-23 21:55:47 +01:00
value = truncate_field_body ( " {} text {} " . format ( prefix , suffix ) ) )
2018-09-16 19:36:50 +02:00
if member . description :
card . add_field ( name = " Description " ,
2018-11-23 21:55:47 +01:00
value = truncate_field_body ( member . description ) , inline = False )
2018-09-16 19:36:50 +02:00
card . set_footer ( text = " System ID: {} | Member ID: {} " . format ( system . hid , member . hid ) )
2018-10-11 12:54:40 +02:00
return card
2018-12-18 20:11:04 +01:00
async def front_status ( ctx : " CommandContext " , switch : Switch ) - > discord . Embed :
2018-10-11 12:54:40 +02:00
if switch :
embed = status ( " " )
2018-12-18 20:11:04 +01:00
fronter_names = [ member . name for member in await switch . fetch_members ( ctx . conn ) ]
2018-10-11 12:54:40 +02:00
if len ( fronter_names ) == 0 :
embed . add_field ( name = " Current fronter " , value = " (no fronter) " )
elif len ( fronter_names ) == 1 :
2018-11-23 21:55:47 +01:00
embed . add_field ( name = " Current fronter " , value = truncate_field_body ( fronter_names [ 0 ] ) )
2018-10-11 12:54:40 +02:00
else :
2018-11-23 21:55:47 +01:00
embed . add_field ( name = " Current fronters " , value = truncate_field_body ( " , " . join ( fronter_names ) ) )
2018-10-11 12:54:40 +02:00
if switch . timestamp :
embed . add_field ( name = " Since " ,
2018-12-18 19:38:53 +01:00
value = " {} ( {} ) " . format ( ctx . format_time ( switch . timestamp ) ,
2018-12-05 11:44:10 +01:00
display_relative ( switch . timestamp ) ) )
2018-10-11 12:54:40 +02:00
else :
embed = error ( " No switches logged. " )
return embed
2018-12-05 11:44:10 +01:00
async def get_message_contents ( client : discord . Client , channel_id : int , message_id : int ) :
channel = client . get_channel ( channel_id )
if channel :
try :
original_message = await channel . get_message ( message_id )
return original_message . content or None
except ( discord . errors . Forbidden , discord . errors . NotFound ) :
pass
return None
async def message_card ( client : discord . Client , message : db . MessageInfo ) :
# Get the original sender of the messages
try :
original_sender = await client . get_user_info ( message . sender )
except discord . NotFound :
# Account was since deleted - rare but we're handling it anyway
original_sender = None
embed = discord . Embed ( )
embed . timestamp = discord . utils . snowflake_time ( message . mid )
embed . colour = discord . Colour . blue ( )
if message . system_name :
system_value = " {} (` {} `) " . format ( message . system_name , message . system_hid )
else :
system_value = " ` {} ` " . format ( message . system_hid )
embed . add_field ( name = " System " , value = system_value )
embed . add_field ( name = " Member " , value = " {} (` {} `) " . format ( message . name , message . hid ) )
if original_sender :
sender_name = " {} # {} " . format ( original_sender . name , original_sender . discriminator )
else :
sender_name = " (deleted account {} ) " . format ( message . sender )
embed . add_field ( name = " Sent by " , value = sender_name )
message_content = await get_message_contents ( client , message . channel , message . mid )
embed . description = message_content or " (unknown, message deleted) "
embed . set_author ( name = message . name , icon_url = message . avatar_url or discord . Embed . Empty )
return embed
2018-12-10 20:09:35 +01:00
def help_footer_embed ( ) - > discord . Embed :
embed = discord . Embed ( )
embed . set_footer ( text = " By @Ske#6201 | GitHub: https://github.com/xSke/PluralKit/ " )
return embed
2019-03-08 14:48:33 +01:00
2019-04-09 22:08:27 +02:00
# TODO: merge these somehow, they're very similar
2019-04-09 15:36:04 -04:00
def member_list_short ( system : System , all_members : List [ Member ] , current_page : int , page_size : int ) :
page_count = int ( math . ceil ( len ( all_members ) / page_size ) )
title = " "
if len ( all_members ) > page_size :
title + = " [ {} / {} ] " . format ( current_page + 1 , page_count )
if system . name :
title + = " Members of {} (` {} `) " . format ( system . name , system . hid )
else :
title + = " Members of ` {} ` " . format ( system . hid )
embed = discord . Embed ( )
embed . title = title
2019-04-09 22:08:27 +02:00
desc = " "
2019-04-09 15:36:04 -04:00
for member in all_members [ current_page * page_size : current_page * page_size + page_size ] :
2019-04-09 22:08:27 +02:00
if member . prefix or member . suffix :
2019-04-09 22:12:49 +02:00
desc + = " [` {} `] ** {} ** *( {} text {} )* \n " . format ( member . hid , member . name , member . prefix or " " , member . suffix or " " )
2019-04-09 22:08:27 +02:00
else :
2019-04-09 22:12:49 +02:00
desc + = " [` {} `] ** {} ** \n " . format ( member . hid , member . name )
2019-04-09 22:08:27 +02:00
embed . description = desc
2019-04-09 15:36:04 -04:00
return embed
def member_list_full ( system : System , all_members : List [ Member ] , current_page : int , page_size : int ) :
2019-03-08 17:24:16 +01:00
page_count = int ( math . ceil ( len ( all_members ) / page_size ) )
2019-03-08 14:48:33 +01:00
title = " "
if len ( all_members ) > page_size :
title + = " [ {} / {} ] " . format ( current_page + 1 , page_count )
if system . name :
title + = " Members of {} (` {} `) " . format ( system . name , system . hid )
else :
title + = " Members of ` {} ` " . format ( system . hid )
embed = discord . Embed ( )
embed . title = title
for member in all_members [ current_page * page_size : current_page * page_size + page_size ] :
2019-03-08 17:24:16 +01:00
member_description = " **ID**: {} \n " . format ( member . hid )
if member . birthday :
2019-03-09 12:56:07 +01:00
member_description + = " **Birthday:** {} \n " . format ( member . birthday_string ( ) )
2019-03-08 17:24:16 +01:00
if member . pronouns :
member_description + = " **Pronouns:** {} \n " . format ( member . pronouns )
2019-03-23 17:42:18 +01:00
if member . description :
if len ( member . description ) > 512 :
member_description + = " \n " + truncate_description_list ( member . description ) + " \n " + " Type `pk;member {} ` for full description. " . format ( member . hid )
else :
member_description + = " \n " + member . description
2019-03-08 17:24:16 +01:00
2019-03-10 22:52:43 +01:00
embed . add_field ( name = member . name , value = truncate_field_body ( member_description ) or " \u200B " , inline = False )
2019-03-23 21:13:43 +09:30
return embed