Added flexibility to data `update_where`. Added interactive utils, with improved pager. Added user data table, with caching and transactional interface. Added `topcoins` command to `Economy` Added `top` command to `Study`
106 lines
3.0 KiB
Python
106 lines
3.0 KiB
Python
from . import tables as tb
|
|
from meta import conf, client
|
|
|
|
|
|
class User:
|
|
"""
|
|
Class representing a "Lion", i.e. a member of the managed guild.
|
|
Mostly acts as a transparent interface to the corresponding Row,
|
|
but also adds some transaction caching logic to `coins`.
|
|
"""
|
|
__slots__ = ('userid', '_pending_coins', '_member')
|
|
|
|
# Users with pending transactions
|
|
_pending = {} # userid -> User
|
|
|
|
# User cache. Currently users don't expire
|
|
_users = {} # userid -> User
|
|
|
|
def __init__(self, userid):
|
|
self.userid = userid
|
|
self._pending_coins = 0
|
|
|
|
self._users[self.userid] = self
|
|
|
|
@classmethod
|
|
def fetch(cls, userid):
|
|
"""
|
|
Fetch a User with the given userid.
|
|
If they don't exist, creates them.
|
|
If possible, retrieves the user from the user cache.
|
|
"""
|
|
if userid in cls._users:
|
|
return cls._users[userid]
|
|
else:
|
|
tb.users.fetch_or_create(userid)
|
|
return cls(userid)
|
|
|
|
@property
|
|
def member(self):
|
|
"""
|
|
The discord `Member` corresponding to this user.
|
|
May be `None` if the member is no longer in the guild or the caches aren't populated.
|
|
Not guaranteed to be `None` if the member is not in the guild.
|
|
"""
|
|
if self._member is None:
|
|
self._member = client.get_guild(conf.meta.getint('managed_guild_id')).get_member(self.userid)
|
|
|
|
@property
|
|
def data(self):
|
|
"""
|
|
The Row corresponding to this user.
|
|
"""
|
|
return tb.users.fetch(self.userid)
|
|
|
|
@property
|
|
def time(self):
|
|
"""
|
|
Amount of time the user has spent.. studying?
|
|
"""
|
|
return self.data.tracked_time
|
|
|
|
@property
|
|
def coins(self):
|
|
"""
|
|
Number of coins the user has, accounting for the pending value.
|
|
"""
|
|
return self.data.coins + self._pending_coins
|
|
|
|
def addCoins(self, amount, flush=True):
|
|
"""
|
|
Add coins to the user, optionally store the transaction in pending.
|
|
"""
|
|
self._pending_coins += amount
|
|
if self._pending_coins != 0:
|
|
self._pending[self.userid] = self
|
|
else:
|
|
self._pending.pop(self.userid, None)
|
|
if flush:
|
|
self.flush()
|
|
|
|
def flush(self):
|
|
"""
|
|
Flush any pending transactions to the database.
|
|
"""
|
|
self.sync(self)
|
|
|
|
@classmethod
|
|
def sync(cls, *users):
|
|
"""
|
|
Flush pending transactions to the database.
|
|
Also refreshes the Row cache for updated users.
|
|
"""
|
|
users = users or list(cls._pending.values())
|
|
|
|
if users:
|
|
# Build userid to pending coin map
|
|
userid_coins = [(user.userid, user._pending_coins) for user in users]
|
|
|
|
# Write to database
|
|
tb.users.queries.add_coins(userid_coins)
|
|
|
|
# Cleanup pending users
|
|
for user in users:
|
|
user._pending_coins = 0
|
|
cls._pending.pop(user.userid, None)
|