Using brabeion¶
Getting Started¶
-
class
brabeion.base.Badge¶
brabeion works by allowing you to define your badges as subclasses of a
common Badge class and registering them with brabeion. For example if
your site gave users points, and you wanted to award three ranks of badges
based on how many points a user had your badge might look like this:
from brabeion import badges
from brabeion.base import Badge, BadgeAwarded
class PointsBadge(Badge):
slug = "points"
levels = [
"Bronze",
"Silver",
"Gold",
]
events = [
"points_awarded",
]
multiple = False
def award(self, **state):
user = state["user"]
points = user.get_profile().points
if points > 10000:
return BadgeAwarded(level=3)
elif points > 7500:
return BadgeAwarded(level=2)
elif points > 5000:
return BadgeAwarded(level=1)
badges.register(PointsBadge)
There are a few relevant attributes and methods here.
-
slug¶ The unique identifier for this
Badge, it should never change.
-
levels¶ A list of the levels available for this badge (if this badge doesn’t have levels it should just be a list with one item). It can either be a list of strings, which are the names of the levels, or a list of
brabeion.base.BadgeDetailwhich have both names and description.
-
events¶ A list of events that can possibly trigger this badge to be awarded. How events are triggered is described in further detail below.
-
multiple¶ A boolean specifying whether or not this badge can be awarded to the same user multiple times, currently if this badge has multiple levels this must be
False.
-
award(self, **state)¶ This method returns whether or not a user should be awarded this badge.
stateis guarnteed to have a"user"key, as well as any other custom data you provide. It should return either aBadgeAwardedinstance, orNone. If thisBadgedoesn’t have multiple levelsBadgeAwardeddoesn’t need to be provided an explicit level.Note
BadgeAwarded.levelis 1-indexed.
Now that you have your PointsBadge class you need to be able to tell
brabeion when to try to give it to a user. To do this, any time a user
might have received a badge just call badges.possibly_award_badge with
the name of the event, and whatever state these events might need and
brabeion will handle the details of seeing what badges need to be awarded
to the user:
from brabeion import badges
def my_view(request):
if request.method == "POST":
# do some things
request.user.profile.award_points(15)
badges.possibly_award_badge("points_awarded", user=request.user)
# more view
By default badges will be awarded at the current time, if you need to overide
the award time of the badge you can pass a force_timestamp keyword argument
to possible_award_badge().
Asynchronous Badges¶
Note
To use asynchronous badges you must have celery installed and configured.
If your Badge.award() method takes a long time to compute it may be
prohibitively expensive to call during the request/response cycle. To solve
this problem brabeion provides an async option to Badges. If this
is True brabeion will defer calling your award() method, using
celery, and it will be called at a later time, by another process (read the
celery docs for more information on how
celery works).
Because award() won’t be called until later you can define a freeze()
method which allows you to provide and additional state that you’ll need to
compute award() correctly. This may be necessary because your Badge
requires some mutable state.
class AddictBadge(Badge):
# stuff
async = True
def freeze(self, **state):
state["current_day"] = datetime.today()
return state
In this example badge the user will be awarded the AddictBadge when they’ve
visited the site every day for a month, this is expensive to calculate so it
will be done outside the request/response cycle. However, what happens if they
visit the site right before midnight, and then the award() method isn’t
actually called until the next day? Using the freeze method you can provide
additional state to the award() method.