Intro To Badges - griffithlab/civic-server GitHub Wiki
CIViC has a system for awarding users badges for various accomplishments on the site. Its implementation is heavily inspired by the merit gem with a few key differences. Primarily, the CIViC implementation is designed to:
- Work by default with
ActiveJob
and our existing background task queue - Not assume naming conventions and existence of controller level instance variables
- Not require an additional ORM
- Work with our existing notification and event systems
Defining Badges
Badges are defined in the app/models/badges/definitions.rb
file. Specifically, the class method badges
should return a list of hashes, one for each supported badge.
def self.badges
#Define your badges here
[
{
name: 'Commenter',
tier: 'bronze',
description: 'Made their first comment.'
}
]
end
name
is a required field and must be unique. It will be used to refer to the badge later.description
is required and should be a brief text description of the badge. This will be displayed on the user's profile.tier
can be eitherbronze
,silver
,gold
, orspecial
. It is a reflection of the rarity or difficulty of acquiring a badge. Please see below for a more detailed explanation.additional_fields
can be an arbitrary hash - it will be serialized as JSON. It is currently only used to overrideimage_urls
Tiers and badge images
The bronze, silver, and gold badge tiers all share common images (much like Stack Overflow). When creating a badge with one of those tiers, no additional information is required. The system does support an additional badge type: special
. When the special
badge type is selected, you will need to supply a custom badge image. This can be done by providing an image_urls
hash under additional_fields
. This should contain the paths to .png
files representing the badges at various sizes. (Currently 128, 64, 32, and 15 pixel squares.)
{
name: 'NKI Hackathon Attendee 2016',
tier: 'special',
description: 'Attended the NKI Hackathon in Amsterdam',
additional_fields: {
image_urls: {
x128: '/public/badges/nki_128.png',
x64: '/public/badges/nki_64.png',
#etc
}
}
}
Awarding Badges
The conditions for awarding badges are defined in app/models/badges/rules.rb
. They take the form of a call to the grant
method. The first argument is the name
of the badge to award. This must match the name field from a badge in the definitions file. The next argument is a hash with a single key: on
. The value is either a single controller action, or an array of them. This specifies which requests will trigger a check for this particular badge. The final argument is a block which itself takes two arguments - the user
that triggered the request and the params
to that request. This block should return a truthy value if the badge should be awarded.
grant 'Commenter', on: ['gene_comments#create', 'variant_comments#create`] do |user, params|
user.comments.count >= 1
end
The above rule will award the Commenter
badge to a user after they comment on either a gene or a variant, as long as their comment count is at least one.
Custom target user
Sometimes you may wish to award a badge to a user which is not the user that initiated a request. In this case, you can set the @target_user
instance variable inside the grant
block. For instance, the following example will award a badge named 'Contributor` to the user which submitted an evidence item upon its acceptance into CIViC.
grant 'Conbtributor', on: 'evidence_items#accept' do |user, params|
evidence_item = EvidenceItem.find(params[:id])
@target_user = evidence_item.submitter
evidence_item.status == 'accepted'
end
Badges will not be awarded multiple times so there is no need to check if a condition has already been met, only if it is currently met.
Testing
By default, badge processing happens in the background. If you would like to start a background worker in your development environment, you can do so with the following commands.
rails c
Delayed::Worker.new.start
The worker can be stopped with Ctrl-C