Add automatically assigned trust level badges.
This commit is contained in:
parent
eb7aab3e0b
commit
b144b75565
|
@ -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;
|
||||||
|
|
|
@ -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}}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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}}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,11 @@ class BadgeGranter
|
||||||
StaffActionLogger.new(@granted_by).log_badge_grant(user_badge)
|
StaffActionLogger.new(@granted_by).log_badge_grant(user_badge)
|
||||||
end
|
end
|
||||||
|
|
||||||
@user.notifications.create(notification_type: Notification.types[:granted_badge],
|
if SiteSetting.enable_badges?
|
||||||
data: { badge_id: @badge.id,
|
@user.notifications.create(notification_type: Notification.types[:granted_badge],
|
||||||
badge_name: @badge.name }.to_json)
|
data: { badge_id: @badge.id,
|
||||||
|
badge_name: @badge.name }.to_json)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -15,6 +15,6 @@ select
|
||||||
end
|
end
|
||||||
|
|
||||||
def down
|
def down
|
||||||
raise ActiveRecord::IrriversableMigration
|
raise ActiveRecord::IrreversibleMigration
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,6 +13,6 @@ class FixSearch < ActiveRecord::Migration
|
||||||
end
|
end
|
||||||
|
|
||||||
def down
|
def down
|
||||||
raise ActiveRecord::IrriversableMigration
|
raise ActiveRecord::IrreversibleMigration
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in New Issue