From b144b7556543c6e5a129fd10957d73aa6dae691f Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Sun, 4 May 2014 23:45:38 +0530 Subject: [PATCH 1/3] Add automatically assigned trust level badges. --- .../javascripts/discourse/models/badge.js | 4 +- .../templates/badges/index.js.handlebars | 2 +- .../templates/badges/show.js.handlebars | 2 +- .../components/user-badge.js.handlebars | 4 +- app/models/badge.rb | 4 ++ app/models/user.rb | 1 + app/services/badge_granter.rb | 23 +++++++-- config/locales/client.en.yml | 16 +++++-- ...{700_badge_types.rb => 600_badge_types.rb} | 0 db/fixtures/601_badges.rb | 47 +++++++++++++++++++ ...01855_migrate_bookmarks_to_post_actions.rb | 2 +- .../20120812235417_retire_expressions.rb | 2 +- db/migrate/20130120222728_fix_search.rb | 2 +- ...ncrement_reserved_trust_level_badge_ids.rb | 16 +++++++ lib/boost_trust_level.rb | 1 + spec/controllers/badges_controller_spec.rb | 2 +- spec/services/badge_granter_spec.rb | 28 +++++++++++ test/javascripts/models/badge_test.js | 2 +- 18 files changed, 141 insertions(+), 17 deletions(-) rename db/fixtures/{700_badge_types.rb => 600_badge_types.rb} (100%) create mode 100644 db/fixtures/601_badges.rb create mode 100644 db/migrate/20140504174212_increment_reserved_trust_level_badge_ids.rb diff --git a/app/assets/javascripts/discourse/models/badge.js b/app/assets/javascripts/discourse/models/badge.js index 0d629d17568..0326351207f 100644 --- a/app/assets/javascripts/discourse/models/badge.js +++ b/app/assets/javascripts/discourse/models/badge.js @@ -35,7 +35,7 @@ Discourse.Badge = Discourse.Model.extend({ @type {String} **/ 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')}); }.property('name', 'i18nNameKey'), @@ -46,7 +46,7 @@ Discourse.Badge = Discourse.Model.extend({ @type {String} **/ translatedDescription: function() { - var i18nKey = "badges." + this.get('i18nNameKey') + ".description", + var i18nKey = "badges.badge." + this.get('i18nNameKey') + ".description", translation = I18n.t(i18nKey); if (translation.indexOf(i18nKey) !== -1) { translation = null; diff --git a/app/assets/javascripts/discourse/templates/badges/index.js.handlebars b/app/assets/javascripts/discourse/templates/badges/index.js.handlebars index 2317de8a9b0..0551537fea3 100644 --- a/app/assets/javascripts/discourse/templates/badges/index.js.handlebars +++ b/app/assets/javascripts/discourse/templates/badges/index.js.handlebars @@ -5,7 +5,7 @@ {{#each}} {{user-badge badge=this}} - {{description}} + {{translatedDescription}} {{i18n badges.granted count=grant_count}} {{/each}} diff --git a/app/assets/javascripts/discourse/templates/badges/show.js.handlebars b/app/assets/javascripts/discourse/templates/badges/show.js.handlebars index 35638c72d85..980975093d9 100644 --- a/app/assets/javascripts/discourse/templates/badges/show.js.handlebars +++ b/app/assets/javascripts/discourse/templates/badges/show.js.handlebars @@ -8,7 +8,7 @@ - +
{{user-badge badge=this}}{{description}}{{translatedDescription}} {{i18n badges.granted count=grant_count}}
diff --git a/app/assets/javascripts/discourse/templates/components/user-badge.js.handlebars b/app/assets/javascripts/discourse/templates/components/user-badge.js.handlebars index ca2070b7e3d..64419e5278d 100644 --- a/app/assets/javascripts/discourse/templates/components/user-badge.js.handlebars +++ b/app/assets/javascripts/discourse/templates/components/user-badge.js.handlebars @@ -1,6 +1,6 @@ {{#link-to 'badges.show' badge}} - + - {{badge.name}} + {{badge.displayName}} {{/link-to}} diff --git a/app/models/badge.rb b/app/models/badge.rb index 70e18460836..2ae330bc4d6 100644 --- a/app/models/badge.rb +++ b/app/models/badge.rb @@ -5,6 +5,10 @@ class Badge < ActiveRecord::Base validates :name, presence: true, uniqueness: true validates :badge_type, presence: true validates :allow_title, inclusion: [true, false] + + def self.trust_level_badge_ids + (1..4).to_a + end end # == Schema Information diff --git a/app/models/user.rb b/app/models/user.rb index 9eae13b2b49..e064afac344 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -447,6 +447,7 @@ class User < ActiveRecord::Base transaction do self.save! Group.user_trust_level_change!(self.id, self.trust_level) + BadgeGranter.update_trust_level_badges!(self) end end diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index 8b4de1a54f7..fb0e07a7c75 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -24,9 +24,11 @@ class BadgeGranter StaffActionLogger.new(@granted_by).log_badge_grant(user_badge) end - @user.notifications.create(notification_type: Notification.types[:granted_badge], - data: { badge_id: @badge.id, - badge_name: @badge.name }.to_json) + if SiteSetting.enable_badges? + @user.notifications.create(notification_type: Notification.types[:granted_badge], + data: { badge_id: @badge.id, + badge_name: @badge.name }.to_json) + end end end @@ -54,4 +56,19 @@ class BadgeGranter 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 diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 2f8bb0519c1..edc52ccc61e 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1850,6 +1850,16 @@ en: one: "1 granted" other: "%{count} granted" select_badge_for_title: Select a badge to use as your title - example_badge: - name: Example Badge - description: This is a generic example badge. + badge: + basic_user: + 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. diff --git a/db/fixtures/700_badge_types.rb b/db/fixtures/600_badge_types.rb similarity index 100% rename from db/fixtures/700_badge_types.rb rename to db/fixtures/600_badge_types.rb diff --git a/db/fixtures/601_badges.rb b/db/fixtures/601_badges.rb new file mode 100644 index 00000000000..bffbfa18d95 --- /dev/null +++ b/db/fixtures/601_badges.rb @@ -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 diff --git a/db/migrate/20120809201855_migrate_bookmarks_to_post_actions.rb b/db/migrate/20120809201855_migrate_bookmarks_to_post_actions.rb index 597a015a57f..89db3302139 100644 --- a/db/migrate/20120809201855_migrate_bookmarks_to_post_actions.rb +++ b/db/migrate/20120809201855_migrate_bookmarks_to_post_actions.rb @@ -5,6 +5,6 @@ class MigrateBookmarksToPostActions < ActiveRecord::Migration def down # I can reverse this, but not really worth the work - raise ActiveRecord::IrriversableMigration + raise ActiveRecord::IrreversibleMigration end end diff --git a/db/migrate/20120812235417_retire_expressions.rb b/db/migrate/20120812235417_retire_expressions.rb index 164e1999098..696d9a39f89 100644 --- a/db/migrate/20120812235417_retire_expressions.rb +++ b/db/migrate/20120812235417_retire_expressions.rb @@ -15,6 +15,6 @@ select end def down - raise ActiveRecord::IrriversableMigration + raise ActiveRecord::IrreversibleMigration end end diff --git a/db/migrate/20130120222728_fix_search.rb b/db/migrate/20130120222728_fix_search.rb index 2ca0bf7c8a2..ee44ea1ae80 100644 --- a/db/migrate/20130120222728_fix_search.rb +++ b/db/migrate/20130120222728_fix_search.rb @@ -13,6 +13,6 @@ class FixSearch < ActiveRecord::Migration end def down - raise ActiveRecord::IrriversableMigration + raise ActiveRecord::IrreversibleMigration end end diff --git a/db/migrate/20140504174212_increment_reserved_trust_level_badge_ids.rb b/db/migrate/20140504174212_increment_reserved_trust_level_badge_ids.rb new file mode 100644 index 00000000000..ff3e00f1939 --- /dev/null +++ b/db/migrate/20140504174212_increment_reserved_trust_level_badge_ids.rb @@ -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 diff --git a/lib/boost_trust_level.rb b/lib/boost_trust_level.rb index bb06aa0eae8..e36eab8b4ca 100644 --- a/lib/boost_trust_level.rb +++ b/lib/boost_trust_level.rb @@ -18,6 +18,7 @@ class BoostTrustLevel @user.update_attributes!(trust_level: @level) end @logger.log_trust_level_change(@user, previous_level, @level) + BadgeGranter.update_trust_level_badges!(@user) success end diff --git a/spec/controllers/badges_controller_spec.rb b/spec/controllers/badges_controller_spec.rb index adc3957d0c9..61b6994c716 100644 --- a/spec/controllers/badges_controller_spec.rb +++ b/spec/controllers/badges_controller_spec.rb @@ -9,7 +9,7 @@ describe BadgesController do response.status.should == 200 parsed = JSON.parse(response.body) - parsed["badges"].length.should == 1 + parsed["badges"].length.should == Badge.count end end diff --git a/spec/services/badge_granter_spec.rb b/spec/services/badge_granter_spec.rb index a186d6f85a4..b441097a8d4 100644 --- a/spec/services/badge_granter_spec.rb +++ b/spec/services/badge_granter_spec.rb @@ -1,10 +1,15 @@ require 'spec_helper' +require_dependency 'boost_trust_level' describe BadgeGranter do let(:badge) { Fabricate(:badge) } let(:user) { Fabricate(:user) } + before do + SiteSetting.enable_badges = true + end + describe 'grant' do it 'grants a badge' do @@ -66,4 +71,27 @@ describe BadgeGranter do 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 diff --git a/test/javascripts/models/badge_test.js b/test/javascripts/models/badge_test.js index a4365e352a4..9e4eed9aeea 100644 --- a/test/javascripts/models/badge_test.js +++ b/test/javascripts/models/badge_test.js @@ -13,7 +13,7 @@ test('displayName', function() { this.stub(I18n, "t").returnsArg(0); 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() { From c07244a4e69be0e448ede7cadf8ef1d283e684f4 Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Wed, 14 May 2014 21:01:41 +0530 Subject: [PATCH 2/3] Refactor BadgeGranter.update_trust_level_badges! -> update_badges. --- app/models/user.rb | 2 +- app/services/badge_granter.rb | 25 ++++++++++++++----------- lib/boost_trust_level.rb | 2 +- spec/services/badge_granter_spec.rb | 4 ++-- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index e064afac344..a141fe15830 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -447,7 +447,7 @@ class User < ActiveRecord::Base transaction do self.save! Group.user_trust_level_change!(self.id, self.trust_level) - BadgeGranter.update_trust_level_badges!(self) + BadgeGranter.update_badges(self, trust_level: trust_level) end end diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index fb0e07a7c75..7fc2ff14932 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -56,17 +56,20 @@ class BadgeGranter 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 + def self.update_badges(user, opts={}) + if opts.has_key?(:trust_level) + # Update trust level badges. + trust_level = opts[:trust_level] + Badge.trust_level_badge_ids.each do |badge_id| + user_badge = UserBadge.find_by(user_id: user.id, badge_id: badge_id) + if user_badge + # Revoke the badge if trust level was lowered. + BadgeGranter.revoke(user_badge) if trust_level < badge_id + else + # Grant the badge if trust level was increased. + badge = Badge.find(badge_id) + BadgeGranter.grant(badge, user) if trust_level >= badge_id + end end end end diff --git a/lib/boost_trust_level.rb b/lib/boost_trust_level.rb index e36eab8b4ca..87ea55f1355 100644 --- a/lib/boost_trust_level.rb +++ b/lib/boost_trust_level.rb @@ -18,7 +18,7 @@ class BoostTrustLevel @user.update_attributes!(trust_level: @level) end @logger.log_trust_level_change(@user, previous_level, @level) - BadgeGranter.update_trust_level_badges!(@user) + BadgeGranter.update_badges(@user, trust_level: @level) success end diff --git a/spec/services/badge_granter_spec.rb b/spec/services/badge_granter_spec.rb index b441097a8d4..d155eb17530 100644 --- a/spec/services/badge_granter_spec.rb +++ b/spec/services/badge_granter_spec.rb @@ -76,12 +76,12 @@ describe BadgeGranter do let(:logger) { StaffActionLogger.new(Fabricate(:admin)) } it "is called by User#change_trust_level!" do - BadgeGranter.expects(:update_trust_level_badges!) + BadgeGranter.expects(:update_badges) user.change_trust_level!(:basic) end it "is called by BoostTrustLevel#save!" do - BadgeGranter.expects(:update_trust_level_badges!) + BadgeGranter.expects(:update_badges) BoostTrustLevel.new(user: user, level: 1, logger: logger).save! end From 8c2ec4c52afc3d827b8f8501fcc16d026d4286f3 Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Thu, 15 May 2014 23:13:04 +0530 Subject: [PATCH 3/3] Get rid of update_badges mocks. --- spec/services/badge_granter_spec.rb | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/spec/services/badge_granter_spec.rb b/spec/services/badge_granter_spec.rb index d155eb17530..68b94bd3842 100644 --- a/spec/services/badge_granter_spec.rb +++ b/spec/services/badge_granter_spec.rb @@ -71,21 +71,11 @@ describe BadgeGranter do end - context "revoke" do + context "update_badges" do let(:user) { Fabricate(:user) } let(:logger) { StaffActionLogger.new(Fabricate(:admin)) } - it "is called by User#change_trust_level!" do - BadgeGranter.expects(:update_badges) - user.change_trust_level!(:basic) - end - - it "is called by BoostTrustLevel#save!" do - BadgeGranter.expects(:update_badges) - BoostTrustLevel.new(user: user, level: 1, logger: logger).save! - end - - it "grants and revokes badges" do + it "grants and revokes trust level 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!