Add system member list command
This commit is contained in:
parent
aad5a8b417
commit
942f7cd0ab
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@ -9,8 +9,8 @@
|
|||||||
"type": "python",
|
"type": "python",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceRoot}/src/bot_main.py",
|
"program": "${workspaceRoot}/src/bot_main.py",
|
||||||
"envFile": "${workspaceFolder}/.env",
|
"args": ["${workspaceRoot}/pluralkit.conf"],
|
||||||
"console": "integratedTerminal"
|
"console": "integratedTerminal",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -42,6 +42,9 @@ class CommandError(Exception):
|
|||||||
|
|
||||||
|
|
||||||
class CommandContext:
|
class CommandContext:
|
||||||
|
client: discord.Client
|
||||||
|
message: discord.Message
|
||||||
|
|
||||||
def __init__(self, client: discord.Client, message: discord.Message, conn, args: str, system: Optional[System]):
|
def __init__(self, client: discord.Client, message: discord.Message, conn, args: str, system: Optional[System]):
|
||||||
self.client = client
|
self.client = client
|
||||||
self.message = message
|
self.message = message
|
||||||
|
@ -39,6 +39,8 @@ async def system_root(ctx: CommandContext):
|
|||||||
await system_timezone(ctx)
|
await system_timezone(ctx)
|
||||||
elif ctx.match("set"):
|
elif ctx.match("set"):
|
||||||
await system_set(ctx)
|
await system_set(ctx)
|
||||||
|
elif ctx.match("list") or ctx.match("members"):
|
||||||
|
await system_list(ctx, await ctx.ensure_system())
|
||||||
elif not ctx.has_next():
|
elif not ctx.has_next():
|
||||||
# (no argument, command ends here, default to showing own system)
|
# (no argument, command ends here, default to showing own system)
|
||||||
await system_info(ctx, await ctx.ensure_system())
|
await system_info(ctx, await ctx.ensure_system())
|
||||||
@ -63,12 +65,15 @@ async def specified_system_root(ctx: CommandContext):
|
|||||||
await system_fronthistory(ctx, system)
|
await system_fronthistory(ctx, system)
|
||||||
elif ctx.match("frontpercent") or ctx.match("frontbreakdown") or ctx.match("frontpercentage"):
|
elif ctx.match("frontpercent") or ctx.match("frontbreakdown") or ctx.match("frontpercentage"):
|
||||||
await system_frontpercent(ctx, system)
|
await system_frontpercent(ctx, system)
|
||||||
|
elif ctx.match("list") or ctx.match("members"):
|
||||||
|
await system_list(ctx, system)
|
||||||
else:
|
else:
|
||||||
await system_info(ctx, system)
|
await system_info(ctx, system)
|
||||||
|
|
||||||
|
|
||||||
async def system_info(ctx: CommandContext, system: System):
|
async def system_info(ctx: CommandContext, system: System):
|
||||||
await ctx.reply(embed=await pluralkit.bot.embeds.system_card(ctx.conn, ctx.client, system))
|
this_system = await ctx.get_system()
|
||||||
|
await ctx.reply(embed=await pluralkit.bot.embeds.system_card(ctx.conn, ctx.client, system, this_system and this_system.id == system.id))
|
||||||
|
|
||||||
|
|
||||||
async def system_new(ctx: CommandContext):
|
async def system_new(ctx: CommandContext):
|
||||||
@ -124,6 +129,10 @@ async def system_timezone(ctx: CommandContext):
|
|||||||
# Take the lat/long given by Overpass and put it into timezonefinder
|
# Take the lat/long given by Overpass and put it into timezonefinder
|
||||||
lat, lng = (float(data[0]["lat"]), float(data[0]["lon"]))
|
lat, lng = (float(data[0]["lat"]), float(data[0]["lon"]))
|
||||||
timezone_name = tzf.timezone_at(lng=lng, lat=lat)
|
timezone_name = tzf.timezone_at(lng=lng, lat=lat)
|
||||||
|
|
||||||
|
# Also delete the original searching message
|
||||||
|
await msg.delete()
|
||||||
|
|
||||||
if not timezone_name:
|
if not timezone_name:
|
||||||
raise CommandError("Time zone for city '{}' not found. This should never happen.".format(data[0]["display_name"]))
|
raise CommandError("Time zone for city '{}' not found. This should never happen.".format(data[0]["display_name"]))
|
||||||
|
|
||||||
@ -132,6 +141,7 @@ async def system_timezone(ctx: CommandContext):
|
|||||||
tz = await system.set_time_zone(ctx.conn, timezone_name)
|
tz = await system.set_time_zone(ctx.conn, timezone_name)
|
||||||
offset = tz.utcoffset(datetime.utcnow())
|
offset = tz.utcoffset(datetime.utcnow())
|
||||||
offset_str = "UTC{:+02d}:{:02d}".format(int(offset.total_seconds() // 3600), int(offset.total_seconds() // 60 % 60))
|
offset_str = "UTC{:+02d}:{:02d}".format(int(offset.total_seconds() // 3600), int(offset.total_seconds() // 60 % 60))
|
||||||
|
|
||||||
await ctx.reply_ok("System time zone set to {} ({}, {}).\n*Data from OpenStreetMap, queried using Nominatim.*".format(tz.tzname(datetime.utcnow()), offset_str, tz.zone))
|
await ctx.reply_ok("System time zone set to {} ({}, {}).\n*Data from OpenStreetMap, queried using Nominatim.*".format(tz.tzname(datetime.utcnow()), offset_str, tz.zone))
|
||||||
|
|
||||||
|
|
||||||
@ -349,3 +359,41 @@ async def system_frontpercent(ctx: CommandContext, system: System):
|
|||||||
embed.set_footer(text="Since {} ({} ago)".format(ctx.format_time(span_start),
|
embed.set_footer(text="Since {} ({} ago)".format(ctx.format_time(span_start),
|
||||||
display_relative(span_start)))
|
display_relative(span_start)))
|
||||||
await ctx.reply(embed=embed)
|
await ctx.reply(embed=embed)
|
||||||
|
|
||||||
|
async def system_list(ctx: CommandContext, system: System):
|
||||||
|
all_members = sorted(await system.get_members(ctx.conn), key=lambda m: m.name)
|
||||||
|
page_size = 10
|
||||||
|
if len(all_members) <= page_size:
|
||||||
|
# If we have less than 10 members, don't bother paginating
|
||||||
|
await ctx.reply(embed=embeds.member_list(await ctx.get_system(), all_members, 0, page_size = page_size))
|
||||||
|
else:
|
||||||
|
current_page = 0
|
||||||
|
msg: discord.Message = None
|
||||||
|
while True:
|
||||||
|
page_count = len(all_members) // page_size
|
||||||
|
embed = embeds.member_list(await ctx.get_system(), all_members, current_page)
|
||||||
|
|
||||||
|
# Add reactions for moving back and forth
|
||||||
|
if not msg:
|
||||||
|
msg = await ctx.reply(embed=embed)
|
||||||
|
await msg.add_reaction("\u2B05")
|
||||||
|
await msg.add_reaction("\u27A1")
|
||||||
|
else:
|
||||||
|
await msg.edit(embed=embed)
|
||||||
|
|
||||||
|
def check(reaction, user):
|
||||||
|
return user.id == ctx.message.author.id and reaction.emoji in ["\u2B05", "\u27A1"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
reaction, _ = await ctx.client.wait_for("reaction_add", timeout=5*60, check=check)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
return
|
||||||
|
|
||||||
|
if reaction.emoji == "\u2B05":
|
||||||
|
current_page = (current_page - 1) % page_count
|
||||||
|
elif reaction.emoji == "\u27A1":
|
||||||
|
current_page = (current_page + 1) % page_count
|
||||||
|
|
||||||
|
# If we can, remove the original reaction from the member
|
||||||
|
if ctx.message.channel.permissions_for(ctx.message.guild.get_member(ctx.client.user.id)).manage_messages:
|
||||||
|
await reaction.remove(ctx.message.author)
|
@ -1,6 +1,6 @@
|
|||||||
import discord
|
import discord
|
||||||
import humanize
|
import humanize
|
||||||
from typing import Tuple
|
from typing import Tuple, List
|
||||||
|
|
||||||
from pluralkit import db
|
from pluralkit import db
|
||||||
from pluralkit.bot.utils import escape
|
from pluralkit.bot.utils import escape
|
||||||
@ -66,7 +66,7 @@ def exception_log(message_content, author_name, author_discriminator, author_id,
|
|||||||
return embed
|
return embed
|
||||||
|
|
||||||
|
|
||||||
async def system_card(conn, client: discord.Client, system: System) -> discord.Embed:
|
async def system_card(conn, client: discord.Client, system: System, is_own_system: bool = True) -> discord.Embed:
|
||||||
card = discord.Embed()
|
card = discord.Embed()
|
||||||
card.colour = discord.Colour.blue()
|
card.colour = discord.Colour.blue()
|
||||||
|
|
||||||
@ -97,33 +97,7 @@ async def system_card(conn, client: discord.Client, system: System) -> discord.E
|
|||||||
card.add_field(name="Description",
|
card.add_field(name="Description",
|
||||||
value=truncate_field_body(system.description), inline=False)
|
value=truncate_field_body(system.description), inline=False)
|
||||||
|
|
||||||
# Get names of all members
|
card.add_field(name="Members", value="*See `pk;system {} list`".format(system.hid) if not is_own_system else "*See `pk;system list`*")
|
||||||
all_members = await system.get_members(conn)
|
|
||||||
if all_members:
|
|
||||||
member_texts = []
|
|
||||||
for member in all_members:
|
|
||||||
member_texts.append("{} (`{}`)".format(escape(member.name), member.hid))
|
|
||||||
|
|
||||||
# Interim solution for pagination of large systems
|
|
||||||
# Previously a lot of systems would hit the 1024 character limit and thus break the message
|
|
||||||
# This splits large system lists into multiple embed fields
|
|
||||||
# The 6000 character total limit will still apply here but this sort of pushes the problem until I find a better fix
|
|
||||||
pages = [""]
|
|
||||||
for member in member_texts:
|
|
||||||
last_page = pages[-1]
|
|
||||||
new_page = last_page + "\n" + member if last_page else member
|
|
||||||
|
|
||||||
if len(new_page) >= 1024:
|
|
||||||
pages.append(member)
|
|
||||||
else:
|
|
||||||
pages[-1] = new_page
|
|
||||||
|
|
||||||
for index, page in enumerate(pages):
|
|
||||||
field_name = "Members"
|
|
||||||
if index >= 1:
|
|
||||||
field_name = "Members (part {})".format(index + 1)
|
|
||||||
card.add_field(name=truncate_field_name(field_name), value=truncate_field_body(page), inline=False)
|
|
||||||
|
|
||||||
card.set_footer(text="System ID: {}".format(system.hid))
|
card.set_footer(text="System ID: {}".format(system.hid))
|
||||||
return card
|
return card
|
||||||
|
|
||||||
@ -243,3 +217,21 @@ def help_footer_embed() -> discord.Embed:
|
|||||||
embed = discord.Embed()
|
embed = discord.Embed()
|
||||||
embed.set_footer(text="By @Ske#6201 | GitHub: https://github.com/xSke/PluralKit/")
|
embed.set_footer(text="By @Ske#6201 | GitHub: https://github.com/xSke/PluralKit/")
|
||||||
return embed
|
return embed
|
||||||
|
|
||||||
|
def member_list(system: System, all_members: List[Member], current_page: int = 0, page_size: int = 10):
|
||||||
|
page_count = 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
|
||||||
|
for member in all_members[current_page*page_size:current_page*page_size+page_size]:
|
||||||
|
embed.add_field(name=member.name, value=(member.description or "") + "\n*ID: `{}`*".format(member.hid), inline=False)
|
||||||
|
return embed
|
@ -13,6 +13,7 @@ pk;system delete
|
|||||||
pk;system [system] fronter
|
pk;system [system] fronter
|
||||||
pk;system [system] fronthistory
|
pk;system [system] fronthistory
|
||||||
pk;system [system] frontpercent
|
pk;system [system] frontpercent
|
||||||
|
pk;system [system] list
|
||||||
pk;link <other account>
|
pk;link <other account>
|
||||||
pk;unlink
|
pk;unlink
|
||||||
```
|
```
|
||||||
|
@ -2,7 +2,7 @@ aiodns
|
|||||||
aiohttp==3.3.0
|
aiohttp==3.3.0
|
||||||
asyncpg
|
asyncpg
|
||||||
dateparser
|
dateparser
|
||||||
https://github.com/Rapptz/discord.py/archive/860d6a9ace8248dfeec18b8b159e7b757d9f56bb.zip#egg=discord.py
|
https://github.com/Rapptz/discord.py/archive/aceec2009a7c819d2236884fa9ccc5ce58a92bea.zip#egg=discord.py
|
||||||
humanize
|
humanize
|
||||||
uvloop; sys.platform != 'win32' and sys.platform != 'cygwin' and sys.platform != 'cli'
|
uvloop; sys.platform != 'win32' and sys.platform != 'cygwin' and sys.platform != 'cli'
|
||||||
ciso8601
|
ciso8601
|
||||||
|
Loading…
Reference in New Issue
Block a user