Add automatically assigned trust level badges.

This commit is contained in:
Vikhyat Korrapati 2014-05-04 23:45:38 +05:30
parent eb7aab3e0b
commit b144b75565
18 changed files with 141 additions and 17 deletions

View File

@ -35,7 +35,7 @@ Discourse.Badge = Discourse.Model.extend({
@type {String} @type {String}
**/ **/
displayName: function() { displayName: function() {
var i18nKey = "badges." + this.get('i18nNameKey') + ".name"; var i18nKey = "badges.badge." + this.get('i18nNameKey') + ".name";
return I18n.t(i18nKey, {defaultValue: this.get('name')}); return I18n.t(i18nKey, {defaultValue: this.get('name')});
}.property('name', 'i18nNameKey'), }.property('name', 'i18nNameKey'),
@ -46,7 +46,7 @@ Discourse.Badge = Discourse.Model.extend({
@type {String} @type {String}
**/ **/
translatedDescription: function() { translatedDescription: function() {
var i18nKey = "badges." + this.get('i18nNameKey') + ".description", var i18nKey = "badges.badge." + this.get('i18nNameKey') + ".description",
translation = I18n.t(i18nKey); translation = I18n.t(i18nKey);
if (translation.indexOf(i18nKey) !== -1) { if (translation.indexOf(i18nKey) !== -1) {
translation = null; translation = null;

View File

@ -5,7 +5,7 @@
{{#each}} {{#each}}
<tr> <tr>
<td class='badge'>{{user-badge badge=this}}</td> <td class='badge'>{{user-badge badge=this}}</td>
<td class='description'>{{description}}</td> <td class='description'>{{translatedDescription}}</td>
<td class='grant-count'>{{i18n badges.granted count=grant_count}}</td> <td class='grant-count'>{{i18n badges.granted count=grant_count}}</td>
</tr> </tr>
{{/each}} {{/each}}

View File

@ -8,7 +8,7 @@
<table class='badges-listing'> <table class='badges-listing'>
<tr> <tr>
<td class='badge'>{{user-badge badge=this}}</td> <td class='badge'>{{user-badge badge=this}}</td>
<td class='description'>{{description}}</td> <td class='description'>{{translatedDescription}}</td>
<td class='grant-count'>{{i18n badges.granted count=grant_count}}</td> <td class='grant-count'>{{i18n badges.granted count=grant_count}}</td>
</tr> </tr>
</table> </table>

View File

@ -1,6 +1,6 @@
{{#link-to 'badges.show' badge}} {{#link-to 'badges.show' badge}}
<span {{bind-attr class=":user-badge badgeTypeClassName" data-badge-name="badge.name" title="badge.description"}}> <span {{bind-attr class=":user-badge badgeTypeClassName" data-badge-name="badge.name" title="badge.translatedDescription"}}>
<i class='fa fa-certificate'></i> <i class='fa fa-certificate'></i>
{{badge.name}} {{badge.displayName}}
</span> </span>
{{/link-to}} {{/link-to}}

View File

@ -5,6 +5,10 @@ class Badge < ActiveRecord::Base
validates :name, presence: true, uniqueness: true validates :name, presence: true, uniqueness: true
validates :badge_type, presence: true validates :badge_type, presence: true
validates :allow_title, inclusion: [true, false] validates :allow_title, inclusion: [true, false]
def self.trust_level_badge_ids
(1..4).to_a
end
end end
# == Schema Information # == Schema Information

View File

@ -447,6 +447,7 @@ class User < ActiveRecord::Base
transaction do transaction do
self.save! self.save!
Group.user_trust_level_change!(self.id, self.trust_level) Group.user_trust_level_change!(self.id, self.trust_level)
BadgeGranter.update_trust_level_badges!(self)
end end
end end

View File

@ -24,11 +24,13 @@ class BadgeGranter
StaffActionLogger.new(@granted_by).log_badge_grant(user_badge) StaffActionLogger.new(@granted_by).log_badge_grant(user_badge)
end end
if SiteSetting.enable_badges?
@user.notifications.create(notification_type: Notification.types[:granted_badge], @user.notifications.create(notification_type: Notification.types[:granted_badge],
data: { badge_id: @badge.id, data: { badge_id: @badge.id,
badge_name: @badge.name }.to_json) badge_name: @badge.name }.to_json)
end end
end end
end
user_badge user_badge
end end
@ -54,4 +56,19 @@ class BadgeGranter
end end
end end
def self.update_trust_level_badges!(user)
Badge.trust_level_badge_ids.each do |badge_id|
user_badge = UserBadge.where(user_id: user.id, badge_id: badge_id).first
if user_badge
# Revoke the badge if the user is not supposed to have it.
BadgeGranter.revoke(user_badge) if user.trust_level < badge_id
else
# Grant the badge if the user is supposed to have it.
badge = Badge.find(badge_id)
BadgeGranter.grant(badge, user) if user.trust_level >= badge_id
end
end
end
end end

View File

@ -1850,6 +1850,16 @@ en:
one: "1 granted" one: "1 granted"
other: "%{count} granted" other: "%{count} granted"
select_badge_for_title: Select a badge to use as your title select_badge_for_title: Select a badge to use as your title
example_badge: badge:
name: Example Badge basic_user:
description: This is a generic example badge. name: Basic User
description: Trusted as a basic user.
regular_user:
name: Regular User
description: Trusted as a regular user.
leader:
name: Leader
description: One of the most active and prolific users.
elder:
name: Elder
description: Long term community leader who has been around and seen everything.

47
db/fixtures/601_badges.rb Normal file
View File

@ -0,0 +1,47 @@
def reset_badge_grant_count(badge)
badge.grant_count = UserBadge.where(badge_id: badge.id).count
badge.save!
end
def grant_trust_level_badges_to_user(user)
return if user.id == Discourse.system_user.id
Badge.trust_level_badge_ids.each do |badge_id|
user_badge = UserBadge.where(user_id: user.id, badge_id: badge_id).first
if user_badge
# Revoke the badge if the user is not supposed to have it.
if user.trust_level < badge_id
user_badge.destroy!
end
else
# Grant the badge if the user is supposed to have it.
badge = Badge.find(badge_id)
if user.trust_level >= badge_id
UserBadge.create!(badge: badge, user: user, granted_by: Discourse.system_user, granted_at: Time.now)
end
end
end
end
trust_level_badges = [
{id: 1, name: "Basic User", type: 3},
{id: 2, name: "Regular User", type: 3},
{id: 3, name: "Leader", type: 2},
{id: 4, name: "Elder", type: 1}
]
backfill_trust_level_badges = false
trust_level_badges.each do |spec|
backfill_trust_level_badges ||= Badge.where(id: spec[:id]).first.nil?
Badge.seed do |b|
b.id = spec[:id]
b.name = spec[:name]
b.badge_type_id = spec[:type]
end
end
if backfill_trust_level_badges
User.find_each {|user| grant_trust_level_badges_to_user(user) }
Badge.where(id: Badge.trust_level_badge_ids).each {|badge| reset_badge_grant_count(badge) }
end

View File

@ -5,6 +5,6 @@ class MigrateBookmarksToPostActions < ActiveRecord::Migration
def down def down
# I can reverse this, but not really worth the work # I can reverse this, but not really worth the work
raise ActiveRecord::IrriversableMigration raise ActiveRecord::IrreversibleMigration
end end
end end

View File

@ -15,6 +15,6 @@ select
end end
def down def down
raise ActiveRecord::IrriversableMigration raise ActiveRecord::IrreversibleMigration
end end
end end

View File

@ -13,6 +13,6 @@ class FixSearch < ActiveRecord::Migration
end end
def down def down
raise ActiveRecord::IrriversableMigration raise ActiveRecord::IrreversibleMigration
end end
end end

View File

@ -0,0 +1,16 @@
class IncrementReservedTrustLevelBadgeIds < ActiveRecord::Migration
def up
execute "ALTER SEQUENCE badges_id_seq START WITH 100"
max_badge_id = Badge.order('id DESC').limit(1).first.try(:id)
Badge.where('id > 0 AND id <= 100').find_each do |badge|
new_id = badge.id + max_badge_id + 100
UserBadge.where(badge_id: badge.id).update_all badge_id: new_id
badge.update_column :id, new_id
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -18,6 +18,7 @@ class BoostTrustLevel
@user.update_attributes!(trust_level: @level) @user.update_attributes!(trust_level: @level)
end end
@logger.log_trust_level_change(@user, previous_level, @level) @logger.log_trust_level_change(@user, previous_level, @level)
BadgeGranter.update_trust_level_badges!(@user)
success success
end end

View File

@ -9,7 +9,7 @@ describe BadgesController do
response.status.should == 200 response.status.should == 200
parsed = JSON.parse(response.body) parsed = JSON.parse(response.body)
parsed["badges"].length.should == 1 parsed["badges"].length.should == Badge.count
end end
end end

View File

@ -1,10 +1,15 @@
require 'spec_helper' require 'spec_helper'
require_dependency 'boost_trust_level'
describe BadgeGranter do describe BadgeGranter do
let(:badge) { Fabricate(:badge) } let(:badge) { Fabricate(:badge) }
let(:user) { Fabricate(:user) } let(:user) { Fabricate(:user) }
before do
SiteSetting.enable_badges = true
end
describe 'grant' do describe 'grant' do
it 'grants a badge' do it 'grants a badge' do
@ -66,4 +71,27 @@ describe BadgeGranter do
end end
context "revoke" do
let(:user) { Fabricate(:user) }
let(:logger) { StaffActionLogger.new(Fabricate(:admin)) }
it "is called by User#change_trust_level!" do
BadgeGranter.expects(:update_trust_level_badges!)
user.change_trust_level!(:basic)
end
it "is called by BoostTrustLevel#save!" do
BadgeGranter.expects(:update_trust_level_badges!)
BoostTrustLevel.new(user: user, level: 1, logger: logger).save!
end
it "grants and revokes badges" do
user.change_trust_level!(:elder)
UserBadge.where(user_id: user.id, badge_id: Badge.trust_level_badge_ids).count.should eq(4)
BoostTrustLevel.new(user: user, level: 1, logger: logger).save!
UserBadge.where(user_id: user.id, badge_id: 1).first.should_not be_nil
UserBadge.where(user_id: user.id, badge_id: 2).first.should be_nil
end
end
end end

View File

@ -13,7 +13,7 @@ test('displayName', function() {
this.stub(I18n, "t").returnsArg(0); this.stub(I18n, "t").returnsArg(0);
var badge2 = Discourse.Badge.create({id: 2, name: "Test Badge 2"}); var badge2 = Discourse.Badge.create({id: 2, name: "Test Badge 2"});
equal(badge2.get('displayName'), "badges.test_badge_2.name", "uses translation when available"); equal(badge2.get('displayName'), "badges.badge.test_badge_2.name", "uses translation when available");
}); });
test('translatedDescription', function() { test('translatedDescription', function() {