Files
croccybot/bot/core/user.py
Conatum 459a728968 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`
2021-08-26 22:34:46 +03:00

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)