From 67a2b2598d0cb08e887f6841c5a80060ffe4617d Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Tue, 10 Jun 2014 06:53:18 +0530 Subject: [PATCH 01/11] Cosmetic changes. --- .../javascripts/admin/controllers/admin_badge_controller.js | 4 +++- app/assets/javascripts/discourse/models/user_badge.js | 4 ++-- app/assets/javascripts/discourse/routes/user_badges_route.js | 2 +- app/controllers/user_badges_controller.rb | 2 +- spec/controllers/user_badges_controller_spec.rb | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/admin/controllers/admin_badge_controller.js b/app/assets/javascripts/admin/controllers/admin_badge_controller.js index cdc06cfe7..3fb21eab6 100644 --- a/app/assets/javascripts/admin/controllers/admin_badge_controller.js +++ b/app/assets/javascripts/admin/controllers/admin_badge_controller.js @@ -8,6 +8,8 @@ @module Discourse **/ +var RESERVED_BADGE_COUNT = 100; + Discourse.AdminBadgeController = Discourse.ObjectController.extend({ /** Whether this badge has been selected. @@ -31,5 +33,5 @@ Discourse.AdminBadgeController = Discourse.ObjectController.extend({ @property readOnly @type {Boolean} **/ - readOnly: Ember.computed.lt('model.id', 100) + readOnly: Ember.computed.lt('model.id', RESERVED_BADGE_COUNT) }); diff --git a/app/assets/javascripts/discourse/models/user_badge.js b/app/assets/javascripts/discourse/models/user_badge.js index a7005341c..410dbd4c8 100644 --- a/app/assets/javascripts/discourse/models/user_badge.js +++ b/app/assets/javascripts/discourse/models/user_badge.js @@ -84,8 +84,8 @@ Discourse.UserBadge.reopenClass({ **/ findByUsername: function(username, options) { var url = "/user_badges.json?username=" + username; - if (options && options.aggregated) { - url += "&aggregated=true"; + if (options && options.grouped) { + url += "&grouped=true"; } return Discourse.ajax(url).then(function(json) { return Discourse.UserBadge.createFromJson(json); diff --git a/app/assets/javascripts/discourse/routes/user_badges_route.js b/app/assets/javascripts/discourse/routes/user_badges_route.js index c5ce95d1c..b6717117f 100644 --- a/app/assets/javascripts/discourse/routes/user_badges_route.js +++ b/app/assets/javascripts/discourse/routes/user_badges_route.js @@ -8,7 +8,7 @@ **/ Discourse.UserBadgesRoute = Discourse.Route.extend({ model: function() { - return Discourse.UserBadge.findByUsername(this.modelFor('user').get('username_lower'), {aggregated: true}); + return Discourse.UserBadge.findByUsername(this.modelFor('user').get('username_lower'), {grouped: true}); }, setupController: function(controller, model) { diff --git a/app/controllers/user_badges_controller.rb b/app/controllers/user_badges_controller.rb index 373234bb5..e2f96d6ec 100644 --- a/app/controllers/user_badges_controller.rb +++ b/app/controllers/user_badges_controller.rb @@ -16,7 +16,7 @@ class UserBadgesController < ApplicationController user_badges = user_badges.includes(:user, :granted_by, badge: :badge_type) - if params[:aggregated] + if params[:grouped] user_badges = user_badges.group(:badge_id).select(UserBadge.attribute_names.map {|x| "MAX(#{x}) as #{x}" }, 'COUNT(*) as count') end diff --git a/spec/controllers/user_badges_controller_spec.rb b/spec/controllers/user_badges_controller_spec.rb index a26b52650..d93e990ea 100644 --- a/spec/controllers/user_badges_controller_spec.rb +++ b/spec/controllers/user_badges_controller_spec.rb @@ -28,7 +28,7 @@ describe UserBadgesController do end it 'includes counts when passed the aggregate argument' do - xhr :get, :index, username: user.username, aggregated: true + xhr :get, :index, username: user.username, grouped: true response.status.should == 200 parsed = JSON.parse(response.body) From 7fa972676a4bffb39b305f7888cf00a41268cf9a Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Tue, 10 Jun 2014 06:54:54 +0530 Subject: [PATCH 02/11] Add post_id to user_badges table. --- db/migrate/20140610012414_add_post_id_to_user_badges.rb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 db/migrate/20140610012414_add_post_id_to_user_badges.rb diff --git a/db/migrate/20140610012414_add_post_id_to_user_badges.rb b/db/migrate/20140610012414_add_post_id_to_user_badges.rb new file mode 100644 index 000000000..26ecd890c --- /dev/null +++ b/db/migrate/20140610012414_add_post_id_to_user_badges.rb @@ -0,0 +1,5 @@ +class AddPostIdToUserBadges < ActiveRecord::Migration + def change + add_column :user_badges, :post_id, :integer + end +end From e0fd1f6f5e8254f838d71528a3c9f9db01844cb9 Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Tue, 10 Jun 2014 13:02:22 +0530 Subject: [PATCH 03/11] Add ability to specify custom font awesome icon for badges. --- .../javascripts/admin/templates/badges.js.handlebars | 7 ++++++- .../javascripts/discourse/components/user-badge.js.es6 | 6 +++++- app/assets/javascripts/discourse/models/badge.js | 3 ++- .../templates/components/user-badge.js.handlebars | 4 +++- app/controllers/admin/badges_controller.rb | 1 + app/serializers/badge_serializer.rb | 2 +- config/locales/client.en.yml | 1 + db/migrate/20140610012833_add_icon_to_badges.rb | 5 +++++ 8 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20140610012833_add_icon_to_badges.rb diff --git a/app/assets/javascripts/admin/templates/badges.js.handlebars b/app/assets/javascripts/admin/templates/badges.js.handlebars index ae0524def..f9c08422a 100644 --- a/app/assets/javascripts/admin/templates/badges.js.handlebars +++ b/app/assets/javascripts/admin/templates/badges.js.handlebars @@ -23,7 +23,7 @@
- {{input type="text" name="name" value=name disabled=readOnly}} + {{input type="text" name="name" value=name disabled=readonly}}
{{#if showDisplayName}} @@ -33,6 +33,11 @@ {{/if}} +
+ + {{input type="text" name="name" value=icon disabled=readonly}} +
+
{{view Ember.Select name="badge_type_id" value=badge_type_id diff --git a/app/assets/javascripts/discourse/components/user-badge.js.es6 b/app/assets/javascripts/discourse/components/user-badge.js.es6 index b4e97ecb0..bc63ace44 100644 --- a/app/assets/javascripts/discourse/components/user-badge.js.es6 +++ b/app/assets/javascripts/discourse/components/user-badge.js.es6 @@ -7,5 +7,9 @@ export default Ember.Component.extend({ showGrantCount: function() { return this.get('count') && this.get('count') > 1; - }.property('count') + }.property('count'), + + isIcon: function() { + return this.get('badge.icon').match(/^fa-/); + }.property('badge.icon') }); diff --git a/app/assets/javascripts/discourse/models/badge.js b/app/assets/javascripts/discourse/models/badge.js index f709ef29c..682534d38 100644 --- a/app/assets/javascripts/discourse/models/badge.js +++ b/app/assets/javascripts/discourse/models/badge.js @@ -116,7 +116,8 @@ Discourse.Badge = Discourse.Model.extend({ description: this.get('description'), badge_type_id: this.get('badge_type_id'), allow_title: !!this.get('allow_title'), - multiple_grant: !!this.get('multiple_grant') + multiple_grant: !!this.get('multiple_grant'), + icon: this.get('icon') } }).then(function(json) { self.updateFromJson(json); 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 1e749080a..dceafcda7 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,8 @@ {{#link-to 'badges.show' badge}} - + {{#if isIcon}} + + {{/if}} {{badge.displayName}} {{#if showGrantCount}} (× {{count}}) diff --git a/app/controllers/admin/badges_controller.rb b/app/controllers/admin/badges_controller.rb index 2715f4cdf..33d7f7645 100644 --- a/app/controllers/admin/badges_controller.rb +++ b/app/controllers/admin/badges_controller.rb @@ -36,6 +36,7 @@ class Admin::BadgesController < Admin::AdminController badge.badge_type = BadgeType.find(params[:badge_type_id]) badge.allow_title = params[:allow_title] badge.multiple_grant = params[:multiple_grant] + badge.icon = params[:icon] badge end end diff --git a/app/serializers/badge_serializer.rb b/app/serializers/badge_serializer.rb index ac6e2fcc0..22111deee 100644 --- a/app/serializers/badge_serializer.rb +++ b/app/serializers/badge_serializer.rb @@ -1,5 +1,5 @@ class BadgeSerializer < ApplicationSerializer - attributes :id, :name, :description, :grant_count, :allow_title, :multiple_grant + attributes :id, :name, :description, :grant_count, :allow_title, :multiple_grant, :icon has_one :badge_type end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 9be4a236d..d10cb8fe7 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1856,6 +1856,7 @@ en: no_badges: There are no badges that can be granted. allow_title: Allow badge to be used as a title multiple_grant: Can be granted multiple times + icon: Icon lightbox: download: "download" diff --git a/db/migrate/20140610012833_add_icon_to_badges.rb b/db/migrate/20140610012833_add_icon_to_badges.rb new file mode 100644 index 000000000..761038507 --- /dev/null +++ b/db/migrate/20140610012833_add_icon_to_badges.rb @@ -0,0 +1,5 @@ +class AddIconToBadges < ActiveRecord::Migration + def change + add_column :badges, :icon, :string, default: "fa-certificate" + end +end From fcfc6177c25a378f6e72d33f32f9533a0fdf21a1 Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Wed, 11 Jun 2014 07:44:47 +0530 Subject: [PATCH 04/11] Allow specifying URLs as badge certificates. --- .../templates/components/user-badge.js.handlebars | 2 ++ app/assets/stylesheets/common/base/user-badges.scss | 11 +++++++++++ 2 files changed, 13 insertions(+) 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 dceafcda7..e62a8f762 100644 --- a/app/assets/javascripts/discourse/templates/components/user-badge.js.handlebars +++ b/app/assets/javascripts/discourse/templates/components/user-badge.js.handlebars @@ -2,6 +2,8 @@ {{#if isIcon}} + {{else}} + {{/if}} {{badge.displayName}} {{#if showGrantCount}} diff --git a/app/assets/stylesheets/common/base/user-badges.scss b/app/assets/stylesheets/common/base/user-badges.scss index 15683b6d0..39175c13a 100644 --- a/app/assets/stylesheets/common/base/user-badges.scss +++ b/app/assets/stylesheets/common/base/user-badges.scss @@ -16,6 +16,11 @@ vertical-align: bottom; } + img { + height: 16px; + width: 16px; + } + &.badge-type-gold .fa { color: #ffd700; } @@ -46,6 +51,12 @@ margin-bottom: 5px; } + img { + display: inline-block; + width: 55px; + height: 55px; + } + .count { display: block; font-size: 0.8em; From 41ecba1b775d6fb693ef3797c75615088be96468 Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Sat, 14 Jun 2014 13:25:06 +0530 Subject: [PATCH 05/11] Mark badge notification as read when the notification is clicked. --- app/controllers/badges_controller.rb | 8 ++++++++ app/models/user_badge.rb | 6 ++++++ app/services/badge_granter.rb | 5 +---- spec/controllers/badges_controller_spec.rb | 13 +++++++++++++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/app/controllers/badges_controller.rb b/app/controllers/badges_controller.rb index 03f825c5f..06cd59080 100644 --- a/app/controllers/badges_controller.rb +++ b/app/controllers/badges_controller.rb @@ -16,6 +16,14 @@ class BadgesController < ApplicationController def show params.require(:id) badge = Badge.find(params[:id]) + + if current_user + user_badge = UserBadge.find_by(user_id: current_user.id, badge_id: badge.id) + if user_badge && user_badge.notification + user_badge.notification.update_attributes read: true + end + end + serialized = MultiJson.dump(serialize_data(badge, BadgeSerializer, root: "badge")) respond_to do |format| format.html do diff --git a/app/models/user_badge.rb b/app/models/user_badge.rb index e938a8558..39453322f 100644 --- a/app/models/user_badge.rb +++ b/app/models/user_badge.rb @@ -7,6 +7,12 @@ class UserBadge < ActiveRecord::Base validates :user_id, presence: true validates :granted_at, presence: true validates :granted_by, presence: true + + # This may be inefficient, but not very easy to optimize unless the data hash + # is converted into a hstore. + def notification + @notification ||= self.user.notifications.where(notification_type: Notification.types[:granted_badge]).where("data LIKE ?", "%" + self.badge_id.to_s + "%").select {|n| n.data_hash["badge_id"] == self.badge_id }.first + end end # == Schema Information diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index a15e7d23f..11fbec47d 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -49,10 +49,7 @@ class BadgeGranter user_badge.user.save! end - # Delete notification -- This is inefficient, but not very easy to optimize - # unless the data hash is converted into a hstore. - notification = user_badge.user.notifications.where(notification_type: Notification.types[:granted_badge]).where("data LIKE ?", "%" + user_badge.badge_id.to_s + "%").select {|n| n.data_hash["badge_id"] == user_badge.badge_id }.first - notification && notification.destroy + user_badge.notification && user_badge.notification.destroy! end end diff --git a/spec/controllers/badges_controller_spec.rb b/spec/controllers/badges_controller_spec.rb index 61b6994c7..f45ffd507 100644 --- a/spec/controllers/badges_controller_spec.rb +++ b/spec/controllers/badges_controller_spec.rb @@ -2,6 +2,11 @@ require 'spec_helper' describe BadgesController do let!(:badge) { Fabricate(:badge) } + let(:user) { Fabricate(:user) } + + before do + SiteSetting.enable_badges = true + end context 'index' do it 'should return a list of all badges' do @@ -20,5 +25,13 @@ describe BadgesController do parsed = JSON.parse(response.body) parsed["badge"].should be_present end + + it "should mark the notification as viewed" do + log_in_user(user) + user_badge = BadgeGranter.grant(badge, user) + user_badge.notification.read.should == false + get :show, id: badge.id, format: :json + user_badge.notification.reload.read.should == true + end end end From cd766ed587e4e6197bc9ea4d1fa51fe7c54a9b2f Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Sat, 14 Jun 2014 13:29:14 +0530 Subject: [PATCH 06/11] Use Em.computed.match. --- app/assets/javascripts/discourse/components/user-badge.js.es6 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/assets/javascripts/discourse/components/user-badge.js.es6 b/app/assets/javascripts/discourse/components/user-badge.js.es6 index bc63ace44..0c616cc12 100644 --- a/app/assets/javascripts/discourse/components/user-badge.js.es6 +++ b/app/assets/javascripts/discourse/components/user-badge.js.es6 @@ -9,7 +9,5 @@ export default Ember.Component.extend({ return this.get('count') && this.get('count') > 1; }.property('count'), - isIcon: function() { - return this.get('badge.icon').match(/^fa-/); - }.property('badge.icon') + isIcon: Em.computed.match('badge.icon', /^fa-/) }); From 7daf584251ed00e8e6b8f1dc9f5d195d1bc20cd3 Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Sat, 14 Jun 2014 13:46:38 +0530 Subject: [PATCH 07/11] Add missing tags. --- .../templates/badges/index.js.handlebars | 16 +++++++++------- .../templates/badges/show.js.handlebars | 12 +++++++----- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/discourse/templates/badges/index.js.handlebars b/app/assets/javascripts/discourse/templates/badges/index.js.handlebars index 201e75aa2..5c8a4eb80 100644 --- a/app/assets/javascripts/discourse/templates/badges/index.js.handlebars +++ b/app/assets/javascripts/discourse/templates/badges/index.js.handlebars @@ -2,12 +2,14 @@

{{i18n badges.title}}

- {{#each}} - - - - - - {{/each}} + + {{#each}} + + + + + + {{/each}} +
{{user-badge badge=this}}{{displayDescription}}{{i18n badges.granted count=grant_count}}
{{user-badge badge=this}}{{displayDescription}}{{i18n badges.granted count=grant_count}}
diff --git a/app/assets/javascripts/discourse/templates/badges/show.js.handlebars b/app/assets/javascripts/discourse/templates/badges/show.js.handlebars index e113ccf27..d97eaeb7e 100644 --- a/app/assets/javascripts/discourse/templates/badges/show.js.handlebars +++ b/app/assets/javascripts/discourse/templates/badges/show.js.handlebars @@ -6,11 +6,13 @@ - - - - - + + + + + + +
{{user-badge badge=this}}{{displayDescription}}{{i18n badges.granted count=grant_count}}
{{user-badge badge=this}}{{displayDescription}}{{i18n badges.granted count=grant_count}}
{{#if userBadges}} From a68b47cb9f3faee70bd1236ff8d14329c083ffbd Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Tue, 17 Jun 2014 11:29:28 +0530 Subject: [PATCH 08/11] Add notification_id column to user_badges. --- app/models/badge.rb | 1 + app/models/user_badge.rb | 19 ++++++++----------- app/services/badge_granter.rb | 7 ++----- ...53829_add_notification_id_to_user_badge.rb | 5 +++++ 4 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 db/migrate/20140617053829_add_notification_id_to_user_badge.rb diff --git a/app/models/badge.rb b/app/models/badge.rb index b891ef02d..d090c61a2 100644 --- a/app/models/badge.rb +++ b/app/models/badge.rb @@ -35,6 +35,7 @@ end # updated_at :datetime # allow_title :boolean default(FALSE), not null # multiple_grant :boolean default(FALSE), not null +# icon :string(255) default("fa-certificate") # # Indexes # diff --git a/app/models/user_badge.rb b/app/models/user_badge.rb index 39453322f..5781bd652 100644 --- a/app/models/user_badge.rb +++ b/app/models/user_badge.rb @@ -2,28 +2,25 @@ class UserBadge < ActiveRecord::Base belongs_to :badge belongs_to :user belongs_to :granted_by, class_name: 'User' + belongs_to :notification, dependent: :destroy validates :badge_id, presence: true, uniqueness: {scope: :user_id}, if: 'badge.single_grant?' validates :user_id, presence: true validates :granted_at, presence: true validates :granted_by, presence: true - - # This may be inefficient, but not very easy to optimize unless the data hash - # is converted into a hstore. - def notification - @notification ||= self.user.notifications.where(notification_type: Notification.types[:granted_badge]).where("data LIKE ?", "%" + self.badge_id.to_s + "%").select {|n| n.data_hash["badge_id"] == self.badge_id }.first - end end # == Schema Information # # Table name: user_badges # -# id :integer not null, primary key -# badge_id :integer not null -# user_id :integer not null -# granted_at :datetime not null -# granted_by_id :integer not null +# id :integer not null, primary key +# badge_id :integer not null +# user_id :integer not null +# granted_at :datetime not null +# granted_by_id :integer not null +# post_id :integer +# notification_id :integer # # Indexes # diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index 11fbec47d..35c1f228f 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -25,9 +25,8 @@ class BadgeGranter end if SiteSetting.enable_badges? - @user.notifications.create(notification_type: Notification.types[:granted_badge], - data: { badge_id: @badge.id, - badge_name: @badge.name }.to_json) + notification = @user.notifications.create(notification_type: Notification.types[:granted_badge], data: { badge_id: @badge.id, badge_name: @badge.name }.to_json) + user_badge.update_attributes notification_id: notification.id end end end @@ -48,8 +47,6 @@ class BadgeGranter user_badge.user.title = nil user_badge.user.save! end - - user_badge.notification && user_badge.notification.destroy! end end diff --git a/db/migrate/20140617053829_add_notification_id_to_user_badge.rb b/db/migrate/20140617053829_add_notification_id_to_user_badge.rb new file mode 100644 index 000000000..e066ac3cf --- /dev/null +++ b/db/migrate/20140617053829_add_notification_id_to_user_badge.rb @@ -0,0 +1,5 @@ +class AddNotificationIdToUserBadge < ActiveRecord::Migration + def change + add_column :user_badges, :notification_id, :integer + end +end From b3f403952b6e3250fbb8b238df7d8cc25c5e2714 Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Tue, 17 Jun 2014 20:41:52 +0530 Subject: [PATCH 09/11] Move badge grant_count updating to the UserBadge model callbacks. --- app/models/user_badge.rb | 8 ++++++++ app/services/badge_granter.rb | 2 -- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/models/user_badge.rb b/app/models/user_badge.rb index 5781bd652..245321951 100644 --- a/app/models/user_badge.rb +++ b/app/models/user_badge.rb @@ -8,6 +8,14 @@ class UserBadge < ActiveRecord::Base validates :user_id, presence: true validates :granted_at, presence: true validates :granted_by, presence: true + + after_create do + Badge.increment_counter 'grant_count', self.badge_id + end + + after_destroy do + Badge.decrement_counter 'grant_count', self.badge_id + end end # == Schema Information diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index 35c1f228f..f8983e409 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -19,7 +19,6 @@ class BadgeGranter user_badge = UserBadge.create!(badge: @badge, user: @user, granted_by: @granted_by, granted_at: Time.now) - Badge.increment_counter 'grant_count', @badge.id if @granted_by != Discourse.system_user StaffActionLogger.new(@granted_by).log_badge_grant(user_badge) end @@ -37,7 +36,6 @@ class BadgeGranter def self.revoke(user_badge, options={}) UserBadge.transaction do user_badge.destroy! - Badge.decrement_counter 'grant_count', user_badge.badge_id if options[:revoked_by] StaffActionLogger.new(options[:revoked_by]).log_badge_revoke(user_badge) end From b5eea1d79f5381de2e3e7552957c289e07e3b7f9 Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Tue, 17 Jun 2014 12:37:46 +0530 Subject: [PATCH 10/11] Grant system badges in a background job. --- app/jobs/regular/update_badges.rb | 25 +++++++++++++++++++++++++ app/services/badge_granter.rb | 18 ++---------------- lib/promotion.rb | 2 +- 3 files changed, 28 insertions(+), 17 deletions(-) create mode 100644 app/jobs/regular/update_badges.rb diff --git a/app/jobs/regular/update_badges.rb b/app/jobs/regular/update_badges.rb new file mode 100644 index 000000000..ba33ce6c2 --- /dev/null +++ b/app/jobs/regular/update_badges.rb @@ -0,0 +1,25 @@ +module Jobs + class UpdateBadges < Jobs::Base + + def execute(args) + self.send(args[:action], args) + end + + def trust_level_change(args) + user = User.find(args[:user_id]) + trust_level = user.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 +end diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index f8983e409..baa759daa 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -48,22 +48,8 @@ class BadgeGranter end end - 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 + def self.update_badges(args) + Jobs.enqueue(:update_badges, args) end end diff --git a/lib/promotion.rb b/lib/promotion.rb index c4ae8f963..94fa3913d 100644 --- a/lib/promotion.rb +++ b/lib/promotion.rb @@ -60,7 +60,7 @@ class Promotion @user.user_profile.recook_bio @user.user_profile.save! Group.user_trust_level_change!(@user.id, @user.trust_level) - BadgeGranter.update_badges(@user, trust_level: @user.trust_level) + BadgeGranter.update_badges(action: :trust_level_change, user_id: @user.id) end true From 3ba65af19e731ede4bbe3ecfa7d33debfd400565 Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Tue, 17 Jun 2014 11:59:49 +0530 Subject: [PATCH 11/11] Add like-based system badges. --- app/jobs/regular/update_badges.rb | 17 +++++++++++++++++ app/models/post_action.rb | 20 +++++++++++++------- app/services/badge_granter.rb | 7 +++++-- config/locales/client.en.yml | 12 ++++++++++++ db/fixtures/601_badges.rb | 27 +++++++++++++++++++++++++++ spec/services/badge_granter_spec.rb | 24 ++++++++++++++++++++++++ 6 files changed, 98 insertions(+), 9 deletions(-) diff --git a/app/jobs/regular/update_badges.rb b/app/jobs/regular/update_badges.rb index ba33ce6c2..3432b02e6 100644 --- a/app/jobs/regular/update_badges.rb +++ b/app/jobs/regular/update_badges.rb @@ -21,5 +21,22 @@ module Jobs end end + def post_like(args) + post = Post.find(args[:post_id]) + user = post.user + + # Grant "Welcome" badge to the user if they do not already have it. + BadgeGranter.grant(Badge.find(5), user) + + [{id: 6, count: 10}, {id: 7, count: 25}, {id: 8, count: 100}].each do |b| + if post.like_count >= b[:count] + BadgeGranter.grant(Badge.find(b[:id]), user, post_id: post.id) + else + user_badge = UserBadge.find_by(badge_id: b[:id], user_id: user.id, post_id: post.id) + user_badge && BadgeGranter.revoke(user_badge) + end + end + end + end end diff --git a/app/models/post_action.rb b/app/models/post_action.rb index 7aab8f6ea..86dcf78d8 100644 --- a/app/models/post_action.rb +++ b/app/models/post_action.rb @@ -131,13 +131,19 @@ class PostAction < ActiveRecord::Base post.topic.posts_count != 1 end - create( post_id: post.id, - user_id: user.id, - post_action_type_id: post_action_type_id, - message: opts[:message], - staff_took_action: opts[:take_action] || false, - related_post_id: related_post_id, - targets_topic: !!targets_topic ) + post_action = create( post_id: post.id, + user_id: user.id, + post_action_type_id: post_action_type_id, + message: opts[:message], + staff_took_action: opts[:take_action] || false, + related_post_id: related_post_id, + targets_topic: !!targets_topic ) + + if post_action && post_action.is_like? + BadgeGranter.update_badges(action: :post_like, post_id: post.id) + end + + post_action rescue ActiveRecord::RecordNotUnique # can happen despite being .create diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index baa759daa..b132c7af1 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -3,6 +3,7 @@ class BadgeGranter def initialize(badge, user, opts={}) @badge, @user, @opts = badge, user, opts @granted_by = opts[:granted_by] || Discourse.system_user + @post_id = opts[:post_id] end def self.grant(badge, user, opts={}) @@ -12,12 +13,14 @@ class BadgeGranter def grant return if @granted_by and !Guardian.new(@granted_by).can_grant_badges?(@user) - user_badge = UserBadge.find_by(badge_id: @badge.id, user_id: @user.id) + user_badge = UserBadge.find_by(badge_id: @badge.id, user_id: @user.id, post_id: @post_id) if user_badge.nil? || @badge.multiple_grant? UserBadge.transaction do user_badge = UserBadge.create!(badge: @badge, user: @user, - granted_by: @granted_by, granted_at: Time.now) + granted_by: @granted_by, + granted_at: Time.now, + post_id: @post_id) if @granted_by != Discourse.system_user StaffActionLogger.new(@granted_by).log_badge_grant(user_badge) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index d10cb8fe7..de1083278 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1927,3 +1927,15 @@ en: elder: name: Elder description: Granted global edit, pin, close, archive, split and merge. + welcome: + name: Welcome + description: Received a like. + nice_post: + name: Nice Post + description: Received 10 likes on a post. + good_post: + name: Good Post + description: Received 25 likes on a post. + great_post: + name: Great Post + description: Received 100 likes on a post. diff --git a/db/fixtures/601_badges.rb b/db/fixtures/601_badges.rb index 4e16c48a2..e4479ffc8 100644 --- a/db/fixtures/601_badges.rb +++ b/db/fixtures/601_badges.rb @@ -1,3 +1,4 @@ +# Trust level system badges. trust_level_badges = [ {id: 1, name: "Basic User", type: 3}, {id: 2, name: "Regular User", type: 3}, @@ -44,3 +45,29 @@ SQL Badge.where(id: Badge.trust_level_badge_ids).each {|badge| badge.reset_grant_count! } end +# +# Like system badges. +like_badges = [ + {id: 5, name: "Welcome", type: 3, multiple: false}, + {id: 6, name: "Nice Post", type: 3, multiple: true}, + {id: 7, name: "Good Post", type: 2, multiple: true}, + {id: 8, name: "Great Post", type: 1, multiple: true} +] + +like_badges.each do |spec| + Badge.seed do |b| + b.id = spec[:id] + b.name = spec[:name] + b.badge_type_id = spec[:type] + b.multiple_grant = spec[:multiple] + end +end + +# Create an example badge if one does not already exist. +if Badge.find_by(id: 101).nil? + Badge.seed do |b| + b.id = 101 + b.name = "Example Badge" + b.badge_type_id = 3 + end +end diff --git a/spec/services/badge_granter_spec.rb b/spec/services/badge_granter_spec.rb index 8c8efaf1b..f893bd42c 100644 --- a/spec/services/badge_granter_spec.rb +++ b/spec/services/badge_granter_spec.rb @@ -72,6 +72,7 @@ describe BadgeGranter do context "update_badges" do let(:user) { Fabricate(:user) } + let(:liker) { Fabricate(:user) } it "grants and revokes trust level badges" do user.change_trust_level!(:elder) @@ -80,6 +81,29 @@ describe BadgeGranter do 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 + + it "grants system like badges" do + post = create_post(user: user) + # Welcome badge + PostAction.act(liker, post, PostActionType.types[:like]) + UserBadge.find_by(user_id: user.id, badge_id: 5).should_not be_nil + # Nice post badge + post.update_attributes like_count: 10 + BadgeGranter.update_badges(action: :post_like, post_id: post.id) + UserBadge.find_by(user_id: user.id, badge_id: 6).should_not be_nil + # Good post badge + post.update_attributes like_count: 25 + BadgeGranter.update_badges(action: :post_like, post_id: post.id) + UserBadge.find_by(user_id: user.id, badge_id: 7).should_not be_nil + # Great post badge + post.update_attributes like_count: 100 + BadgeGranter.update_badges(action: :post_like, post_id: post.id) + UserBadge.find_by(user_id: user.id, badge_id: 8).should_not be_nil + # Revoke badges on unlike + post.update_attributes like_count: 99 + BadgeGranter.update_badges(action: :post_like, post_id: post.id) + UserBadge.find_by(user_id: user.id, badge_id: 8).should be_nil + end end end