Core user data and leaderboard commands.
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`
This commit is contained in:
105
bot/core/user.py
Normal file
105
bot/core/user.py
Normal file
@@ -0,0 +1,105 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user