2018-07-24 22:47:57 +02:00
|
|
|
import asyncio
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
2018-09-09 20:38:57 +02:00
|
|
|
import pluralkit.utils
|
2018-07-24 22:47:57 +02:00
|
|
|
from pluralkit.bot.commands import *
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger("pluralkit.commands")
|
|
|
|
|
|
2018-09-07 17:34:38 +02:00
|
|
|
|
|
|
|
|
async def import_tupperware(ctx: CommandContext):
|
2018-07-30 21:06:59 +02:00
|
|
|
tupperware_ids = ["431544605209788416", "433916057053560832"] # Main bot instance and Multi-Pals-specific fork
|
2018-09-07 17:34:38 +02:00
|
|
|
tupperware_members = [ctx.message.server.get_member(bot_id) for bot_id in tupperware_ids if
|
|
|
|
|
ctx.message.server.get_member(bot_id)]
|
2018-07-24 22:47:57 +02:00
|
|
|
|
2018-07-30 21:06:59 +02:00
|
|
|
# Check if there's any Tupperware bot on the server
|
|
|
|
|
if not tupperware_members:
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandError("This command only works in a server where the Tupperware bot is also present.")
|
2018-07-24 22:47:57 +02:00
|
|
|
|
2018-07-30 21:06:59 +02:00
|
|
|
# Make sure at least one of the bts have send/read permissions here
|
|
|
|
|
for bot_member in tupperware_members:
|
|
|
|
|
channel_permissions = ctx.message.channel.permissions_for(bot_member)
|
|
|
|
|
if channel_permissions.read_messages and channel_permissions.send_messages:
|
|
|
|
|
# If so, break out of the loop
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
# If no bots have permission (ie. loop doesn't break), throw error
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandError("This command only works in a channel where the Tupperware bot has read/send access.")
|
|
|
|
|
|
|
|
|
|
await ctx.reply(
|
|
|
|
|
embed=embeds.status("Please reply to this message with `tul!list` (or the server equivalent)."))
|
2018-07-24 22:47:57 +02:00
|
|
|
|
2018-07-30 21:06:59 +02:00
|
|
|
# Check to make sure the message is sent by Tupperware, and that the Tupperware response actually belongs to the correct user
|
2018-07-24 22:47:57 +02:00
|
|
|
def ensure_account(tw_msg):
|
2018-07-30 21:06:59 +02:00
|
|
|
if tw_msg.author not in tupperware_members:
|
|
|
|
|
return False
|
|
|
|
|
|
2018-07-24 22:47:57 +02:00
|
|
|
if not tw_msg.embeds:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
if not tw_msg.embeds[0]["title"]:
|
|
|
|
|
return False
|
2018-09-07 17:34:38 +02:00
|
|
|
|
|
|
|
|
return tw_msg.embeds[0]["title"].startswith(
|
|
|
|
|
"{}#{}".format(ctx.message.author.name, ctx.message.author.discriminator))
|
2018-07-24 22:47:57 +02:00
|
|
|
|
2018-09-01 19:41:35 +02:00
|
|
|
tupperware_page_embeds = []
|
2018-09-07 17:34:38 +02:00
|
|
|
|
2018-09-07 23:21:12 +02:00
|
|
|
tw_msg: discord.Message = await ctx.client.wait_for_message(channel=ctx.message.channel, timeout=60.0 * 5,
|
2018-09-07 17:34:38 +02:00
|
|
|
check=ensure_account)
|
2018-07-24 22:47:57 +02:00
|
|
|
if not tw_msg:
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandError("Tupperware import timed out.")
|
2018-09-01 19:41:35 +02:00
|
|
|
tupperware_page_embeds.append(tw_msg.embeds[0])
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
# Handle Tupperware pagination
|
|
|
|
|
def match_pagination():
|
|
|
|
|
pagination_match = re.search(r"\(page (\d+)/(\d+), \d+ total\)", tw_msg.embeds[0]["title"])
|
|
|
|
|
if not pagination_match:
|
|
|
|
|
return None
|
|
|
|
|
return int(pagination_match.group(1)), int(pagination_match.group(2))
|
|
|
|
|
|
|
|
|
|
pagination_match = match_pagination()
|
|
|
|
|
if pagination_match:
|
|
|
|
|
status_msg = await ctx.reply("Multi-page member list found. Please manually scroll through all the pages.")
|
|
|
|
|
current_page = 0
|
|
|
|
|
total_pages = 1
|
|
|
|
|
|
|
|
|
|
pages_found = {}
|
|
|
|
|
|
|
|
|
|
# Keep trying to read the embed with new pages
|
|
|
|
|
last_found_time = datetime.utcnow()
|
|
|
|
|
while len(pages_found) < total_pages:
|
|
|
|
|
new_page, total_pages = match_pagination()
|
|
|
|
|
|
|
|
|
|
# Put the found page in the pages dict
|
|
|
|
|
pages_found[new_page] = dict(tw_msg.embeds[0])
|
|
|
|
|
|
|
|
|
|
# If this isn't the same page as last check, edit the status message
|
|
|
|
|
if new_page != current_page:
|
|
|
|
|
last_found_time = datetime.utcnow()
|
2018-09-07 17:34:38 +02:00
|
|
|
await ctx.client.edit_message(status_msg,
|
|
|
|
|
"Multi-page member list found. Please manually scroll through all the pages. Read {}/{} pages.".format(
|
|
|
|
|
len(pages_found), total_pages))
|
2018-07-24 22:47:57 +02:00
|
|
|
current_page = new_page
|
|
|
|
|
|
|
|
|
|
# And sleep a bit to prevent spamming the CPU
|
|
|
|
|
await asyncio.sleep(0.25)
|
|
|
|
|
|
|
|
|
|
# Make sure it doesn't spin here for too long, time out after 30 seconds since last new page
|
|
|
|
|
if (datetime.utcnow() - last_found_time).seconds > 30:
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandError("Pagination scan timed out.")
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
# Now that we've got all the pages, put them in the embeds list
|
|
|
|
|
# Make sure to erase the original one we put in above too
|
2018-09-01 19:41:35 +02:00
|
|
|
tupperware_page_embeds = list([embed for page, embed in sorted(pages_found.items(), key=lambda x: x[0])])
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
# Also edit the status message to indicate we're now importing, and it may take a while because there's probably a lot of members
|
|
|
|
|
await ctx.client.edit_message(status_msg, "All pages read. Now importing...")
|
|
|
|
|
|
|
|
|
|
logger.debug("Importing from Tupperware...")
|
|
|
|
|
|
|
|
|
|
# Create new (nameless) system if there isn't any registered
|
2018-09-07 23:03:05 +02:00
|
|
|
system = await ctx.get_system()
|
2018-07-24 22:47:57 +02:00
|
|
|
if system is None:
|
2018-09-09 20:38:57 +02:00
|
|
|
hid = pluralkit.utils.generate_hid()
|
2018-07-24 22:47:57 +02:00
|
|
|
logger.debug("Creating new system (hid={})...".format(hid))
|
|
|
|
|
system = await db.create_system(ctx.conn, system_name=None, system_hid=hid)
|
2018-07-31 01:50:11 +02:00
|
|
|
await db.link_account(ctx.conn, system_id=system.id, account_id=ctx.message.author.id)
|
2018-07-24 22:47:57 +02:00
|
|
|
|
2018-09-01 19:41:35 +02:00
|
|
|
for embed in tupperware_page_embeds:
|
2018-07-24 22:47:57 +02:00
|
|
|
for field in embed["fields"]:
|
|
|
|
|
name = field["name"]
|
|
|
|
|
lines = field["value"].split("\n")
|
|
|
|
|
|
|
|
|
|
member_prefix = None
|
|
|
|
|
member_suffix = None
|
|
|
|
|
member_avatar = None
|
|
|
|
|
member_birthdate = None
|
|
|
|
|
member_description = None
|
|
|
|
|
|
|
|
|
|
# Read the message format line by line
|
|
|
|
|
for line in lines:
|
|
|
|
|
if line.startswith("Brackets:"):
|
|
|
|
|
brackets = line[len("Brackets: "):]
|
|
|
|
|
member_prefix = brackets[:brackets.index("text")].strip() or None
|
2018-09-07 17:34:38 +02:00
|
|
|
member_suffix = brackets[brackets.index("text") + 4:].strip() or None
|
2018-07-24 22:47:57 +02:00
|
|
|
elif line.startswith("Avatar URL: "):
|
|
|
|
|
url = line[len("Avatar URL: "):]
|
|
|
|
|
member_avatar = url
|
|
|
|
|
elif line.startswith("Birthday: "):
|
|
|
|
|
bday_str = line[len("Birthday: "):]
|
|
|
|
|
bday = datetime.strptime(bday_str, "%a %b %d %Y")
|
|
|
|
|
if bday:
|
|
|
|
|
member_birthdate = bday.date()
|
|
|
|
|
elif line.startswith("Total messages sent: ") or line.startswith("Tag: "):
|
|
|
|
|
# Ignore this, just so it doesn't catch as the description
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
member_description = line
|
|
|
|
|
|
|
|
|
|
# Read by name - TW doesn't allow name collisions so we're safe here (prevents dupes)
|
|
|
|
|
existing_member = await db.get_member_by_name(ctx.conn, system_id=system.id, member_name=name)
|
|
|
|
|
if not existing_member:
|
|
|
|
|
# Or create a new member
|
2018-09-09 20:38:57 +02:00
|
|
|
hid = pluralkit.utils.generate_hid()
|
2018-07-24 22:47:57 +02:00
|
|
|
logger.debug("Creating new member {} (hid={})...".format(name, hid))
|
2018-09-07 17:34:38 +02:00
|
|
|
existing_member = await db.create_member(ctx.conn, system_id=system.id, member_name=name,
|
|
|
|
|
member_hid=hid)
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
# Save the new stuff in the DB
|
|
|
|
|
logger.debug("Updating fields...")
|
|
|
|
|
await db.update_member_field(ctx.conn, member_id=existing_member.id, field="prefix", value=member_prefix)
|
|
|
|
|
await db.update_member_field(ctx.conn, member_id=existing_member.id, field="suffix", value=member_suffix)
|
2018-09-07 17:34:38 +02:00
|
|
|
await db.update_member_field(ctx.conn, member_id=existing_member.id, field="avatar_url",
|
|
|
|
|
value=member_avatar)
|
|
|
|
|
await db.update_member_field(ctx.conn, member_id=existing_member.id, field="birthday",
|
|
|
|
|
value=member_birthdate)
|
|
|
|
|
await db.update_member_field(ctx.conn, member_id=existing_member.id, field="description",
|
|
|
|
|
value=member_description)
|
|
|
|
|
|
|
|
|
|
return CommandSuccess(
|
|
|
|
|
"System information imported. Try using `pk;system` now.\nYou should probably remove your members from Tupperware to avoid double-posting.")
|