2018-07-24 22:47:57 +02:00
|
|
|
import dateparser
|
|
|
|
|
import humanize
|
2018-09-07 17:34:38 +02:00
|
|
|
from datetime import datetime, timezone
|
|
|
|
|
from typing import List
|
2018-07-24 22:47:57 +02:00
|
|
|
|
2018-08-02 00:36:50 +02:00
|
|
|
import pluralkit.utils
|
2018-09-07 17:34:38 +02:00
|
|
|
from pluralkit.bot import help
|
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 switch_member(ctx: CommandContext):
|
|
|
|
|
system = await ctx.ensure_system()
|
|
|
|
|
|
|
|
|
|
if not ctx.has_next():
|
|
|
|
|
return CommandError("You must pass at least one member name or ID to register a switch to.",
|
|
|
|
|
help=help.switch_register)
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
members: List[Member] = []
|
2018-09-07 17:34:38 +02:00
|
|
|
for member_name in ctx.remaining().split(" "):
|
2018-07-24 22:47:57 +02:00
|
|
|
# Find the member
|
2018-09-07 17:34:38 +02:00
|
|
|
member = await utils.get_member_fuzzy(ctx.conn, system.id, member_name)
|
2018-07-24 22:47:57 +02:00
|
|
|
if not member:
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandError("Couldn't find member \"{}\".".format(member_name))
|
2018-07-24 22:47:57 +02:00
|
|
|
members.append(member)
|
|
|
|
|
|
|
|
|
|
# Compare requested switch IDs and existing fronter IDs to check for existing switches
|
|
|
|
|
# Lists, because order matters, it makes sense to just swap fronters
|
|
|
|
|
member_ids = [member.id for member in members]
|
2018-09-07 17:34:38 +02:00
|
|
|
fronter_ids = (await pluralkit.utils.get_fronter_ids(ctx.conn, system.id))[0]
|
2018-07-24 22:47:57 +02:00
|
|
|
if member_ids == fronter_ids:
|
|
|
|
|
if len(members) == 1:
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandError("{} is already fronting.".format(members[0].name))
|
|
|
|
|
return CommandError("Members {} are already fronting.".format(", ".join([m.name for m in members])))
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
# Also make sure there aren't any duplicates
|
|
|
|
|
if len(set(member_ids)) != len(member_ids):
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandError("Duplicate members in member list.")
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
# Log the switch
|
|
|
|
|
async with ctx.conn.transaction():
|
2018-09-07 17:34:38 +02:00
|
|
|
switch_id = await db.add_switch(ctx.conn, system_id=system.id)
|
2018-07-24 22:47:57 +02:00
|
|
|
for member in members:
|
|
|
|
|
await db.add_switch_member(ctx.conn, switch_id=switch_id, member_id=member.id)
|
|
|
|
|
|
|
|
|
|
if len(members) == 1:
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandSuccess("Switch registered. Current fronter is now {}.".format(members[0].name))
|
2018-07-24 22:47:57 +02:00
|
|
|
else:
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandSuccess(
|
|
|
|
|
"Switch registered. Current fronters are now {}.".format(", ".join([m.name for m in members])))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def switch_out(ctx: CommandContext):
|
|
|
|
|
system = await ctx.ensure_system()
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
# Get current fronters
|
2018-09-07 17:34:38 +02:00
|
|
|
fronters, _ = await pluralkit.utils.get_fronter_ids(ctx.conn, system_id=system.id)
|
2018-07-24 22:47:57 +02:00
|
|
|
if not fronters:
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandError("There's already no one in front.")
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
# Log it, and don't log any members
|
2018-09-07 17:34:38 +02:00
|
|
|
await db.add_switch(ctx.conn, system_id=system.id)
|
|
|
|
|
return CommandSuccess("Switch-out registered.")
|
|
|
|
|
|
2018-07-24 22:47:57 +02:00
|
|
|
|
2018-09-07 17:34:38 +02:00
|
|
|
async def switch_move(ctx: CommandContext):
|
|
|
|
|
system = await ctx.ensure_system()
|
|
|
|
|
if not ctx.has_next():
|
|
|
|
|
return CommandError("You must pass a time to move the switch to.", help=help.switch_move)
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
# Parse the time to move to
|
2018-09-07 17:34:38 +02:00
|
|
|
new_time = dateparser.parse(ctx.remaining(), languages=["en"], settings={
|
2018-07-24 22:47:57 +02:00
|
|
|
"TO_TIMEZONE": "UTC",
|
|
|
|
|
"RETURN_AS_TIMEZONE_AWARE": False
|
|
|
|
|
})
|
|
|
|
|
if not new_time:
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandError("'{}' can't be parsed as a valid time.".format(ctx.remaining()), help=help.switch_move)
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
# Make sure the time isn't in the future
|
2018-09-07 17:34:38 +02:00
|
|
|
if new_time > datetime.utcnow():
|
|
|
|
|
return CommandError("Can't move switch to a time in the future.", help=help.switch_move)
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
# Make sure it all runs in a big transaction for atomicity
|
|
|
|
|
async with ctx.conn.transaction():
|
|
|
|
|
# Get the last two switches to make sure the switch to move isn't before the second-last switch
|
2018-09-07 17:34:38 +02:00
|
|
|
last_two_switches = await pluralkit.utils.get_front_history(ctx.conn, system.id, count=2)
|
2018-07-24 22:47:57 +02:00
|
|
|
if len(last_two_switches) == 0:
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandError("There are no registered switches for this system.")
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
last_timestamp, last_fronters = last_two_switches[0]
|
|
|
|
|
if len(last_two_switches) > 1:
|
|
|
|
|
second_last_timestamp, _ = last_two_switches[1]
|
|
|
|
|
|
|
|
|
|
if new_time < second_last_timestamp:
|
2018-09-07 17:34:38 +02:00
|
|
|
time_str = humanize.naturaltime(pluralkit.utils.fix_time(second_last_timestamp))
|
|
|
|
|
return CommandError(
|
|
|
|
|
"Can't move switch to before last switch time ({}), as it would cause conflicts.".format(time_str))
|
|
|
|
|
|
2018-07-24 22:47:57 +02:00
|
|
|
# Display the confirmation message w/ humanized times
|
|
|
|
|
members = ", ".join([member.name for member in last_fronters]) or "nobody"
|
|
|
|
|
last_absolute = last_timestamp.isoformat(sep=" ", timespec="seconds")
|
2018-09-07 17:34:38 +02:00
|
|
|
last_relative = humanize.naturaltime(pluralkit.utils.fix_time(last_timestamp))
|
2018-07-24 22:47:57 +02:00
|
|
|
new_absolute = new_time.isoformat(sep=" ", timespec="seconds")
|
2018-09-07 17:34:38 +02:00
|
|
|
new_relative = humanize.naturaltime(pluralkit.utils.fix_time(new_time))
|
|
|
|
|
embed = embeds.status(
|
|
|
|
|
"This will move the latest switch ({}) from {} ({}) to {} ({}). Is this OK?".format(members, last_absolute,
|
|
|
|
|
last_relative,
|
|
|
|
|
new_absolute,
|
|
|
|
|
new_relative))
|
|
|
|
|
|
2018-07-24 22:47:57 +02:00
|
|
|
# Await and handle confirmation reactions
|
|
|
|
|
confirm_msg = await ctx.reply(embed=embed)
|
|
|
|
|
await ctx.client.add_reaction(confirm_msg, "✅")
|
|
|
|
|
await ctx.client.add_reaction(confirm_msg, "❌")
|
|
|
|
|
|
2018-09-07 17:34:38 +02:00
|
|
|
reaction = await ctx.client.wait_for_reaction(emoji=["✅", "❌"], message=confirm_msg, user=ctx.message.author,
|
2018-09-07 23:21:12 +02:00
|
|
|
timeout=60.0 * 5)
|
2018-07-24 22:47:57 +02:00
|
|
|
if not reaction:
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandError("Switch move timed out.")
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
if reaction.reaction.emoji == "❌":
|
2018-09-07 17:34:38 +02:00
|
|
|
return CommandError("Switch move cancelled.")
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
# DB requires the actual switch ID which our utility method above doesn't return, do this manually
|
2018-09-07 17:34:38 +02:00
|
|
|
switch_id = (await db.front_history(ctx.conn, system.id, count=1))[0]["id"]
|
2018-07-24 22:47:57 +02:00
|
|
|
|
|
|
|
|
# Change the switch in the DB
|
2018-09-07 17:34:38 +02:00
|
|
|
await db.move_last_switch(ctx.conn, system.id, switch_id, new_time)
|
|
|
|
|
return CommandSuccess("Switch moved.")
|