Source code for vulyk.blueprints.gamification.core.state
# -*- coding: utf-8 -*-
"""
The package contains user state model and everything that will belong to
this part of domain.
"""
from datetime import datetime
from decimal import Decimal
from vulyk.models.user import User
__all__ = [
'UserState'
]
class InvalidUserStateException(BaseException):
"""
Generic container for all types of error may happen during
user state construction.
"""
pass
[docs]class UserState:
"""
An aggregation of all the stuff user has gotten working on projects so far.
"""
__slots__ = [
'user',
'level',
'points',
'actual_coins',
'potential_coins',
'achievements',
'last_changed'
]
def __init__(self,
user: User,
level: int,
points: Decimal,
actual_coins: Decimal,
potential_coins: Decimal,
achievements: list,
last_changed: datetime) -> None:
"""
:type user: User
:type level: int
:type points: Decimal
:type actual_coins: Decimal
:type potential_coins: Decimal
:type achievements: list[vulyk.blueprints.gamification.core.rules.Rule]
:type last_changed: datetime
"""
self.user = user
self.level = level
self.points = points
self.actual_coins = actual_coins
self.potential_coins = potential_coins
self.achievements = {a.id: a for a in achievements}
self.last_changed = last_changed
self._validate()
def _validate(self):
"""
Keep the internal structure valid.
:raises: InvalidUserStateException
"""
try:
assert self.user is not None, 'User must be present.'
assert self.level >= 0, 'Level value must be zero or greater.'
assert self.points >= Decimal(0), \
'Points value must be zero or greater.'
assert self.actual_coins >= Decimal(0), \
'Actual coins value must be zero or greater.'
assert self.potential_coins >= Decimal(0), \
'Potential coins value must be zero or greater.'
assert isinstance(self.achievements, dict), \
'Achievements value must be a dict'
assert isinstance(self.last_changed, datetime), \
'Last changed value must be a datetime'
except AssertionError as e:
raise InvalidUserStateException(e)
[docs] def to_dict(self) -> dict:
"""
Could be used as a source for JSON or any other representation format
:return: Dict-ized object view
:rtype: dict
"""
return {
'user': self.user.username,
'level': self.level,
'points': self.points,
'actual_coins': self.actual_coins,
'potential_coins': self.potential_coins,
'achievements': [r.to_dict() for r in self.achievements.values()],
'last_changed': self.last_changed.strftime("%d.%m.%Y %H:%M:%S")
}
def __eq__(self, o: object) -> bool:
if isinstance(o, UserState):
return o.user.id == self.user.id \
and o.level == self.level \
and o.points == self.points \
and o.actual_coins == self.actual_coins \
and o.potential_coins == self.potential_coins \
and (set(o.achievements.keys()) ==
set(self.achievements.keys())) \
and o.last_changed == self.last_changed
else:
return False
def __ne__(self, o: object) -> bool:
return not self == o
def __str__(self) -> str:
return 'UserState({user}, {level}, {points}, {act_coins}, ' \
'{pot_coins}, {badges}, {changed})' \
.format(user=self.user.id,
level=self.level,
points=self.points,
act_coins=self.actual_coins,
pot_coins=self.potential_coins,
badges=self.achievements.keys(),
changed=self.last_changed)
def __repr__(self) -> str:
return str(self)