mirror of
https://github.com/NoiTheCat/WorldTime.git
synced 2024-11-24 01:14:13 +00:00
Change parameterless tz.list
This commit is contained in:
parent
82f956f47a
commit
2db1cd05ac
3 changed files with 53 additions and 103 deletions
95
commands.py
95
commands.py
|
@ -1,12 +1,13 @@
|
||||||
# Command handlers
|
# Command handlers
|
||||||
# Incoming commands are fully handled by functions defined here.
|
# Incoming commands are fully handled by functions defined here.
|
||||||
|
|
||||||
from common import BotVersion
|
from common import BotVersion, tzPrint
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
import discord
|
import discord
|
||||||
import pytz
|
import pytz
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import re
|
import re
|
||||||
|
import collections
|
||||||
|
|
||||||
from userdb import UserDatabase
|
from userdb import UserDatabase
|
||||||
from common import tzlcmap, logPrint
|
from common import tzlcmap, logPrint
|
||||||
|
@ -35,47 +36,6 @@ class WtCommands:
|
||||||
# ------
|
# ------
|
||||||
# Helper methods
|
# Helper methods
|
||||||
|
|
||||||
def _tzPrint(self, zone : str):
|
|
||||||
"""
|
|
||||||
Returns a string displaying the current time in the given time zone.
|
|
||||||
String begins with four numbers for sorting purposes and must be trimmed before output.
|
|
||||||
"""
|
|
||||||
now_time = datetime.now(pytz.timezone(zone))
|
|
||||||
return "{:s}● {:s}".format(now_time.strftime("%m%d"), now_time.strftime("%d-%b %H:%M %Z (UTC%z)"))
|
|
||||||
|
|
||||||
def _userResolve(self, guild: discord.Guild, userIds: list):
|
|
||||||
"""
|
|
||||||
Given a list with user IDs, returns a string, the second half of a
|
|
||||||
list entry, describing the users for which a zone is represented by.
|
|
||||||
"""
|
|
||||||
if len(userIds) == 0:
|
|
||||||
return " → This text should never appear."
|
|
||||||
|
|
||||||
# Try given entries. For each entry tried, attempt to get their nickname
|
|
||||||
# or username. Failed attempts are anonymized instead of discarded.
|
|
||||||
namesProcessed = 0
|
|
||||||
namesSkipped = 0
|
|
||||||
processedNames = []
|
|
||||||
while namesProcessed < 4 and len(userIds) > 0:
|
|
||||||
namesProcessed += 1
|
|
||||||
uid = userIds.pop()
|
|
||||||
mem = guild.get_member(int(uid))
|
|
||||||
if mem is not None:
|
|
||||||
processedNames.append(mem.display_name)
|
|
||||||
else:
|
|
||||||
namesSkipped += 1
|
|
||||||
leftovers = namesSkipped + len(userIds)
|
|
||||||
if len(processedNames) == 0:
|
|
||||||
return " → {0} user{1}.".format(leftovers, "s" if leftovers != 1 else "")
|
|
||||||
result = " → "
|
|
||||||
while len(processedNames) > 0:
|
|
||||||
result += processedNames.pop() + ", "
|
|
||||||
if leftovers != 0:
|
|
||||||
result += "{0} other{1}.".format(leftovers, "s" if leftovers != 1 else "")
|
|
||||||
else:
|
|
||||||
result = result[:-2] + "."
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _userFormat(self, member: discord.Member):
|
def _userFormat(self, member: discord.Member):
|
||||||
"""
|
"""
|
||||||
Given a member, returns a formatted string showing their username and nickname
|
Given a member, returns a formatted string showing their username and nickname
|
||||||
|
@ -236,26 +196,33 @@ class WtCommands:
|
||||||
# Supplemental command functions
|
# Supplemental command functions
|
||||||
|
|
||||||
async def _list_noparam(self, guild: discord.Guild, channel: discord.TextChannel):
|
async def _list_noparam(self, guild: discord.Guild, channel: discord.TextChannel):
|
||||||
rawlist = self.userdb.get_list2(guild.id)
|
userlist = self.userdb.get_users(guild.id)
|
||||||
if len(rawlist) == 0:
|
if len(userlist) == 0:
|
||||||
await channel.send(':x: No users with registered time zones have been active in the last 30 days.')
|
await channel.send(':x: No users with registered time zones have been active in the last 30 days.')
|
||||||
return
|
return
|
||||||
if guild.large:
|
|
||||||
# Get full user data here if not available (used by _userResolve)
|
orderedList = collections.OrderedDict(sorted(userlist.items()))
|
||||||
await self.dclient.request_offline_members(guild)
|
result = ''
|
||||||
resultData = []
|
|
||||||
for key, value in rawlist.items():
|
for k, v in orderedList.items():
|
||||||
resultData.append(self._tzPrint(key) + '\n' + self._userResolve(guild, value))
|
foundUsers = 0
|
||||||
resultData.sort()
|
line = k[4:] + ": "
|
||||||
resultFinal = '```\n'
|
for id in v:
|
||||||
for i in resultData:
|
member = await self._resolve_member(guild, id)
|
||||||
resultFinal += i + '\n'
|
if member is None:
|
||||||
resultFinal += '```'
|
continue
|
||||||
await channel.send(resultFinal)
|
if foundUsers > 10:
|
||||||
|
line += "and others... "
|
||||||
|
foundUsers += 1
|
||||||
|
line += self._userFormat(member) + ", "
|
||||||
|
if foundUsers > 0: result += line[:-2] + "\n"
|
||||||
|
|
||||||
|
em = discord.Embed(description=result.strip())
|
||||||
|
await channel.send(embed=em)
|
||||||
|
|
||||||
async def _list_userparam(self, guild: discord.Guild, channel: discord.TextChannel, author: discord.User, param):
|
async def _list_userparam(self, guild: discord.Guild, channel: discord.TextChannel, author: discord.User, param):
|
||||||
param = str(param)
|
param = str(param)
|
||||||
usersearch = self._resolve_member(guild, param)
|
usersearch = await self._resolve_member(guild, param)
|
||||||
if usersearch is None:
|
if usersearch is None:
|
||||||
await channel.send(':x: Cannot find the specified user.')
|
await channel.send(':x: Cannot find the specified user.')
|
||||||
return
|
return
|
||||||
|
@ -266,22 +233,22 @@ class WtCommands:
|
||||||
if ownsearch: await channel.send(':x: You do not have a time zone. Set it with `tz.set`.')
|
if ownsearch: await channel.send(':x: You do not have a time zone. Set it with `tz.set`.')
|
||||||
else: await channel.send(':x: The given user does not have a time zone set.')
|
else: await channel.send(':x: The given user does not have a time zone set.')
|
||||||
return
|
return
|
||||||
em = discord.Embed(description=self._tzPrint(res)[4:] + ": " + self._userFormat(usersearch))
|
em = discord.Embed(description=tzPrint(res)[4:] + ": " + self._userFormat(usersearch))
|
||||||
await channel.send(embed=em)
|
await channel.send(embed=em)
|
||||||
|
|
||||||
def _resolve_member(self, guild: discord.Guild, inputstr: str):
|
async def _resolve_member(self, guild: discord.Guild, inputstr: str):
|
||||||
"""
|
"""
|
||||||
Takes a string input and attempts to find the corresponding member.
|
Takes a string input and attempts to find the corresponding member.
|
||||||
"""
|
"""
|
||||||
|
await self.dclient.request_offline_members(guild)
|
||||||
idsearch = None
|
idsearch = None
|
||||||
try:
|
try:
|
||||||
idsearch = int(inputstr)
|
idsearch = int(inputstr)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
if inputstr.startswith('<@!') and inputstr.endswith('>'):
|
||||||
if inputstr.startswith('<@!') and inputstr.endswith('>'):
|
idsearch = int(inputstr[3:][:-1])
|
||||||
idsearch = int(inputstr[3:][:-1])
|
elif inputstr.startswith('<@') and inputstr.endswith('>'):
|
||||||
elif inputstr.startswith('<@') and inputstr.endswith('>'):
|
idsearch = int(inputstr[2:][:-1])
|
||||||
idsearch = int(inputstr[2:][:-1])
|
|
||||||
|
|
||||||
if idsearch is not None:
|
if idsearch is not None:
|
||||||
return guild.get_member(idsearch)
|
return guild.get_member(idsearch)
|
||||||
|
|
10
common.py
10
common.py
|
@ -4,7 +4,7 @@ import pytz
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
# Bot's current version (as a string), for use in the help command
|
# Bot's current version (as a string), for use in the help command
|
||||||
BotVersion = "1.2.1"
|
BotVersion = "1.3.0"
|
||||||
|
|
||||||
# For case-insensitive time zone lookup, map lowercase tzdata entries with
|
# For case-insensitive time zone lookup, map lowercase tzdata entries with
|
||||||
# entires with proper case. pytz is case sensitive.
|
# entires with proper case. pytz is case sensitive.
|
||||||
|
@ -16,3 +16,11 @@ def logPrint(label, line):
|
||||||
"""
|
"""
|
||||||
resultstr = datetime.utcnow().strftime('%Y-%m-%d %H:%m:%S') + ' [' + label + '] ' + line
|
resultstr = datetime.utcnow().strftime('%Y-%m-%d %H:%m:%S') + ' [' + label + '] ' + line
|
||||||
print(resultstr)
|
print(resultstr)
|
||||||
|
|
||||||
|
def tzPrint(zone : str):
|
||||||
|
"""
|
||||||
|
Returns a string displaying the current time in the given time zone.
|
||||||
|
String begins with four numbers for sorting purposes and must be trimmed before output.
|
||||||
|
"""
|
||||||
|
now_time = datetime.now(pytz.timezone(zone))
|
||||||
|
return "{:s}● {:s}".format(now_time.strftime("%m%d"), now_time.strftime("%d-%b %H:%M %Z (UTC%z)"))
|
47
userdb.py
47
userdb.py
|
@ -1,6 +1,7 @@
|
||||||
# User database abstractions
|
# User database abstractions
|
||||||
|
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
from common import tzPrint
|
||||||
|
|
||||||
class UserDatabase:
|
class UserDatabase:
|
||||||
def __init__(self, connstr):
|
def __init__(self, connstr):
|
||||||
|
@ -63,7 +64,7 @@ class UserDatabase:
|
||||||
|
|
||||||
def get_user(self, serverid, userid):
|
def get_user(self, serverid, userid):
|
||||||
'''
|
'''
|
||||||
Retrieves the time zone name of a single user
|
Retrieves the time zone name of a single user.
|
||||||
'''
|
'''
|
||||||
c = self.db.cursor()
|
c = self.db.cursor()
|
||||||
c.execute("""
|
c.execute("""
|
||||||
|
@ -75,36 +76,12 @@ class UserDatabase:
|
||||||
if result is None: return None
|
if result is None: return None
|
||||||
return result[0]
|
return result[0]
|
||||||
|
|
||||||
|
def get_users(self, serverid):
|
||||||
def get_list(self, serverid, userid=None):
|
"""
|
||||||
'''
|
Retrieves all user time zones for all recently active members.
|
||||||
Retrieves a list of recent time zones based on
|
Users not present are not filtered here. Must be handled by the caller.
|
||||||
recent activity per user. For use in the list command.
|
Returns a dictionary of lists - Key is formatted zone, value is list of users represented.
|
||||||
'''
|
"""
|
||||||
c = self.db.cursor()
|
|
||||||
if userid is None:
|
|
||||||
c.execute("""
|
|
||||||
SELECT zone, count(*) as ct FROM userdata
|
|
||||||
WHERE guild_id = %s
|
|
||||||
AND last_active >= now() - INTERVAL '30 DAYS' -- only users active in the last 30 days
|
|
||||||
GROUP BY zone -- separate by popularity
|
|
||||||
ORDER BY ct DESC LIMIT 20 -- top 20 zones are given
|
|
||||||
""", (serverid))
|
|
||||||
else:
|
|
||||||
c.execute("""
|
|
||||||
SELECT zone, '0' as ct FROM userdata
|
|
||||||
WHERE guild_id = %s AND user_id = %s
|
|
||||||
""", (serverid, userid))
|
|
||||||
|
|
||||||
results = c.fetchall()
|
|
||||||
c.close()
|
|
||||||
return [i[0] for i in results]
|
|
||||||
|
|
||||||
def get_list2(self, serverid):
|
|
||||||
'''
|
|
||||||
Retrieves data for the tz.list command.
|
|
||||||
Returns a dictionary. Keys are zone name, values are arrays with user IDs.
|
|
||||||
'''
|
|
||||||
c = self.db.cursor()
|
c = self.db.cursor()
|
||||||
c.execute("""
|
c.execute("""
|
||||||
SELECT zone, user_id
|
SELECT zone, user_id
|
||||||
|
@ -125,11 +102,9 @@ class UserDatabase:
|
||||||
""", {'guild': serverid})
|
""", {'guild': serverid})
|
||||||
result = {}
|
result = {}
|
||||||
for row in c:
|
for row in c:
|
||||||
inlist = result.get(row[0])
|
resultrow = tzPrint(row[0])
|
||||||
if inlist is None:
|
result[resultrow] = result.get(resultrow, list())
|
||||||
result[row[0]] = []
|
result[resultrow].append(row[1])
|
||||||
inlist = result[row[0]]
|
|
||||||
inlist.append(row[1])
|
|
||||||
c.close()
|
c.close()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue