Compare View

switch
from
...
to
 
Commits (27)
controllers/admin/gamification_plugin_badges_controller.rb
1 class GamificationPluginBadgesController < PluginAdminController 1 class GamificationPluginBadgesController < PluginAdminController
2 2
3 def index 3 def index
4 - @gamification_plugin_badges = environment.gamification_plugin_badges 4 + @gamification_plugin_badges = environment.gamification_plugin_badges.group_by(&:owner)
5 end 5 end
6 6
7 def show 7 def show
@@ -17,8 +17,13 @@ class GamificationPluginBadgesController &lt; PluginAdminController @@ -17,8 +17,13 @@ class GamificationPluginBadgesController &lt; PluginAdminController
17 end 17 end
18 18
19 def create 19 def create
  20 + owner_id = params[:gamification_plugin_badge].delete(:owner_id)
20 @gamification_plugin_badge = GamificationPlugin::Badge.new(params[:gamification_plugin_badge]) 21 @gamification_plugin_badge = GamificationPlugin::Badge.new(params[:gamification_plugin_badge])
21 - @gamification_plugin_badge.owner = environment 22 + if owner_id.present?
  23 + @gamification_plugin_badge.owner = environment.organizations.find(owner_id)
  24 + else
  25 + @gamification_plugin_badge.owner = environment
  26 + end
22 27
23 if @gamification_plugin_badge.save 28 if @gamification_plugin_badge.save
24 session[:notice] = _('Badge was successfully created.') 29 session[:notice] = _('Badge was successfully created.')
@@ -31,6 +36,14 @@ class GamificationPluginBadgesController &lt; PluginAdminController @@ -31,6 +36,14 @@ class GamificationPluginBadgesController &lt; PluginAdminController
31 def update 36 def update
32 @gamification_plugin_badge = environment.gamification_plugin_badges.find(params[:id]) 37 @gamification_plugin_badge = environment.gamification_plugin_badges.find(params[:id])
33 38
  39 + # FIXME avoid code duplication
  40 + owner_id = params[:gamification_plugin_badge].delete(:owner_id)
  41 + if owner_id.present?
  42 + @gamification_plugin_badge.owner = environment.organizations.find(owner_id)
  43 + else
  44 + @gamification_plugin_badge.owner = environment
  45 + end
  46 +
34 if @gamification_plugin_badge.update_attributes(params[:gamification_plugin_badge]) 47 if @gamification_plugin_badge.update_attributes(params[:gamification_plugin_badge])
35 session[:notice] = _('Badge was successfully updated.') 48 session[:notice] = _('Badge was successfully updated.')
36 redirect_to :action => :index 49 redirect_to :action => :index
@@ -39,6 +52,10 @@ class GamificationPluginBadgesController &lt; PluginAdminController @@ -39,6 +52,10 @@ class GamificationPluginBadgesController &lt; PluginAdminController
39 end 52 end
40 end 53 end
41 54
  55 + def search_owners
  56 + render :text => prepare_to_token_input(environment.organizations).to_json
  57 + end
  58 +
42 def destroy 59 def destroy
43 @gamification_plugin_badge = environment.gamification_plugin_badges.find(params[:id]) 60 @gamification_plugin_badge = environment.gamification_plugin_badges.find(params[:id])
44 @gamification_plugin_badge.destroy 61 @gamification_plugin_badge.destroy
lib/ext/environment.rb
@@ -2,6 +2,11 @@ require_dependency &#39;environment&#39; @@ -2,6 +2,11 @@ require_dependency &#39;environment&#39;
2 2
3 class Environment 3 class Environment
4 4
5 - has_many :gamification_plugin_badges, :class_name => 'GamificationPlugin::Badge', :foreign_key => 'owner_id', :source => :owner 5 + has_many :gamification_plugin_environment_badges, :class_name => 'GamificationPlugin::Badge', :foreign_key => 'owner_id', :source => :owner
  6 + has_many :gamification_plugin_organization_badges, :through => :organizations
  7 +
  8 + def gamification_plugin_badges
  9 + GamificationPlugin::Badge.joins('left join profiles on profiles.id = owner_id').where(['owner_id = ? or profiles.environment_id = ?', self.id, self.id])
  10 + end
6 11
7 end 12 end
lib/ext/organization.rb 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +require_dependency 'organization'
  2 +
  3 +class Organization
  4 +
  5 + has_many :gamification_plugin_organization_badges, :class_name => 'GamificationPlugin::Badge', :foreign_key => 'owner_id', :source => :owner
  6 +
  7 +end
lib/gamification_plugin/api.rb
@@ -3,7 +3,7 @@ class GamificationPlugin::API &lt; Grape::API @@ -3,7 +3,7 @@ class GamificationPlugin::API &lt; Grape::API
3 resource :gamification_plugin do 3 resource :gamification_plugin do
4 4
5 get 'badges' do 5 get 'badges' do
6 - environment.gamification_plugin_badges.group(:name).count 6 + environment.gamification_plugin_badges.group('gamification_plugin_badges.name').count
7 end 7 end
8 8
9 resource :my do 9 resource :my do
@@ -57,7 +57,7 @@ class GamificationPlugin::API &lt; Grape::API @@ -57,7 +57,7 @@ class GamificationPlugin::API &lt; Grape::API
57 get ':id/points_by_profile' do 57 get ':id/points_by_profile' do
58 person = environment.people.visible_for_person(current_person).find_by_id(params[:id]) 58 person = environment.people.visible_for_person(current_person).find_by_id(params[:id])
59 return not_found! if person.blank? 59 return not_found! if person.blank?
60 - {points: person.points_by_type(params[:profile]) } 60 + {points: person.points_by_profile(params[:profile]) }
61 end 61 end
62 62
63 get ':id/points_out_of_profiles' do 63 get ':id/points_out_of_profiles' do
@@ -75,4 +75,3 @@ class GamificationPlugin::API &lt; Grape::API @@ -75,4 +75,3 @@ class GamificationPlugin::API &lt; Grape::API
75 end 75 end
76 end 76 end
77 end 77 end
78 -  
lib/gamification_plugin/badge.rb
1 -class GamificationPlugin::Badge < Noosfero::Plugin::ActiveRecord 1 +class GamificationPlugin::Badge < ActiveRecord::Base
2 2
3 belongs_to :owner, :polymorphic => true 3 belongs_to :owner, :polymorphic => true
4 4
lib/gamification_plugin/dashboard_helper.rb
@@ -12,13 +12,22 @@ module GamificationPlugin::DashboardHelper @@ -12,13 +12,22 @@ module GamificationPlugin::DashboardHelper
12 end 12 end
13 13
14 def score_point_category(point) 14 def score_point_category(point)
15 - point = GamificationPlugin::PointsType.where(name: point.score.category).first 15 + point = GamificationPlugin::PointsType.where(id: point.score.category).first
16 point.nil? ? '' : point.description 16 point.nil? ? '' : point.description
17 end 17 end
18 18
  19 + def score_point_target_link(point, text)
  20 + url = Merit::PointRules.target_url(point)
  21 + url.present? ? link_to(text, url) : text
  22 + end
  23 +
  24 + def score_point_action_class(point)
  25 + point.undo_rule? ? 'undo_action':'do_action'
  26 + end
  27 +
19 def ranking(target, from_date=nil, limit=10) 28 def ranking(target, from_date=nil, limit=10)
20 # FIXME move these queries to profile model 29 # FIXME move these queries to profile model
21 - ranking = Profile.select('profiles.*, sum(num_points) as gamification_points, ROW_NUMBER() OVER(order by sum(num_points) DESC) as gamification_position').joins(:sash => {:scores => :score_points}).where(:type => target.class).order('sum(num_points) DESC').group('profiles.id') 30 + ranking = Profile.select('profiles.*, sum(num_points) as gamification_points, ROW_NUMBER() OVER(order by sum(num_points) DESC) as gamification_position').joins(:sash => {:scores => :score_points}).where(:type => target.class).reorder('sum(num_points) DESC').group('profiles.id')
22 ranking = ranking.where("merit_score_points.created_at >= ?", from_date) if from_date.present? 31 ranking = ranking.where("merit_score_points.created_at >= ?", from_date) if from_date.present?
23 target_ranking = Profile.from("(#{ranking.to_sql}) profiles").where('profiles.id' => target.id).first 32 target_ranking = Profile.from("(#{ranking.to_sql}) profiles").where('profiles.id' => target.id).first
24 33
@@ -35,4 +44,15 @@ module GamificationPlugin::DashboardHelper @@ -35,4 +44,15 @@ module GamificationPlugin::DashboardHelper
35 (context_ranking.blank? ? '' : render(:partial => 'gamification/ranking', :locals => {:ranking => context_ranking, :target_ranking => target_ranking, :ranking_class => 'context'})) 44 (context_ranking.blank? ? '' : render(:partial => 'gamification/ranking', :locals => {:ranking => context_ranking, :target_ranking => target_ranking, :ranking_class => 'context'}))
36 end 45 end
37 46
  47 + def badges_title(owner)
  48 + return _('Badges for %s' % owner.name) if owner.kind_of?(Organization)
  49 + _('Badges')
  50 + end
  51 +
  52 + def grouped_badges
  53 + environment.gamification_plugin_badges.all.group_by(&:owner).sort do |a, b|
  54 + a.first.kind_of?(Environment) ? -1 : a.first.name <=> b.first.name
  55 + end
  56 + end
  57 +
38 end 58 end
lib/merit/badge_rules.rb
@@ -14,6 +14,7 @@ module Merit @@ -14,6 +14,7 @@ module Merit
14 action: 'comment#create', 14 action: 'comment#create',
15 default_threshold: 5, 15 default_threshold: 5,
16 to: :author, 16 to: :author,
  17 + target_profile: lambda {|comment| comment.profile },
17 value: lambda { |comment, author| author.present? ? author.comments.count : 0 } 18 value: lambda { |comment, author| author.present? ? author.comments.count : 0 }
18 } 19 }
19 ], 20 ],
@@ -22,6 +23,7 @@ module Merit @@ -22,6 +23,7 @@ module Merit
22 action: 'comment#create', 23 action: 'comment#create',
23 default_threshold: 5, 24 default_threshold: 5,
24 to: lambda {|comment| comment.source.author}, 25 to: lambda {|comment| comment.source.author},
  26 + target_profile: lambda {|comment| comment.profile },
25 value: lambda { |comment, author| author.present? ? Comment.where(source_id: Article.where(author_id: author.id)).count : 0 } 27 value: lambda { |comment, author| author.present? ? Comment.where(source_id: Article.where(author_id: author.id)).count : 0 }
26 } 28 }
27 ], 29 ],
@@ -30,6 +32,7 @@ module Merit @@ -30,6 +32,7 @@ module Merit
30 action: 'article#create', 32 action: 'article#create',
31 default_threshold: 5, 33 default_threshold: 5,
32 to: :author, 34 to: :author,
  35 + target_profile: lambda {|article| article.profile },
33 value: lambda { |article, author| author.present? ? TextArticle.where(author_id: author.id).count : 0 } 36 value: lambda { |article, author| author.present? ? TextArticle.where(author_id: author.id).count : 0 }
34 }, 37 },
35 ], 38 ],
@@ -38,6 +41,7 @@ module Merit @@ -38,6 +41,7 @@ module Merit
38 action: 'vote#create', 41 action: 'vote#create',
39 default_threshold: 5, 42 default_threshold: 5,
40 to: lambda {|vote| vote.voteable.author}, 43 to: lambda {|vote| vote.voteable.author},
  44 + target_profile: lambda {|vote| vote.voteable.profile },
41 value: lambda { |vote, author| vote.voteable ? Vote.for_voteable(vote.voteable).where('vote > 0').count : 0} 45 value: lambda { |vote, author| vote.voteable ? Vote.for_voteable(vote.voteable).where('vote > 0').count : 0}
42 } 46 }
43 ], 47 ],
@@ -46,6 +50,7 @@ module Merit @@ -46,6 +50,7 @@ module Merit
46 action: 'vote#create', 50 action: 'vote#create',
47 default_threshold: 5, 51 default_threshold: 5,
48 to: lambda {|vote| vote.voteable.author}, 52 to: lambda {|vote| vote.voteable.author},
  53 + target_profile: lambda {|vote| vote.voteable.profile },
49 value: lambda { |vote, author| Vote.for_voteable(vote.voteable).where('vote < 0').count } 54 value: lambda { |vote, author| Vote.for_voteable(vote.voteable).where('vote < 0').count }
50 } 55 }
51 ], 56 ],
@@ -54,6 +59,7 @@ module Merit @@ -54,6 +59,7 @@ module Merit
54 action: 'vote#create', 59 action: 'vote#create',
55 default_threshold: 5, 60 default_threshold: 5,
56 to: lambda {|vote| vote.voter}, 61 to: lambda {|vote| vote.voter},
  62 + target_profile: lambda {|vote| vote.voteable.profile },
57 value: lambda { |vote, voter| voter ? Vote.for_voter(voter).count : 0 } 63 value: lambda { |vote, voter| voter ? Vote.for_voter(voter).count : 0 }
58 } 64 }
59 ], 65 ],
@@ -65,6 +71,7 @@ module Merit @@ -65,6 +71,7 @@ module Merit
65 value: lambda { |friendship, person| person.friends.count } 71 value: lambda { |friendship, person| person.friends.count }
66 } 72 }
67 ], 73 ],
  74 + manual: [],
68 75
69 #FIXME review the name of the badges and see a way to make it generic 76 #FIXME review the name of the badges and see a way to make it generic
70 creative: [ 77 creative: [
@@ -72,12 +79,14 @@ module Merit @@ -72,12 +79,14 @@ module Merit
72 action: 'comment#create', 79 action: 'comment#create',
73 default_threshold: 5, 80 default_threshold: 5,
74 to: :author, 81 to: :author,
  82 + target_profile: lambda {|comment| comment.profile },
75 value: lambda { |comment, author| author.present? ? author.comments.count : 0 } 83 value: lambda { |comment, author| author.present? ? author.comments.count : 0 }
76 }, 84 },
77 { 85 {
78 action: 'article#create', 86 action: 'article#create',
79 default_threshold: 5, 87 default_threshold: 5,
80 to: :author, 88 to: :author,
  89 + target_profile: lambda {|article| article.profile },
81 value: lambda { |article, author| author.present? ? author.articles.count : 0 } 90 value: lambda { |article, author| author.present? ? author.articles.count : 0 }
82 }, 91 },
83 ], 92 ],
@@ -86,6 +95,7 @@ module Merit @@ -86,6 +95,7 @@ module Merit
86 action: 'articlefollower#create', 95 action: 'articlefollower#create',
87 default_threshold: 5, 96 default_threshold: 5,
88 to: lambda {|article| article.person }, 97 to: lambda {|article| article.person },
  98 + target_profile: lambda {|article_follower| article_follower.article.profile },
89 model: 'ArticleFollower', 99 model: 'ArticleFollower',
90 value: lambda { |article, person| person.present? ? person.article_followers.count : 0 } 100 value: lambda { |article, person| person.present? ? person.article_followers.count : 0 }
91 } 101 }
@@ -95,12 +105,14 @@ module Merit @@ -95,12 +105,14 @@ module Merit
95 action: 'Vote#create', 105 action: 'Vote#create',
96 default_threshold: 5, 106 default_threshold: 5,
97 to: lambda { |vote| vote.voter }, 107 to: lambda { |vote| vote.voter },
  108 + target_profile: lambda {|vote| vote.voteable.profile },
98 value: lambda { |vote, voter| Vote.for_voter(voter).count } 109 value: lambda { |vote, voter| Vote.for_voter(voter).count }
99 }, 110 },
100 { 111 {
101 action: 'Event#create', 112 action: 'Event#create',
102 default_threshold: 5, 113 default_threshold: 5,
103 to: lambda { |article| article.author }, 114 to: lambda { |article| article.author },
  115 + target_profile: lambda {|article| article.profile },
104 value: lambda { |event, author| author.events.count } 116 value: lambda { |event, author| author.events.count }
105 }, 117 },
106 ], 118 ],
@@ -109,12 +121,14 @@ module Merit @@ -109,12 +121,14 @@ module Merit
109 action: 'vote#create', 121 action: 'vote#create',
110 default_threshold: 5, 122 default_threshold: 5,
111 to: lambda {|vote| vote.voter}, 123 to: lambda {|vote| vote.voter},
  124 + target_profile: lambda {|vote| vote.voteable.profile },
112 value: lambda { |vote, voter| voter ? voter.votes.where('vote > 0').count : 0 } 125 value: lambda { |vote, voter| voter ? voter.votes.where('vote > 0').count : 0 }
113 }, 126 },
114 { 127 {
115 action: 'comment#create', 128 action: 'comment#create',
116 default_threshold: 5, 129 default_threshold: 5,
117 to: :author, 130 to: :author,
  131 + target_profile: lambda {|comment| comment.profile },
118 value: lambda { |comment, author| author.present? ? author.comments.count : 0 } 132 value: lambda { |comment, author| author.present? ? author.comments.count : 0 }
119 } 133 }
120 ], 134 ],
@@ -123,6 +137,7 @@ module Merit @@ -123,6 +137,7 @@ module Merit
123 action: 'articlefollower#create', 137 action: 'articlefollower#create',
124 default_threshold: 5, 138 default_threshold: 5,
125 to: :person, 139 to: :person,
  140 + target_profile: lambda {|article_follower| article_follower.article.profile },
126 model: 'ArticleFollower', 141 model: 'ArticleFollower',
127 value: lambda { |article_follower, person| person.present? ? person.article_followers.count : 0 } 142 value: lambda { |article_follower, person| person.present? ? person.article_followers.count : 0 }
128 }, 143 },
@@ -130,11 +145,28 @@ module Merit @@ -130,11 +145,28 @@ module Merit
130 action: 'comment#create', 145 action: 'comment#create',
131 default_threshold: 5, 146 default_threshold: 5,
132 to: :author, 147 to: :author,
  148 + target_profile: lambda {|comment| comment.profile },
133 value: lambda { |comment, author| author.present? ? author.comments.count : 0 } 149 value: lambda { |comment, author| author.present? ? author.comments.count : 0 }
134 }, 150 },
135 ] 151 ]
136 } 152 }
137 153
  154 + def target_author(source, setting)
  155 + if setting[:to].is_a? Symbol
  156 + source.send(setting[:to])
  157 + else
  158 + setting[:to].call(source) rescue nil
  159 + end
  160 + end
  161 +
  162 + def target_profile(source, setting)
  163 + setting[:target_profile].present? ? setting[:target_profile].call(source) : nil
  164 + end
  165 +
  166 + def check_organization_badge(badge, source, setting)
  167 + !badge.owner.kind_of?(Organization) || badge.owner == target_profile(source, setting)
  168 + end
  169 +
138 def initialize(environment=nil) 170 def initialize(environment=nil)
139 return if environment.nil? 171 return if environment.nil?
140 @environment = environment 172 @environment = environment
@@ -142,7 +174,7 @@ module Merit @@ -142,7 +174,7 @@ module Merit
142 rules = AVAILABLE_RULES 174 rules = AVAILABLE_RULES
143 rules.merge! CONFERENCE_RULES if defined? CONFERENCE_RULES 175 rules.merge! CONFERENCE_RULES if defined? CONFERENCE_RULES
144 176
145 - environment.gamification_plugin_badges.all.each do |badge| 177 + environment.gamification_plugin_badges.each do |badge|
146 next if rules[badge.name.to_sym].nil? 178 next if rules[badge.name.to_sym].nil?
147 rules[badge.name.to_sym].each do |setting| 179 rules[badge.name.to_sym].each do |setting|
148 options = {badge: badge.name, level: badge.level, to: setting[:to]} 180 options = {badge: badge.name, level: badge.level, to: setting[:to]}
@@ -150,18 +182,11 @@ module Merit @@ -150,18 +182,11 @@ module Merit
150 grant_on setting[:action], options do |source| 182 grant_on setting[:action], options do |source|
151 can_be_granted = true 183 can_be_granted = true
152 rules[badge.name.to_sym].each do |s| 184 rules[badge.name.to_sym].each do |s|
153 - if setting[:to].is_a? Symbol  
154 - to = source.send(setting[:to])  
155 - else  
156 - begin  
157 - to = setting[:to].call(source)  
158 - rescue  
159 - to = nil  
160 - end  
161 - end  
162 - # pass source and to for different situations 185 + to = target_author(source, setting)
  186 + # pass source and to for different situations
163 action = (badge.custom_fields || {}).fetch(s[:action], {}) 187 action = (badge.custom_fields || {}).fetch(s[:action], {})
164 can_be_granted &= s[:value].call(source, to) >= action.fetch(:threshold, s[:default_threshold]).to_i 188 can_be_granted &= s[:value].call(source, to) >= action.fetch(:threshold, s[:default_threshold]).to_i
  189 + can_be_granted &= check_organization_badge(badge, source, setting)
165 end 190 end
166 can_be_granted 191 can_be_granted
167 end 192 end
lib/merit/point_rules.rb
@@ -11,6 +11,7 @@ module Merit @@ -11,6 +11,7 @@ module Merit
11 description: _('Comment author'), 11 description: _('Comment author'),
12 default_weight: 40, 12 default_weight: 40,
13 target_profile: lambda {|comment| comment.source.profile }, 13 target_profile: lambda {|comment| comment.source.profile },
  14 + target_url: lambda {|comment| comment.url},
14 }, 15 },
15 comment_article_author: { 16 comment_article_author: {
16 action: 'comment#create', 17 action: 'comment#create',
@@ -20,6 +21,7 @@ module Merit @@ -20,6 +21,7 @@ module Merit
20 description: _('Article author of a comment'), 21 description: _('Article author of a comment'),
21 default_weight: 50, 22 default_weight: 50,
22 target_profile: lambda {|comment| comment.source.profile }, 23 target_profile: lambda {|comment| comment.source.profile },
  24 + target_url: lambda {|comment| comment.url},
23 }, 25 },
24 comment_article: { 26 comment_article: {
25 action: 'comment#create', 27 action: 'comment#create',
@@ -29,6 +31,7 @@ module Merit @@ -29,6 +31,7 @@ module Merit
29 description: _('Source article of a comment'), 31 description: _('Source article of a comment'),
30 default_weight: 50, 32 default_weight: 50,
31 target_profile: lambda {|comment| comment.source.profile }, 33 target_profile: lambda {|comment| comment.source.profile },
  34 + target_url: lambda {|comment| comment.url},
32 }, 35 },
33 comment_community: { 36 comment_community: {
34 action: 'comment#create', 37 action: 'comment#create',
@@ -38,7 +41,8 @@ module Merit @@ -38,7 +41,8 @@ module Merit
38 description: _('Article community of a comment'), 41 description: _('Article community of a comment'),
39 default_weight: 50, 42 default_weight: 50,
40 target_profile: lambda {|comment| comment.source.profile }, 43 target_profile: lambda {|comment| comment.source.profile },
41 - condition: lambda {|comment, profile| comment.profile.community?} 44 + condition: lambda {|comment, profile| comment.profile.community?},
  45 + target_url: lambda {|comment| comment.url},
42 }, 46 },
43 article_author: { 47 article_author: {
44 action: 'article#create', 48 action: 'article#create',
@@ -48,6 +52,7 @@ module Merit @@ -48,6 +52,7 @@ module Merit
48 description: _('Article author'), 52 description: _('Article author'),
49 default_weight: 50, 53 default_weight: 50,
50 target_profile: lambda {|article| article.profile }, 54 target_profile: lambda {|article| article.profile },
  55 + target_url: lambda {|article| article.url},
51 }, 56 },
52 article_community: { 57 article_community: {
53 action: 'article#create', 58 action: 'article#create',
@@ -57,7 +62,8 @@ module Merit @@ -57,7 +62,8 @@ module Merit
57 description: _('Article community'), 62 description: _('Article community'),
58 default_weight: 10, 63 default_weight: 10,
59 target_profile: lambda {|article| article.profile }, 64 target_profile: lambda {|article| article.profile },
60 - condition: lambda {|article, profile| article.profile.present? and article.profile.community? } 65 + condition: lambda {|article, profile| article.profile.present? and article.profile.community? },
  66 + target_url: lambda {|article| article.url},
61 }, 67 },
62 vote_voteable_author: { 68 vote_voteable_author: {
63 action: 'vote#create', 69 action: 'vote#create',
@@ -67,6 +73,7 @@ module Merit @@ -67,6 +73,7 @@ module Merit
67 description: _('Author of a voted content'), 73 description: _('Author of a voted content'),
68 default_weight: 20, 74 default_weight: 20,
69 target_profile: lambda {|vote| vote.voteable.present? ? vote.voteable.profile : nil }, 75 target_profile: lambda {|vote| vote.voteable.present? ? vote.voteable.profile : nil },
  76 + target_url: lambda {|vote| vote.voteable.url},
70 }, 77 },
71 vote_voteable: { 78 vote_voteable: {
72 action: 'vote#create', 79 action: 'vote#create',
@@ -76,6 +83,7 @@ module Merit @@ -76,6 +83,7 @@ module Merit
76 description: _('Voted content'), 83 description: _('Voted content'),
77 default_weight: 30, 84 default_weight: 30,
78 target_profile: lambda {|vote| vote.voteable.present? ? vote.voteable.profile : nil }, 85 target_profile: lambda {|vote| vote.voteable.present? ? vote.voteable.profile : nil },
  86 + target_url: lambda {|vote| vote.voteable.url},
79 }, 87 },
80 vote_voter: { 88 vote_voter: {
81 action: 'vote#create', 89 action: 'vote#create',
@@ -85,6 +93,7 @@ module Merit @@ -85,6 +93,7 @@ module Merit
85 description: _('Voter'), 93 description: _('Voter'),
86 default_weight: 10, 94 default_weight: 10,
87 target_profile: lambda {|vote| vote.voteable.present? ? vote.voteable.profile : nil }, 95 target_profile: lambda {|vote| vote.voteable.present? ? vote.voteable.profile : nil },
  96 + target_url: lambda {|vote| vote.voteable.url},
88 }, 97 },
89 friends: { 98 friends: {
90 action: 'friendship#create', 99 action: 'friendship#create',
@@ -150,6 +159,7 @@ module Merit @@ -150,6 +159,7 @@ module Merit
150 end 159 end
151 160
152 def profile_condition(setting, target, profile) 161 def profile_condition(setting, target, profile)
  162 + return false if target == true
153 profile.nil? || setting[:target_profile].blank? || setting[:target_profile].call(target) == profile 163 profile.nil? || setting[:target_profile].blank? || setting[:target_profile].call(target) == profile
154 end 164 end
155 165
@@ -163,6 +173,15 @@ module Merit @@ -163,6 +173,15 @@ module Merit
163 end 173 end
164 end 174 end
165 175
  176 + def self.target_url(point)
  177 + rule_name = point.point_type.present? ? point.point_type.name : point.score.category
  178 + target_url = AVAILABLE_RULES[rule_name.to_sym][:target_url]
  179 + return nil if target_url.blank? || point.action.blank?
  180 +
  181 + model = BaseTargetFinder.new(Merit::Rule.new, point.action).get_target_from_database
  182 + model.present? ? target_url.call(model) : nil
  183 + end
  184 +
166 def initialize(environment=nil) 185 def initialize(environment=nil)
167 return if environment.nil? 186 return if environment.nil?
168 @environment = environment 187 @environment = environment
lib/merit_ext.rb
@@ -17,6 +17,15 @@ module Merit @@ -17,6 +17,15 @@ module Merit
17 class Score 17 class Score
18 class Point 18 class Point
19 belongs_to :action 19 belongs_to :action
  20 +
  21 + def point_type
  22 + @point_type ||= GamificationPlugin::PointsType.where(id: score.category).first
  23 + end
  24 +
  25 + def undo_rule?
  26 + rule = Merit::PointRules::AVAILABLE_RULES[point_type.name.to_sym]
  27 + rule[:undo_action] == "#{action.target_model}##{action.action_method}"
  28 + end
20 end 29 end
21 end 30 end
22 31
@@ -34,7 +43,7 @@ module Merit @@ -34,7 +43,7 @@ module Merit
34 module ClassMethods 43 module ClassMethods
35 44
36 def has_merit_actions(options = {}) 45 def has_merit_actions(options = {})
37 - after_create { |obj| obj.new_merit_action(:create, options) } 46 + after_create { |obj| obj.delay.new_merit_action(:create, options) }
38 before_destroy { |obj| obj.new_merit_action(:destroy, options) } 47 before_destroy { |obj| obj.new_merit_action(:destroy, options) }
39 end 48 end
40 49
models/gamification_plugin/points_categorization.rb
1 -class GamificationPlugin::PointsCategorization < Noosfero::Plugin::ActiveRecord 1 +class GamificationPlugin::PointsCategorization < ActiveRecord::Base
2 belongs_to :profile 2 belongs_to :profile
3 belongs_to :point_type, class_name: 'GamificationPlugin::PointsType', foreign_key: :point_type_id 3 belongs_to :point_type, class_name: 'GamificationPlugin::PointsType', foreign_key: :point_type_id
4 attr_accessible :profile_id, :profile, :point_type_id, :weight 4 attr_accessible :profile_id, :profile, :point_type_id, :weight
@@ -10,5 +10,5 @@ class GamificationPlugin::PointsCategorization &lt; Noosfero::Plugin::ActiveRecord @@ -10,5 +10,5 @@ class GamificationPlugin::PointsCategorization &lt; Noosfero::Plugin::ActiveRecord
10 scope :for_type, lambda { |p_type| joins(:point_type).where(gamification_plugin_points_types: {name: p_type}) } 10 scope :for_type, lambda { |p_type| joins(:point_type).where(gamification_plugin_points_types: {name: p_type}) }
11 scope :for_profile, lambda { |p_profile| joins(:profile).where(profiles: {identifier: p_profile}) } 11 scope :for_profile, lambda { |p_profile| joins(:profile).where(profiles: {identifier: p_profile}) }
12 12
13 - scope :grouped_profiles, select(:profile_id).group(:profile_id).includes(:profile) 13 + scope :grouped_profiles, -> { select(:profile_id).group(:profile_id).includes(:profile) }
14 end 14 end
models/gamification_plugin/points_type.rb
1 -class GamificationPlugin::PointsType < Noosfero::Plugin::ActiveRecord 1 +class GamificationPlugin::PointsType < ActiveRecord::Base
2 attr_accessible :description, :name 2 attr_accessible :description, :name
3 3
4 validates :name, presence: true, uniqueness: true 4 validates :name, presence: true, uniqueness: true
public/admin.css
1 .gamification-plugin-rank-rules .template-level { 1 .gamification-plugin-rank-rules .template-level {
2 display: none !important; 2 display: none !important;
3 } 3 }
  4 +
  5 +.gamification-plugin-badges .badge-owner-group {
  6 + text-align: right;
  7 + color: gray;
  8 + font-weight: bold;
  9 +}
public/admin.js
@@ -13,6 +13,11 @@ var gamificationPluginAdmin = { @@ -13,6 +13,11 @@ var gamificationPluginAdmin = {
13 var name = jQuery('#gamification-plugin-form-badge-name').find('option:selected').text(); 13 var name = jQuery('#gamification-plugin-form-badge-name').find('option:selected').text();
14 jQuery('.name_'+name).show(); 14 jQuery('.name_'+name).show();
15 jQuery('.name_'+name).find('input').removeAttr('disabled'); 15 jQuery('.name_'+name).find('input').removeAttr('disabled');
  16 + if(jQuery('.name_'+name).children().length>0) {
  17 + jQuery('.action-fields').show();
  18 + } else {
  19 + jQuery('.action-fields').hide();
  20 + }
16 } 21 }
17 22
18 } 23 }
public/style.css
@@ -237,3 +237,7 @@ @@ -237,3 +237,7 @@
237 float: left; 237 float: left;
238 width: 180px; 238 width: 180px;
239 } 239 }
  240 +
  241 +.gamification-dashboard .points .score.undo_action .category {
  242 + text-decoration: line-through;
  243 +}
script/check_merit_actions_vs_points.rb 0 → 100644
@@ -0,0 +1,197 @@ @@ -0,0 +1,197 @@
  1 +#!/usr/bin/env ruby
  2 +# encoding: UTF-8
  3 +
  4 +#
  5 +# This script was created for ensuring all the actions observed
  6 +# by merit for pontuation was judged and pontuated accordingly
  7 +# It checks the merit_actions registers for each action(model
  8 +# create or destroy) and recreates it
  9 +#
  10 +
  11 +require 'csv'
  12 +
  13 +ActiveRecord::Base.logger.level = Logger::Severity::UNKNOWN
  14 +
  15 +class ProcessObserver
  16 + def update(changed_data)
  17 + merit = changed_data[:merit_object]
  18 + if merit.kind_of?(Merit::Score::Point)
  19 + action = Merit::Action.find(changed_data[:merit_action_id])
  20 + new_date = YAML.load(action.target_data).created_at
  21 + action.update_attribute(:created_at, new_date)
  22 + merit.update_attribute(:created_at, new_date)
  23 + end
  24 + end
  25 +end
  26 +
  27 +def create_action(obj, index, count)
  28 + target_model = obj.class.base_class.name.downcase
  29 + action = Merit::Action.find_by_target_id_and_target_model_and_action_method(obj.id, target_model, 'create')
  30 + if action.nil?
  31 + puts "#{index}/#{count} Create merit action for #{target_model} #{obj.id}"
  32 + begin
  33 + obj.new_merit_action(:create)
  34 + rescue Exception => e
  35 + puts "Could not be create: #{e.message}"
  36 + end
  37 + end
  38 +end
  39 +
  40 +def recreate_actions person, objects, category
  41 + puts "Recreating actions for #{person.identifier} on model #{objects.name}"
  42 + actions = Merit::Action.where(target_id: objects, target_model: objects.name.downcase, action_method: 'create')
  43 + Merit::Score::Point.where(action_id: actions).destroy_all
  44 + actions.destroy_all
  45 + # erase remaining points if any (can be wrong on destroy cases ?)
  46 + person.score_points.where(score_id: Merit::Score.where(category: category)).destroy_all
  47 + count = objects.count
  48 + objects.each_with_index{ |obj, index| create_action(obj, index, count) }
  49 +end
  50 +
  51 +def calc_points categorization, objects
  52 + rule = Merit::PointRules::AVAILABLE_RULES[categorization.point_type.name.to_sym]
  53 + return 0 if rule.nil?
  54 +
  55 + sum = objects.map{|o| rule[:value].respond_to?(:call) ? rule[:value].call(o) : rule[:value] }.sum
  56 + return sum * categorization.weight
  57 +end
  58 +
  59 +# avoid updating level on every action for increasing performance
  60 +Merit.observers.delete('RankObserver')
  61 +
  62 +Merit.observers << 'ProcessObserver'
  63 +
  64 +class Article < ActiveRecord::Base
  65 + def self.text_article_types
  66 + ['ProposalsDiscussionPlugin::Proposal']
  67 + end
  68 +end
  69 +
  70 +puts "Cleaning up points from actions which don't exist"
  71 +Merit::Score::Point.includes(:action).find_each(batch_size: 100) do |point|
  72 + point.destroy if point.action.nil?
  73 +end
  74 +
  75 +# erase the badges spreadsheet
  76 +CSV.open( "gamification_wrong_badges.csv", 'w' ) do |csv|
  77 + csv << ['identifier', 'missing badges', 'exceeding badges']
  78 +end
  79 +# erase the points spreadsheet
  80 +CSV.open( "gamification_points_out_expectation.csv", 'w' ) do |csv|
  81 + csv << ['identifier', 'name', 'action', 'profile', 'category id', 'category type', 'should have', 'have']
  82 +end
  83 +
  84 +Environment.all.each do |environment|
  85 + puts "Process environment #{environment.name}"
  86 +
  87 + Merit::AppPointRules.clear
  88 + Merit::AppBadgeRules.clear
  89 + Merit::AppPointRules.merge!(Merit::PointRules.new(environment).defined_rules)
  90 + Merit::AppBadgeRules.merge!(Merit::BadgeRules.new(environment).defined_rules)
  91 +
  92 + group_control = YAML.load(File.read(File.join(Rails.root,'tmp','control_group.yml'))) if File.exist?(File.join(Rails.root,'tmp','control_group.yml'))
  93 + conditions = group_control.nil? ? {} : {:identifier => group_control.map{|k,v| v['profiles']}.flatten}
  94 +
  95 + clean_profiles_file = File.join(Rails.root,'tmp','gamification_clean_profiles.yml')
  96 + clean_profiles = YAML.load(File.read(clean_profiles_file)) if File.exist?(File.join(clean_profiles_file))
  97 + clean_profiles = [0] if clean_profiles.nil?
  98 +
  99 + people_count = environment.people.where(conditions).where("id not in (?)",clean_profiles).count
  100 + person_index = 0
  101 + puts "Analising environment people"
  102 + environment.people.where("id not in (?)",clean_profiles).find_each(:conditions => conditions) do |person|
  103 + person_index += 1
  104 + profile_ids = GamificationPlugin::PointsCategorization.uniq.pluck(:profile_id)
  105 + profile_ids.keep_if { |item| group_control.keys.include?(item) } unless group_control.nil?
  106 + profile_ids.delete nil # avoid loosing time with generic for now
  107 + profile_ids.each do |profile_id|
  108 + profile = Profile.where(id: profile_id).first
  109 + if profile.nil?
  110 + profile_name = 'generic'
  111 + # person actions
  112 + person_articles = Article.where(author_id: person.id)
  113 + comments = Comment.where(author_id: person.id)
  114 + votes = Vote.for_voter(person)
  115 + follows = ArticleFollower.where(person_id: person.id)
  116 + else
  117 + profile_name = profile.identifier
  118 + #person actions
  119 + person_articles = Article.where(author_id: person.id, profile_id: profile)
  120 + comments = Comment.where(author_id: person.id, source_id: profile.articles)
  121 + general_votes = Vote.for_voter(person)
  122 + votes = general_votes.where("(voteable_type = 'Article' and voteable_id in (?)) or (voteable_type = 'Comment' and voteable_id in (?))",profile.articles, Comment.where(source_type: "Article", source_id: profile.articles))
  123 + follows = ArticleFollower.where(person_id: person.id, article_id: profile.articles)
  124 + end
  125 + # received actions
  126 + comments_received = Comment.where(:source_id => person_articles)
  127 + votes_received = Vote.where("(voteable_type = 'Article' and voteable_id in (?)) or (voteable_type = 'Comment' and voteable_id in (?))",person_articles, person.comments)
  128 + follows_received = ArticleFollower.where(:article_id => person_articles)
  129 +
  130 + puts "#{person_index}/#{people_count} - Analising points for #{person.identifier} on #{profile_name}"
  131 + #puts "Proposed #{person_articles.count} times, Commented #{comments.count} times, Voted #{votes.count} times, Followed #{follows.count} times"
  132 + #puts "Received #{votes_received.count} votes, #{comments_received.count} comments, #{follows_received.count} follows\n"
  133 +
  134 + scope_by_badge_action = {
  135 + "articlefollower#create" => follows, "comment#create" => comments, "article#create" => person_articles, "vote#create" => votes
  136 + }
  137 +
  138 + # ignoring user badges out of environment badges
  139 + should_and_doesnt_have = []
  140 + should_not_have = []
  141 + should_have = true
  142 + environment.gamification_plugin_badges.each do |badge|
  143 + (badge.custom_fields || {}).each do |action, config|
  144 + break if scope_by_badge_action[action].nil? or config[:threshold].nil?
  145 + should_have &= scope_by_badge_action[action].count >= config[:threshold].to_i
  146 + end
  147 + have = person.badges.include? badge
  148 + if should_have && !have
  149 + should_and_doesnt_have << "#{badge.title} #{badge.level}"
  150 + elsif should_have && !have
  151 + should_not_have << "#{badge.title} #{badge.level}"
  152 + end
  153 + end
  154 + if should_and_doesnt_have.size > 0 || should_not_have.size > 0
  155 + CSV.open( "gamification_wrong_badges.csv", 'a' ) do |csv|
  156 + [person.identifier, should_and_doesnt_have.join(' | '), should_not_have.join(' | ')]
  157 + end
  158 + end
  159 +
  160 + scope_by_type = {
  161 + article_author: person_articles, comment_author: comments, vote_voter: votes, follower: follows,
  162 + comment_article_author: comments_received, vote_voteable_author: votes_received, followed_article_author: follows_received
  163 + }
  164 +
  165 + puts "Points:"
  166 + is_profile_clean = true
  167 + scope_by_type.each do |type, scope|
  168 + c = GamificationPlugin::PointsCategorization.for_type(type).where(profile_id: profile_id).joins(:point_type).first
  169 + points = calc_points c, scope
  170 + puts "On #{c.point_type.name} it should have #{points} and have #{person.points(category: c.id.to_s)} "
  171 + if points != person.points(category: c.id.to_s)
  172 + recreate_actions person, scope, c.id.to_s
  173 + points = calc_points c, scope
  174 + if points != person.reload.points(category: c.id.to_s)
  175 + puts "after recreating points the person has: #{person.reload.points(category: c.id.to_s)} and should have #{points}"
  176 + # write to the spreadsheet the person points that couldn't regulate
  177 + CSV.open( "gamification_points_out_expectation.csv", 'a' ) do |csv|
  178 + [person.identifier, person.name, scope.first.class.base_class.name, profile_name, c.id, c.point_type.name, scope.count*c.weight, person.points(category: c.id.to_s)]
  179 + end
  180 + is_profile_clean = false
  181 + else
  182 + puts "points fixed for #{c.point_type.name}!"
  183 + end
  184 + end
  185 + end
  186 + File.open(clean_profiles_file, 'w') {|f| f.write(clean_profiles.push(person.id).to_yaml)} if is_profile_clean
  187 + puts
  188 + end
  189 + end
  190 +
  191 + # update everyone's level after the whole pontuation,
  192 + # which is much faster than on every created action
  193 + environment.people.find_each(batch_size: 100) do |person|
  194 + puts "Updating #{person.identifier} level\n"
  195 + person.update_attribute(:level, person.gamification_plugin_calculate_level)
  196 + end
  197 +end
script/export_ranking.rb
@@ -37,15 +37,18 @@ profile_ids.each do |profile_id| @@ -37,15 +37,18 @@ profile_ids.each do |profile_id|
37 person_down_votes = person.comments.joins(:votes).where('vote < 0').count + person_articles.joins(:votes).where('vote < 0').count 37 person_down_votes = person.comments.joins(:votes).where('vote < 0').count + person_articles.joins(:votes).where('vote < 0').count
38 person_comments = person.comments.count 38 person_comments = person.comments.count
39 person_followers = (person.following_articles & person.article_followers.where(article_id: person_articles)).count 39 person_followers = (person.following_articles & person.article_followers.where(article_id: person_articles)).count
  40 + votes = Vote.for_voter(person).count
40 else 41 else
41 person_articles = profile.articles.where(:author_id => person.id) 42 person_articles = profile.articles.where(:author_id => person.id)
42 person_up_votes = person.comments.where(:source_id => profile.articles).joins(:votes).where('vote > 0').count + person_articles.joins(:votes).where('vote > 0').count 43 person_up_votes = person.comments.where(:source_id => profile.articles).joins(:votes).where('vote > 0').count + person_articles.joins(:votes).where('vote > 0').count
43 person_down_votes = person.comments.where(:source_id => profile.articles).joins(:votes).where('vote < 0').count + person_articles.joins(:votes).where('vote < 0').count 44 person_down_votes = person.comments.where(:source_id => profile.articles).joins(:votes).where('vote < 0').count + person_articles.joins(:votes).where('vote < 0').count
44 person_comments = person.comments.where(:source_id => profile.articles).count 45 person_comments = person.comments.where(:source_id => profile.articles).count
45 person_followers = (person.following_articles & person.article_followers.where(article_id: profile.articles)).count 46 person_followers = (person.following_articles & person.article_followers.where(article_id: profile.articles)).count
  47 + the_votes = Vote.for_voter(person)
  48 + votes = the_votes.where(voteable_type: 'Article', voteable_id: profile.articles).count + the_votes.where(voteable_type: 'Comment', voteable_id: Comment.where(source_type: ["ProposalsDiscussionPlugin::Proposal", "Article"], source_id: profile.articles)).count
46 end 49 end
47 quantities_values = [ 50 quantities_values = [
48 - Vote.for_voter(person).count, 51 + votes,
49 person.friends.count, 52 person.friends.count,
50 person_up_votes, 53 person_up_votes,
51 person_down_votes, 54 person_down_votes,
script/process_merit_rules.rb
@@ -35,13 +35,16 @@ end @@ -35,13 +35,16 @@ end
35 # person.sash.destroy unless person.sash.nil? 35 # person.sash.destroy unless person.sash.nil?
36 #end 36 #end
37 37
  38 +# avoid updating level on every action for increasing performance
  39 +Merit.observers.delete('RankObserver')
  40 +
38 Merit.observers << 'ProcessObserver' 41 Merit.observers << 'ProcessObserver'
39 42
40 class Article < ActiveRecord::Base 43 class Article < ActiveRecord::Base
41 def self.text_article_types 44 def self.text_article_types
42 # ['TextArticle', 'TextileArticle', 'TinyMceArticle', 'ProposalsDiscussionPlugin::Proposal'] 45 # ['TextArticle', 'TextileArticle', 'TinyMceArticle', 'ProposalsDiscussionPlugin::Proposal']
43 ['ProposalsDiscussionPlugin::Proposal'] 46 ['ProposalsDiscussionPlugin::Proposal']
44 - end 47 + end
45 end 48 end
46 49
47 Environment.all.each do |environment| 50 Environment.all.each do |environment|
@@ -56,7 +59,7 @@ Environment.all.each do |environment| @@ -56,7 +59,7 @@ Environment.all.each do |environment|
56 article_index = 0 59 article_index = 0
57 60
58 puts "Amount of articles '#{article_count}'" 61 puts "Amount of articles '#{article_count}'"
59 - environment.articles.where(:type => Article.text_article_types).find_each do |article| 62 + environment.articles.includes(:comments).where(:type => Article.text_article_types).find_each(batch_size: 100) do |article|
60 article_index += 1 63 article_index += 1
61 puts "Analising article #{article_index} of #{article_count}" 64 puts "Analising article #{article_index} of #{article_count}"
62 create_action(article, article_index, article_count) 65 create_action(article, article_index, article_count)
test/functional/gamification_plugin_badges_controller_test.rb
@@ -25,6 +25,14 @@ class GamificationPluginBadgesControllerTest &lt; ActionController::TestCase @@ -25,6 +25,14 @@ class GamificationPluginBadgesControllerTest &lt; ActionController::TestCase
25 end 25 end
26 end 26 end
27 27
  28 + should "should create gamification_plugin_badge with organization as owner" do
  29 + organization = fast_create(Organization)
  30 + assert_difference('GamificationPlugin::Badge.count') do
  31 + post :create, gamification_plugin_badge: { description: @gamification_plugin_badge.description, level: @gamification_plugin_badge.level, name: @gamification_plugin_badge.name, custom_fields: {threshold: @gamification_plugin_badge.threshold}, owner_id: organization.id }
  32 + assert_equal organization, GamificationPlugin::Badge.last.owner
  33 + end
  34 + end
  35 +
28 should "should show gamification_plugin_badge" do 36 should "should show gamification_plugin_badge" do
29 get :show, id: @gamification_plugin_badge 37 get :show, id: @gamification_plugin_badge
30 assert_response :success 38 assert_response :success
@@ -40,6 +48,23 @@ class GamificationPluginBadgesControllerTest &lt; ActionController::TestCase @@ -40,6 +48,23 @@ class GamificationPluginBadgesControllerTest &lt; ActionController::TestCase
40 assert assigns(:gamification_plugin_badge) 48 assert assigns(:gamification_plugin_badge)
41 end 49 end
42 50
  51 + should "should change badge owner" do
  52 + organization = fast_create(Organization)
  53 + put :update, id: @gamification_plugin_badge, gamification_plugin_badge: { description: @gamification_plugin_badge.description, level: @gamification_plugin_badge.level, name: @gamification_plugin_badge.name, custom_fields: {threshold: @gamification_plugin_badge.threshold}, owner_id: organization.id }
  54 + assert assigns(:gamification_plugin_badge)
  55 + assert_equal organization, @gamification_plugin_badge.reload.owner
  56 + end
  57 +
  58 + should "should keep badge owner when update" do
  59 + organization = fast_create(Organization)
  60 + @gamification_plugin_badge.owner = organization
  61 + @gamification_plugin_badge.save!
  62 +
  63 + put :update, id: @gamification_plugin_badge, gamification_plugin_badge: { description: @gamification_plugin_badge.description, level: @gamification_plugin_badge.level, name: @gamification_plugin_badge.name, custom_fields: {threshold: @gamification_plugin_badge.threshold}, owner_id: organization.id }
  64 + assert assigns(:gamification_plugin_badge)
  65 + assert_equal organization, @gamification_plugin_badge.reload.owner
  66 + end
  67 +
43 should "should destroy gamification_plugin_badge" do 68 should "should destroy gamification_plugin_badge" do
44 assert_difference('GamificationPlugin::Badge.count', -1) do 69 assert_difference('GamificationPlugin::Badge.count', -1) do
45 delete :destroy, id: @gamification_plugin_badge 70 delete :destroy, id: @gamification_plugin_badge
test/functional/gamification_plugin_profile_controller_test.rb
@@ -11,12 +11,13 @@ class GamificationPluginProfileControllerTest &lt; ActionController::TestCase @@ -11,12 +11,13 @@ class GamificationPluginProfileControllerTest &lt; ActionController::TestCase
11 attr_accessor :person, :environment 11 attr_accessor :person, :environment
12 12
13 should 'display points in gamification dashboard' do 13 should 'display points in gamification dashboard' do
14 - person.add_points(20, :category => :comment_author)  
15 - person.add_points(30, :category => :article_author) 14 + create_all_point_rules
  15 + article = create(TextArticle, :profile_id => fast_create(Community).id, :author => person)
  16 + create(Comment, :source => article, :author_id => create_user.person.id)
16 get :dashboard, :profile => person.identifier 17 get :dashboard, :profile => person.identifier
17 - assert_tag :div, :attributes => {:class => 'score article_author positive'}, :child => {:tag => 'span', :attributes => {:class => 'value'}, :content => '30'}  
18 - assert_tag :div, :attributes => {:class => 'score comment_author positive'}, :child => {:tag => 'span', :attributes => {:class => 'value'}, :content => '20'}  
19 - assert_tag :div, :attributes => {:class => 'score total'}, :child => {:tag => 'span', :attributes => {:class => 'value'}, :content => '50'} 18 + assert_tag :div, :attributes => {:class => 'score article_author positive do_action'}, :child => {:tag => 'span', :attributes => {:class => 'value'}, :content => default_point_weight(:article_author).to_s}
  19 + assert_tag :div, :attributes => {:class => 'score comment_article_author positive do_action'}, :child => {:tag => 'span', :attributes => {:class => 'value'}, :content => default_point_weight(:comment_article_author).to_s}
  20 + assert_tag :div, :attributes => {:class => 'score total'}, :child => {:tag => 'span', :attributes => {:class => 'value'}, :content => (default_point_weight(:comment_article_author) + default_point_weight(:article_author)).to_s}
20 end 21 end
21 22
22 should 'display level in gamification dashboard' do 23 should 'display level in gamification dashboard' do
@@ -33,7 +34,7 @@ class GamificationPluginProfileControllerTest &lt; ActionController::TestCase @@ -33,7 +34,7 @@ class GamificationPluginProfileControllerTest &lt; ActionController::TestCase
33 person.add_badge(badge1.id) 34 person.add_badge(badge1.id)
34 person.add_badge(badge2.id) 35 person.add_badge(badge2.id)
35 get :dashboard, :profile => person.identifier 36 get :dashboard, :profile => person.identifier
36 - assert_select '.badges .badge-list .badge', 1 37 + assert_select '.badges .badge-list li.badge', 1
37 end 38 end
38 39
39 end 40 end
test/test_helper.rb
@@ -15,6 +15,10 @@ def create_all_point_rules @@ -15,6 +15,10 @@ def create_all_point_rules
15 end 15 end
16 end 16 end
17 17
  18 +def default_point_weight(rule_name)
  19 + Merit::PointRules::AVAILABLE_RULES[rule_name][:default_weight]
  20 +end
  21 +
18 def load_point_rule(rule_name, config) 22 def load_point_rule(rule_name, config)
19 rule_config = Merit::PointRules::AVAILABLE_RULES[rule_name.to_sym] 23 rule_config = Merit::PointRules::AVAILABLE_RULES[rule_name.to_sym]
20 raise "Point rule '#{rule_name}' is not available" if rule_config.nil? 24 raise "Point rule '#{rule_name}' is not available" if rule_config.nil?
@@ -22,7 +26,7 @@ def load_point_rule(rule_name, config) @@ -22,7 +26,7 @@ def load_point_rule(rule_name, config)
22 rule_config 26 rule_config
23 end 27 end
24 28
25 -#person_points_debug(person) 29 +#person_points_debug(person)
26 def person_points_debug(person) 30 def person_points_debug(person)
27 person.score_points.map do |sp| 31 person.score_points.map do |sp|
28 puts 'Ponto:' 32 puts 'Ponto:'
test/unit/api_test.rb
@@ -8,6 +8,7 @@ class APITest &lt; ActiveSupport::TestCase @@ -8,6 +8,7 @@ class APITest &lt; ActiveSupport::TestCase
8 environment = Environment.default 8 environment = Environment.default
9 environment.enable_plugin(GamificationPlugin) 9 environment.enable_plugin(GamificationPlugin)
10 GamificationPlugin.gamification_set_rules(@environment) 10 GamificationPlugin.gamification_set_rules(@environment)
  11 + create_all_point_rules
11 end 12 end
12 13
13 should 'get my own badges' do 14 should 'get my own badges' do
@@ -27,14 +28,6 @@ class APITest &lt; ActiveSupport::TestCase @@ -27,14 +28,6 @@ class APITest &lt; ActiveSupport::TestCase
27 assert_not_nil json['percent'] 28 assert_not_nil json['percent']
28 end 29 end
29 30
30 - should 'get my total pontuation' do  
31 - badge = GamificationPlugin::Badge.create!(:owner => environment, :name => 'test_badge')  
32 - person.add_badge(badge.id)  
33 - get "/api/v1/gamification_plugin/my/points?#{params.to_query}"  
34 - json = JSON.parse(last_response.body)  
35 - assert_not_nil json['points']  
36 - end  
37 -  
38 should 'get badges of the public person' do 31 should 'get badges of the public person' do
39 badge = GamificationPlugin::Badge.create!(:owner => environment, :name => 'test_badge') 32 badge = GamificationPlugin::Badge.create!(:owner => environment, :name => 'test_badge')
40 another_person = create(User, :environment => environment).person 33 another_person = create(User, :environment => environment).person
@@ -63,7 +56,7 @@ class APITest &lt; ActiveSupport::TestCase @@ -63,7 +56,7 @@ class APITest &lt; ActiveSupport::TestCase
63 another_person.save 56 another_person.save
64 another_person.add_badge(badge.id) 57 another_person.add_badge(badge.id)
65 get "/api/v1/gamification_plugin/people/#{another_person.id}/badges?#{params.to_query}" 58 get "/api/v1/gamification_plugin/people/#{another_person.id}/badges?#{params.to_query}"
66 - json = JSON.parse(last_response.body) 59 + JSON.parse(last_response.body)
67 assert_equal 404, last_response.status 60 assert_equal 404, last_response.status
68 end 61 end
69 62
@@ -76,4 +69,115 @@ class APITest &lt; ActiveSupport::TestCase @@ -76,4 +69,115 @@ class APITest &lt; ActiveSupport::TestCase
76 assert_equal 404, last_response.status 69 assert_equal 404, last_response.status
77 end 70 end
78 71
  72 + should 'get amount of environment badges grouped by name' do
  73 + 3.times { GamificationPlugin::Badge.create!(:owner => environment, :name => 'test_badge') }
  74 + get "/api/v1/gamification_plugin/badges"
  75 + json = JSON.parse(last_response.body)
  76 + assert_equal 3, json['test_badge']
  77 + end
  78 +
  79 + should 'get my points' do
  80 + article = create(TextArticle, :profile_id => @person.id, :author => @person)
  81 + create(Comment, :source_id => article.id, :author => fast_create(Person))
  82 +
  83 + process_delayed_job_queue
  84 +
  85 + get "/api/v1/gamification_plugin/my/points?#{params.to_query}"
  86 + json = JSON.parse(last_response.body)
  87 + assert_equal default_point_weight(:article_author) + default_point_weight(:comment_article_author), json['points']
  88 + end
  89 +
  90 + should 'get my points filtered by type' do
  91 + article = create(TextArticle, :profile_id => @person.id, :author => @person)
  92 + create(Comment, :source_id => article.id, :author => fast_create(Person))
  93 +
  94 + process_delayed_job_queue
  95 +
  96 + params[:type] = 'article_author'
  97 +
  98 + get "/api/v1/gamification_plugin/my/points_by_type?#{params.to_query}"
  99 + json = JSON.parse(last_response.body)
  100 + assert_equal default_point_weight(:article_author), json['points']
  101 + end
  102 +
  103 + should 'get my points filtered by profile' do
  104 + community = fast_create(Community)
  105 + create_point_rule_definition('article_author', community)
  106 + create(TextArticle, :profile_id => @person.id, :author => @person)
  107 + create(TextArticle, :profile_id => community.id, :author => @person)
  108 +
  109 + process_delayed_job_queue
  110 +
  111 + params[:profile] = community.identifier
  112 +
  113 + get "/api/v1/gamification_plugin/my/points_by_profile?#{params.to_query}"
  114 + json = JSON.parse(last_response.body)
  115 + assert_equal default_point_weight(:article_author), json['points']
  116 + end
  117 +
  118 + should 'get my points excluding points earned in profiles' do
  119 + community = fast_create(Community)
  120 + create_point_rule_definition('article_author', community)
  121 + create(TextArticle, :profile_id => @person.id, :author => @person)
  122 + create(TextArticle, :profile_id => community.id, :author => @person)
  123 +
  124 + process_delayed_job_queue
  125 +
  126 + get "/api/v1/gamification_plugin/my/points_out_of_profiles?#{params.to_query}"
  127 + json = JSON.parse(last_response.body)
  128 + assert_equal 2*default_point_weight(:article_author), json['points']
  129 + end
  130 +
  131 + should 'get points of a person' do
  132 + article = create(TextArticle, :profile_id => @person.id, :author => @person)
  133 + create(Comment, :source_id => article.id, :author => fast_create(Person))
  134 +
  135 + process_delayed_job_queue
  136 +
  137 + get "/api/v1/gamification_plugin/people/#{person.id}/points?#{params.to_query}"
  138 + json = JSON.parse(last_response.body)
  139 + assert_equal default_point_weight(:article_author) + default_point_weight(:comment_article_author), json['points']
  140 + end
  141 +
  142 + should 'get points of a person filtered by type' do
  143 + article = create(TextArticle, :profile_id => @person.id, :author => @person)
  144 + create(Comment, :source_id => article.id, :author => fast_create(Person))
  145 +
  146 + process_delayed_job_queue
  147 +
  148 + params[:type] = 'article_author'
  149 +
  150 + get "/api/v1/gamification_plugin/people/#{@person.id}/points_by_type?#{params.to_query}"
  151 + json = JSON.parse(last_response.body)
  152 + assert_equal default_point_weight(:article_author), json['points']
  153 + end
  154 +
  155 + should 'get points of a person filtered by profile' do
  156 + community = fast_create(Community)
  157 + create_point_rule_definition('article_author', community)
  158 + create(TextArticle, :profile_id => @person.id, :author => @person)
  159 + create(TextArticle, :profile_id => community.id, :author => @person)
  160 +
  161 + process_delayed_job_queue
  162 +
  163 + params[:profile] = community.identifier
  164 +
  165 + get "/api/v1/gamification_plugin/people/#{@person.id}/points_by_profile?#{params.to_query}"
  166 + json = JSON.parse(last_response.body)
  167 + assert_equal default_point_weight(:article_author), json['points']
  168 + end
  169 +
  170 + should 'get points of a person excluding points earned in profiles' do
  171 + community = fast_create(Community)
  172 + create_point_rule_definition('article_author', community)
  173 + create(TextArticle, :profile_id => @person.id, :author => @person)
  174 + create(TextArticle, :profile_id => community.id, :author => @person)
  175 +
  176 + process_delayed_job_queue
  177 +
  178 + get "/api/v1/gamification_plugin/people/#{@person.id}/points_out_of_profiles?#{params.to_query}"
  179 + json = JSON.parse(last_response.body)
  180 + assert_equal 2*default_point_weight(:article_author), json['points']
  181 + end
  182 +
79 end 183 end
test/unit/article_follower_test.rb
@@ -14,9 +14,12 @@ class ArticleFollowerTest &lt; ActiveSupport::TestCase @@ -14,9 +14,12 @@ class ArticleFollowerTest &lt; ActiveSupport::TestCase
14 create_point_rule_definition('followed_article') 14 create_point_rule_definition('followed_article')
15 article = create(TextArticle, :name => 'Test', :profile => community, :author => person) 15 article = create(TextArticle, :name => 'Test', :profile => community, :author => person)
16 16
  17 + process_delayed_job_queue
  18 +
17 c = GamificationPlugin::PointsCategorization.for_type(:followed_article).first 19 c = GamificationPlugin::PointsCategorization.for_type(:followed_article).first
18 assert_difference 'article.points(:category => c.id.to_s)', c.weight do 20 assert_difference 'article.points(:category => c.id.to_s)', c.weight do
19 article.person_followers << person 21 article.person_followers << person
  22 + process_delayed_job_queue
20 end 23 end
21 end 24 end
22 25
@@ -25,9 +28,12 @@ class ArticleFollowerTest &lt; ActiveSupport::TestCase @@ -25,9 +28,12 @@ class ArticleFollowerTest &lt; ActiveSupport::TestCase
25 28
26 article = create(TextArticle, :name => 'Test', :profile => community, :author => person) 29 article = create(TextArticle, :name => 'Test', :profile => community, :author => person)
27 30
  31 + process_delayed_job_queue
  32 +
28 c = GamificationPlugin::PointsCategorization.for_type(:follower).first 33 c = GamificationPlugin::PointsCategorization.for_type(:follower).first
29 assert_difference 'person.points(:category => c.id.to_s)', c.weight do 34 assert_difference 'person.points(:category => c.id.to_s)', c.weight do
30 article.person_followers << person 35 article.person_followers << person
  36 + process_delayed_job_queue
31 end 37 end
32 end 38 end
33 39
@@ -36,9 +42,12 @@ class ArticleFollowerTest &lt; ActiveSupport::TestCase @@ -36,9 +42,12 @@ class ArticleFollowerTest &lt; ActiveSupport::TestCase
36 42
37 article = create(TextArticle, :name => 'Test', :profile => community, :author => person) 43 article = create(TextArticle, :name => 'Test', :profile => community, :author => person)
38 44
  45 + process_delayed_job_queue
  46 +
39 c = GamificationPlugin::PointsCategorization.for_type(:followed_article_author).first 47 c = GamificationPlugin::PointsCategorization.for_type(:followed_article_author).first
40 assert_difference 'article.author.points(:category => c.id.to_s)', c.weight do 48 assert_difference 'article.author.points(:category => c.id.to_s)', c.weight do
41 article.person_followers << person 49 article.person_followers << person
  50 + process_delayed_job_queue
42 end 51 end
43 end 52 end
44 53
@@ -46,11 +55,18 @@ class ArticleFollowerTest &lt; ActiveSupport::TestCase @@ -46,11 +55,18 @@ class ArticleFollowerTest &lt; ActiveSupport::TestCase
46 create_point_rule_definition('follower') 55 create_point_rule_definition('follower')
47 follower = create_user('someuser').person 56 follower = create_user('someuser').person
48 article = create(TextArticle, :profile_id => community.id, :author => person) 57 article = create(TextArticle, :profile_id => community.id, :author => person)
  58 +
  59 + process_delayed_job_queue
  60 +
49 score_points = follower.score_points.count 61 score_points = follower.score_points.count
50 points = follower.points 62 points = follower.points
51 article.person_followers << follower 63 article.person_followers << follower
  64 + process_delayed_job_queue
  65 +
52 assert_equal score_points + 1, follower.score_points.count 66 assert_equal score_points + 1, follower.score_points.count
53 ArticleFollower.last.destroy 67 ArticleFollower.last.destroy
  68 + process_delayed_job_queue
  69 +
54 assert_equal score_points + 2, follower.score_points.count 70 assert_equal score_points + 2, follower.score_points.count
55 assert_equal points, follower.points 71 assert_equal points, follower.points
56 end 72 end
@@ -58,9 +74,13 @@ class ArticleFollowerTest &lt; ActiveSupport::TestCase @@ -58,9 +74,13 @@ class ArticleFollowerTest &lt; ActiveSupport::TestCase
58 should 'subtract merit points to article author when a user unfollow an article' do 74 should 'subtract merit points to article author when a user unfollow an article' do
59 create_point_rule_definition('follower') 75 create_point_rule_definition('follower')
60 article = create(TextArticle, :profile_id => community.id, :author => person) 76 article = create(TextArticle, :profile_id => community.id, :author => person)
  77 +
  78 + process_delayed_job_queue
  79 +
61 assert_no_difference 'person.points' do 80 assert_no_difference 'person.points' do
62 assert_difference 'person.score_points.count' do 81 assert_difference 'person.score_points.count' do
63 article.person_followers << fast_create(Person) 82 article.person_followers << fast_create(Person)
  83 + process_delayed_job_queue
64 end 84 end
65 assert_difference 'person.score_points.count' do 85 assert_difference 'person.score_points.count' do
66 ArticleFollower.last.destroy 86 ArticleFollower.last.destroy
@@ -71,11 +91,16 @@ class ArticleFollowerTest &lt; ActiveSupport::TestCase @@ -71,11 +91,16 @@ class ArticleFollowerTest &lt; ActiveSupport::TestCase
71 should 'subtract merit points to article when a user unfollow an article' do 91 should 'subtract merit points to article when a user unfollow an article' do
72 create_point_rule_definition('followed_article') 92 create_point_rule_definition('followed_article')
73 article = create(TextArticle, :profile_id => community.id, :author => person) 93 article = create(TextArticle, :profile_id => community.id, :author => person)
  94 + process_delayed_job_queue
74 score_points = article.score_points.count 95 score_points = article.score_points.count
75 points = article.points 96 points = article.points
76 article.person_followers << person 97 article.person_followers << person
  98 + process_delayed_job_queue
  99 +
77 assert_equal score_points + 1, article.score_points.count 100 assert_equal score_points + 1, article.score_points.count
78 ArticleFollower.last.destroy 101 ArticleFollower.last.destroy
  102 + process_delayed_job_queue
  103 +
79 assert_equal score_points + 2, article.score_points.count 104 assert_equal score_points + 2, article.score_points.count
80 assert_equal points, article.points 105 assert_equal points, article.points
81 end 106 end
test/unit/article_test.rb
@@ -12,6 +12,7 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -12,6 +12,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
12 should 'add merit points to author when create a new article' do 12 should 'add merit points to author when create a new article' do
13 create_point_rule_definition('article_author') 13 create_point_rule_definition('article_author')
14 create(TextArticle, :profile_id => person.id, :author => person) 14 create(TextArticle, :profile_id => person.id, :author => person)
  15 + process_delayed_job_queue
15 assert_equal 1, person.score_points.count 16 assert_equal 1, person.score_points.count
16 assert person.score_points.first.action.present? 17 assert person.score_points.first.action.present?
17 end 18 end
@@ -19,8 +20,10 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -19,8 +20,10 @@ class ArticleTest &lt; ActiveSupport::TestCase
19 should 'subtract merit points to author when destroy an article' do 20 should 'subtract merit points to author when destroy an article' do
20 create_point_rule_definition('article_author') 21 create_point_rule_definition('article_author')
21 article = create(TextArticle, :profile_id => person.id, :author => person) 22 article = create(TextArticle, :profile_id => person.id, :author => person)
  23 + process_delayed_job_queue
22 assert_equal 1, person.score_points.count 24 assert_equal 1, person.score_points.count
23 article.destroy 25 article.destroy
  26 + process_delayed_job_queue
24 assert_equal 2, person.score_points.count 27 assert_equal 2, person.score_points.count
25 assert_equal 0, person.points 28 assert_equal 0, person.points
26 end 29 end
@@ -30,6 +33,7 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -30,6 +33,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
30 GamificationPlugin.gamification_set_rules(environment) 33 GamificationPlugin.gamification_set_rules(environment)
31 34
32 5.times { create(TextArticle, :profile_id => person.id, :author => person) } 35 5.times { create(TextArticle, :profile_id => person.id, :author => person) }
  36 + process_delayed_job_queue
33 assert_equal 'article_author', person.badges.first.name 37 assert_equal 'article_author', person.badges.first.name
34 assert_equal 1, person.badges.first.level 38 assert_equal 1, person.badges.first.level
35 end 39 end
@@ -40,6 +44,8 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -40,6 +44,8 @@ class ArticleTest &lt; ActiveSupport::TestCase
40 GamificationPlugin.gamification_set_rules(environment) 44 GamificationPlugin.gamification_set_rules(environment)
41 45
42 10.times { create(TextArticle, :profile_id => person.id, :author => person) } 46 10.times { create(TextArticle, :profile_id => person.id, :author => person) }
  47 + process_delayed_job_queue
  48 + sleep 4
43 assert_equal ['article_author'], person.badges.map(&:name).uniq 49 assert_equal ['article_author'], person.badges.map(&:name).uniq
44 assert_equal [1, 2], person.badges.map(&:level) 50 assert_equal [1, 2], person.badges.map(&:level)
45 end 51 end
@@ -48,49 +54,59 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -48,49 +54,59 @@ class ArticleTest &lt; ActiveSupport::TestCase
48 create_point_rule_definition('vote_voteable_author') 54 create_point_rule_definition('vote_voteable_author')
49 community = fast_create(Community) 55 community = fast_create(Community)
50 article = create(TextArticle, :name => 'Test', :profile => community, :author => person) 56 article = create(TextArticle, :name => 'Test', :profile => community, :author => person)
  57 + process_delayed_job_queue
51 58
52 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first 59 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first
53 - assert_difference 'article.author.points(:category => c.id.to_s)', c.weight do  
54 - Vote.create!(:voter => person, :voteable => article, :vote => 1)  
55 - end 60 + points = article.author.points(:category => c.id.to_s)
  61 + Vote.create!(:voter => person, :voteable => article, :vote => 1)
  62 + process_delayed_job_queue
  63 + assert_equal article.author.points(:category => c.id.to_s), points + c.weight
56 end 64 end
57 65
58 should 'add merit points to article when an user like it' do 66 should 'add merit points to article when an user like it' do
59 create_point_rule_definition('vote_voteable') 67 create_point_rule_definition('vote_voteable')
60 article = create(TextArticle, :name => 'Test', :profile => person, :author => person) 68 article = create(TextArticle, :name => 'Test', :profile => person, :author => person)
  69 + process_delayed_job_queue
61 article = article.reload 70 article = article.reload
62 71
63 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable).first 72 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable).first
64 assert_difference 'article.points(:category => c.id.to_s)', c.weight do 73 assert_difference 'article.points(:category => c.id.to_s)', c.weight do
65 Vote.create!(:voter => person, :voteable => article, :vote => 1) 74 Vote.create!(:voter => person, :voteable => article, :vote => 1)
  75 + process_delayed_job_queue
66 end 76 end
67 end 77 end
68 78
69 should 'add merit points to community when create a new article' do 79 should 'add merit points to community when create a new article' do
70 create_point_rule_definition('article_community') 80 create_point_rule_definition('article_community')
71 community = fast_create(Community) 81 community = fast_create(Community)
  82 + process_delayed_job_queue
72 assert_difference 'community.score_points.count' do 83 assert_difference 'community.score_points.count' do
73 create(TextArticle, :profile_id => community.id, :author => person) 84 create(TextArticle, :profile_id => community.id, :author => person)
  85 + process_delayed_job_queue
74 end 86 end
75 end 87 end
76 88
77 should 'add merit points to voter when he likes an article' do 89 should 'add merit points to voter when he likes an article' do
78 create_point_rule_definition('vote_voter') 90 create_point_rule_definition('vote_voter')
79 article = create(TextArticle, :name => 'Test', :profile => person, :author => person) 91 article = create(TextArticle, :name => 'Test', :profile => person, :author => person)
  92 + process_delayed_job_queue
80 93
81 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first 94 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first
82 assert_difference 'article.author.points(:category => c.id.to_s)', c.weight do 95 assert_difference 'article.author.points(:category => c.id.to_s)', c.weight do
83 Vote.create!(:voter => person, :voteable => article, :vote => 1) 96 Vote.create!(:voter => person, :voteable => article, :vote => 1)
  97 + process_delayed_job_queue
84 end 98 end
85 end 99 end
86 100
87 should 'add merit points to voter when he dislikes an article' do 101 should 'add merit points to voter when he dislikes an article' do
88 create_point_rule_definition('vote_voter') 102 create_point_rule_definition('vote_voter')
89 article = create(TextArticle, :name => 'Test', :profile => person, :author => person) 103 article = create(TextArticle, :name => 'Test', :profile => person, :author => person)
  104 + process_delayed_job_queue
90 105
91 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first 106 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first
92 assert_difference 'article.author.points(:category => c.id.to_s)', c.weight do 107 assert_difference 'article.author.points(:category => c.id.to_s)', c.weight do
93 Vote.create!(:voter => person, :voteable => article, :vote => -1) 108 Vote.create!(:voter => person, :voteable => article, :vote => -1)
  109 + process_delayed_job_queue
94 end 110 end
95 end 111 end
96 112
@@ -101,8 +117,10 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -101,8 +117,10 @@ class ArticleTest &lt; ActiveSupport::TestCase
101 article = create(TextArticle, :name => 'Test', :profile => person, :author => person) 117 article = create(TextArticle, :name => 'Test', :profile => person, :author => person)
102 4.times { Vote.create!(:voter => fast_create(Person), :voteable => article, :vote => 1) } 118 4.times { Vote.create!(:voter => fast_create(Person), :voteable => article, :vote => 1) }
103 Vote.create!(:voter => fast_create(Person), :voteable => article, :vote => -1) 119 Vote.create!(:voter => fast_create(Person), :voteable => article, :vote => -1)
  120 + process_delayed_job_queue
104 assert_equal [], person.badges 121 assert_equal [], person.badges
105 Vote.create!(:voter => fast_create(Person), :voteable => article, :vote => 1) 122 Vote.create!(:voter => fast_create(Person), :voteable => article, :vote => 1)
  123 + process_delayed_job_queue
106 assert_equal 'positive_votes_received', person.reload.badges.first.name 124 assert_equal 'positive_votes_received', person.reload.badges.first.name
107 end 125 end
108 126
@@ -113,8 +131,10 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -113,8 +131,10 @@ class ArticleTest &lt; ActiveSupport::TestCase
113 article = create(TextArticle, :name => 'Test', :profile => person, :author => person) 131 article = create(TextArticle, :name => 'Test', :profile => person, :author => person)
114 4.times { Vote.create!(:voter => fast_create(Person), :voteable => article, :vote => -1) } 132 4.times { Vote.create!(:voter => fast_create(Person), :voteable => article, :vote => -1) }
115 Vote.create!(:voter => fast_create(Person), :voteable => article, :vote => 1) 133 Vote.create!(:voter => fast_create(Person), :voteable => article, :vote => 1)
  134 + process_delayed_job_queue
116 assert_equal [], person.badges 135 assert_equal [], person.badges
117 Vote.create!(:voter => fast_create(Person), :voteable => article, :vote => -1) 136 Vote.create!(:voter => fast_create(Person), :voteable => article, :vote => -1)
  137 + process_delayed_job_queue
118 assert_equal 'negative_votes_received', person.reload.badges.first.name 138 assert_equal 'negative_votes_received', person.reload.badges.first.name
119 end 139 end
120 140
@@ -123,6 +143,7 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -123,6 +143,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
123 community = fast_create(Community) 143 community = fast_create(Community)
124 rule = create_point_rule_definition('article_author', community) 144 rule = create_point_rule_definition('article_author', community)
125 create(TextArticle, profile_id: community.id, author_id: person.id) 145 create(TextArticle, profile_id: community.id, author_id: person.id)
  146 + process_delayed_job_queue
126 assert_equal rule.weight, person.points_by_profile(community.identifier) 147 assert_equal rule.weight, person.points_by_profile(community.identifier)
127 assert person.score_points.first.action.present? 148 assert person.score_points.first.action.present?
128 end 149 end
@@ -131,8 +152,10 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -131,8 +152,10 @@ class ArticleTest &lt; ActiveSupport::TestCase
131 community = fast_create(Community) 152 community = fast_create(Community)
132 rule = create_point_rule_definition('article_author', community) 153 rule = create_point_rule_definition('article_author', community)
133 article = create(TextArticle, profile_id: community.id, author_id: person.id) 154 article = create(TextArticle, profile_id: community.id, author_id: person.id)
  155 + process_delayed_job_queue
134 assert_equal rule.weight, person.points_by_profile(community.identifier) 156 assert_equal rule.weight, person.points_by_profile(community.identifier)
135 article.destroy 157 article.destroy
  158 + process_delayed_job_queue
136 assert_equal 0, person.points 159 assert_equal 0, person.points
137 end 160 end
138 161
@@ -140,10 +163,12 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -140,10 +163,12 @@ class ArticleTest &lt; ActiveSupport::TestCase
140 community = fast_create(Community) 163 community = fast_create(Community)
141 create_point_rule_definition('vote_voteable_author', community) 164 create_point_rule_definition('vote_voteable_author', community)
142 article = create(TextArticle, :name => 'Test', :profile => community, :author => person) 165 article = create(TextArticle, :name => 'Test', :profile => community, :author => person)
  166 + process_delayed_job_queue
143 167
144 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first 168 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first
145 assert_difference 'article.author.points(:category => c.id.to_s)', c.weight do 169 assert_difference 'article.author.points(:category => c.id.to_s)', c.weight do
146 Vote.create!(:voter => person, :voteable => article, :vote => 1) 170 Vote.create!(:voter => person, :voteable => article, :vote => 1)
  171 + process_delayed_job_queue
147 end 172 end
148 end 173 end
149 174
@@ -151,19 +176,23 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -151,19 +176,23 @@ class ArticleTest &lt; ActiveSupport::TestCase
151 community = fast_create(Community) 176 community = fast_create(Community)
152 create_point_rule_definition('vote_voteable', community) 177 create_point_rule_definition('vote_voteable', community)
153 article = create(TextArticle, :name => 'Test', :profile => community, :author => person) 178 article = create(TextArticle, :name => 'Test', :profile => community, :author => person)
  179 + process_delayed_job_queue
154 article = article.reload 180 article = article.reload
155 181
156 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable).first 182 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable).first
157 assert_difference 'article.points(:category => c.id.to_s)', c.weight do 183 assert_difference 'article.points(:category => c.id.to_s)', c.weight do
158 Vote.create!(:voter => person, :voteable => article, :vote => 1) 184 Vote.create!(:voter => person, :voteable => article, :vote => 1)
  185 + process_delayed_job_queue
159 end 186 end
160 end 187 end
161 188
162 should 'add merit points to community when create a new article on community' do 189 should 'add merit points to community when create a new article on community' do
163 community = fast_create(Community) 190 community = fast_create(Community)
164 create_point_rule_definition('article_community') 191 create_point_rule_definition('article_community')
  192 + process_delayed_job_queue
165 assert_difference 'community.score_points.count' do 193 assert_difference 'community.score_points.count' do
166 create(TextArticle, :profile_id => community.id, :author => person) 194 create(TextArticle, :profile_id => community.id, :author => person)
  195 + process_delayed_job_queue
167 end 196 end
168 end 197 end
169 198
@@ -171,10 +200,12 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -171,10 +200,12 @@ class ArticleTest &lt; ActiveSupport::TestCase
171 community = fast_create(Community) 200 community = fast_create(Community)
172 create_point_rule_definition('vote_voter', community) 201 create_point_rule_definition('vote_voter', community)
173 article = create(TextArticle, :name => 'Test', :profile => community, :author => person) 202 article = create(TextArticle, :name => 'Test', :profile => community, :author => person)
  203 + process_delayed_job_queue
174 204
175 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first 205 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first
176 assert_difference 'article.author.points(:category => c.id.to_s)', c.weight do 206 assert_difference 'article.author.points(:category => c.id.to_s)', c.weight do
177 Vote.create!(:voter => person, :voteable => article, :vote => 1) 207 Vote.create!(:voter => person, :voteable => article, :vote => 1)
  208 + process_delayed_job_queue
178 end 209 end
179 end 210 end
180 211
@@ -182,11 +213,35 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -182,11 +213,35 @@ class ArticleTest &lt; ActiveSupport::TestCase
182 community = fast_create(Community) 213 community = fast_create(Community)
183 create_point_rule_definition('vote_voter', community) 214 create_point_rule_definition('vote_voter', community)
184 article = create(TextArticle, :name => 'Test', :profile => community, :author => person) 215 article = create(TextArticle, :name => 'Test', :profile => community, :author => person)
  216 + process_delayed_job_queue
185 217
186 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first 218 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first
187 assert_difference 'article.author.points(:category => c.id.to_s)', c.weight do 219 assert_difference 'article.author.points(:category => c.id.to_s)', c.weight do
188 Vote.create!(:voter => person, :voteable => article, :vote => -1) 220 Vote.create!(:voter => person, :voteable => article, :vote => -1)
  221 + process_delayed_job_queue
189 end 222 end
190 end 223 end
191 224
  225 + should "add organization's merit badge to author when create 5 new articles" do
  226 + organization = fast_create(Organization)
  227 + GamificationPlugin::Badge.create!(:owner => organization, :name => 'article_author', :level => 1)
  228 + GamificationPlugin.gamification_set_rules(environment)
  229 +
  230 + 5.times { create(TextArticle, :profile_id => organization.id, :author => person) }
  231 + process_delayed_job_queue
  232 + assert_equal 'article_author', person.badges.first.name
  233 + assert_equal 1, person.badges.first.level
  234 + end
  235 +
  236 + should "do not earn organization's badge when the article is not posted in the organization itself" do
  237 + organization = fast_create(Organization)
  238 + other_organization = fast_create(Organization)
  239 + GamificationPlugin::Badge.create!(:owner => organization, :name => 'article_author', :level => 1)
  240 + GamificationPlugin.gamification_set_rules(environment)
  241 +
  242 + 5.times { create(TextArticle, :profile_id => other_organization.id, :author => person) }
  243 + process_delayed_job_queue
  244 + assert_equal [], person.badges
  245 + end
  246 +
192 end 247 end
test/unit/badge_rules_test.rb 0 → 100644
@@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
  1 +require_relative "../test_helper"
  2 +
  3 +class BadgeRulesTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @environment = Environment.default
  7 + end
  8 +
  9 + attr_accessor :environment
  10 +
  11 + should "define badge rules for environment's badges" do
  12 + badge = GamificationPlugin::Badge.create!(:owner => environment, :name => :comment_author)
  13 + badge_rules = Merit::BadgeRules.new(environment)
  14 + assert_equal [Merit::BadgeRules::AVAILABLE_RULES[badge.name.to_sym].first[:action]], badge_rules.defined_rules.keys
  15 + end
  16 +
  17 + should "define badge rules for organization's badges" do
  18 + organization = fast_create(Organization)
  19 + badge = GamificationPlugin::Badge.create!(:owner => organization, :name => :comment_author)
  20 + badge_rules = Merit::BadgeRules.new(environment)
  21 + assert_equal [Merit::BadgeRules::AVAILABLE_RULES[badge.name.to_sym].first[:action]], badge_rules.defined_rules.keys
  22 + end
  23 +
  24 + should 'check organization returns true when badge belongs to the environment' do
  25 + badge = GamificationPlugin::Badge.create!(:owner => environment, :name => :comment_author)
  26 + badge_rules = Merit::BadgeRules.new(environment)
  27 + comment = fast_create(Comment)
  28 + assert badge_rules.check_organization_badge(badge, comment, Merit::BadgeRules::AVAILABLE_RULES[badge.name.to_sym].first)
  29 + end
  30 +
  31 + should 'check organization returns true when the comment belongs to the organization' do
  32 + organization = fast_create(Organization)
  33 + badge = GamificationPlugin::Badge.create!(:owner => organization, :name => :comment_author)
  34 + badge_rules = Merit::BadgeRules.new(environment)
  35 + article = fast_create(Article,:profile_id => organization.id)
  36 + comment = fast_create(Comment, :source_id => article.id)
  37 + assert badge_rules.check_organization_badge(badge, comment, Merit::BadgeRules::AVAILABLE_RULES[badge.name.to_sym].first)
  38 + end
  39 +
  40 + should 'check organization returns false when the comment does not belongs to the organization' do
  41 + organization = fast_create(Organization)
  42 + badge = GamificationPlugin::Badge.create!(:owner => organization, :name => :comment_author)
  43 + badge_rules = Merit::BadgeRules.new(environment)
  44 + comment = fast_create(Comment)
  45 + assert !badge_rules.check_organization_badge(badge, comment, Merit::BadgeRules::AVAILABLE_RULES[badge.name.to_sym].first)
  46 + end
  47 +
  48 +end
test/unit/badge_test.rb
@@ -5,9 +5,10 @@ class BadgeTest &lt; ActiveSupport::TestCase @@ -5,9 +5,10 @@ class BadgeTest &lt; ActiveSupport::TestCase
5 def setup 5 def setup
6 @person = create_user('testuser').person 6 @person = create_user('testuser').person
7 @environment = Environment.default 7 @environment = Environment.default
  8 + @organization = fast_create(Organization)
8 end 9 end
9 10
10 - attr_accessor :person, :environment 11 + attr_accessor :person, :environment, :organization
11 12
12 should 'add badge to person' do 13 should 'add badge to person' do
13 badge = GamificationPlugin::Badge.create!(:owner => environment) 14 badge = GamificationPlugin::Badge.create!(:owner => environment)
@@ -37,4 +38,16 @@ class BadgeTest &lt; ActiveSupport::TestCase @@ -37,4 +38,16 @@ class BadgeTest &lt; ActiveSupport::TestCase
37 assert_equal [badge2], person.badges.notification_pending 38 assert_equal [badge2], person.badges.notification_pending
38 end 39 end
39 40
  41 + should 'add badge to person with organization as the badge owner' do
  42 + badge = GamificationPlugin::Badge.create(:owner => organization)
  43 + person.add_badge(badge.id)
  44 + assert_equal [badge], person.badges
  45 + end
  46 +
  47 + should 'add a manual badge to person' do
  48 + badge = GamificationPlugin::Badge.create!(:name => :manual, :owner => environment)
  49 + person.add_badge(badge.id)
  50 + assert_equal [badge], person.badges
  51 + end
  52 +
40 end 53 end
test/unit/comment_test.rb
@@ -13,14 +13,17 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -13,14 +13,17 @@ class CommentTest &lt; ActiveSupport::TestCase
13 should 'add merit points to author when create a new comment' do 13 should 'add merit points to author when create a new comment' do
14 create_point_rule_definition('comment_author') 14 create_point_rule_definition('comment_author')
15 create(Comment, :source => article, :author_id => person.id) 15 create(Comment, :source => article, :author_id => person.id)
  16 + process_delayed_job_queue
16 assert_equal 1, person.score_points.count 17 assert_equal 1, person.score_points.count
17 end 18 end
18 19
19 should 'subtract merit points from author when destroy a comment' do 20 should 'subtract merit points from author when destroy a comment' do
20 create_point_rule_definition('comment_author') 21 create_point_rule_definition('comment_author')
21 comment = create(Comment, :source => article, :author_id => person.id) 22 comment = create(Comment, :source => article, :author_id => person.id)
  23 + process_delayed_job_queue
22 assert_equal 1, person.score_points.count 24 assert_equal 1, person.score_points.count
23 comment.destroy 25 comment.destroy
  26 + process_delayed_job_queue
24 assert_equal 2, person.score_points.count 27 assert_equal 2, person.score_points.count
25 assert_equal 0, person.points 28 assert_equal 0, person.points
26 end 29 end
@@ -30,6 +33,7 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -30,6 +33,7 @@ class CommentTest &lt; ActiveSupport::TestCase
30 GamificationPlugin.gamification_set_rules(environment) 33 GamificationPlugin.gamification_set_rules(environment)
31 34
32 5.times { create(Comment, :source => article, :author_id => person.id) } 35 5.times { create(Comment, :source => article, :author_id => person.id) }
  36 + process_delayed_job_queue
33 assert_equal 'comment_author', person.badges.first.name 37 assert_equal 'comment_author', person.badges.first.name
34 end 38 end
35 39
@@ -38,6 +42,7 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -38,6 +42,7 @@ class CommentTest &lt; ActiveSupport::TestCase
38 GamificationPlugin.gamification_set_rules(environment) 42 GamificationPlugin.gamification_set_rules(environment)
39 43
40 5.times { create(Comment, :source => article, :author_id => person.id) } 44 5.times { create(Comment, :source => article, :author_id => person.id) }
  45 + process_delayed_job_queue
41 assert_equal 'comment_received', author.badges.first.name 46 assert_equal 'comment_received', author.badges.first.name
42 end 47 end
43 48
@@ -48,8 +53,10 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -48,8 +53,10 @@ class CommentTest &lt; ActiveSupport::TestCase
48 comment = create(Comment, :source => article, :author_id => person.id) 53 comment = create(Comment, :source => article, :author_id => person.id)
49 4.times { Vote.create!(:voter => fast_create(Person), :voteable => comment, :vote => 1) } 54 4.times { Vote.create!(:voter => fast_create(Person), :voteable => comment, :vote => 1) }
50 Vote.create!(:voter => fast_create(Person), :voteable => comment, :vote => -1) 55 Vote.create!(:voter => fast_create(Person), :voteable => comment, :vote => -1)
  56 + process_delayed_job_queue
51 assert_equal [], person.badges 57 assert_equal [], person.badges
52 Vote.create!(:voter => fast_create(Person), :voteable => comment, :vote => 1) 58 Vote.create!(:voter => fast_create(Person), :voteable => comment, :vote => 1)
  59 + process_delayed_job_queue
53 assert_equal 'positive_votes_received', person.reload.badges.first.name 60 assert_equal 'positive_votes_received', person.reload.badges.first.name
54 end 61 end
55 62
@@ -60,18 +67,22 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -60,18 +67,22 @@ class CommentTest &lt; ActiveSupport::TestCase
60 comment = create(Comment, :source => article, :author_id => person.id) 67 comment = create(Comment, :source => article, :author_id => person.id)
61 4.times { Vote.create!(:voter => fast_create(Person), :voteable => comment, :vote => -1) } 68 4.times { Vote.create!(:voter => fast_create(Person), :voteable => comment, :vote => -1) }
62 Vote.create!(:voter => fast_create(Person), :voteable => comment, :vote => 1) 69 Vote.create!(:voter => fast_create(Person), :voteable => comment, :vote => 1)
  70 + process_delayed_job_queue
63 assert_equal [], person.badges 71 assert_equal [], person.badges
64 Vote.create!(:voter => fast_create(Person), :voteable => comment, :vote => -1) 72 Vote.create!(:voter => fast_create(Person), :voteable => comment, :vote => -1)
  73 + process_delayed_job_queue
65 assert_equal 'negative_votes_received', person.reload.badges.first.name 74 assert_equal 'negative_votes_received', person.reload.badges.first.name
66 end 75 end
67 76
68 should 'add merit points to comment owner when an user like his comment' do 77 should 'add merit points to comment owner when an user like his comment' do
69 create_point_rule_definition('vote_voteable_author') 78 create_point_rule_definition('vote_voteable_author')
70 comment = create(Comment, :source => article, :author_id => person.id) 79 comment = create(Comment, :source => article, :author_id => person.id)
  80 + process_delayed_job_queue
71 81
72 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first 82 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first
73 assert_difference 'comment.author.points(:category => c.id.to_s)', c.weight do 83 assert_difference 'comment.author.points(:category => c.id.to_s)', c.weight do
74 Vote.create!(:voter => person, :voteable => comment, :vote => 1) 84 Vote.create!(:voter => person, :voteable => comment, :vote => 1)
  85 + process_delayed_job_queue
75 end 86 end
76 end 87 end
77 88
@@ -79,20 +90,24 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -79,20 +90,24 @@ class CommentTest &lt; ActiveSupport::TestCase
79 create_point_rule_definition('vote_voteable_author') 90 create_point_rule_definition('vote_voteable_author')
80 comment = create(Comment, :source => article, :author_id => author.id) 91 comment = create(Comment, :source => article, :author_id => author.id)
81 Vote.create!(:voter => person, :voteable => comment, :vote => 1) 92 Vote.create!(:voter => person, :voteable => comment, :vote => 1)
  93 + process_delayed_job_queue
82 94
83 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first 95 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first
84 assert_difference 'comment.author.points', -1*c.weight do 96 assert_difference 'comment.author.points', -1*c.weight do
85 Vote.where(:voteable_id => comment.id).destroy_all 97 Vote.where(:voteable_id => comment.id).destroy_all
  98 + process_delayed_job_queue
86 end 99 end
87 end 100 end
88 101
89 should 'subtract merit points from comment owner when an user dislike his comment' do 102 should 'subtract merit points from comment owner when an user dislike his comment' do
90 create_point_rule_definition('vote_voteable_author') 103 create_point_rule_definition('vote_voteable_author')
91 comment = create(Comment, :source => article, :author_id => person.id) 104 comment = create(Comment, :source => article, :author_id => person.id)
  105 + process_delayed_job_queue
92 106
93 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first 107 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first
94 assert_difference 'comment.author.points(:category => c.id.to_s)', -1*c.weight do 108 assert_difference 'comment.author.points(:category => c.id.to_s)', -1*c.weight do
95 Vote.create!(:voter => person, :voteable => comment, :vote => -1) 109 Vote.create!(:voter => person, :voteable => comment, :vote => -1)
  110 + process_delayed_job_queue
96 end 111 end
97 end 112 end
98 113
@@ -100,37 +115,44 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -100,37 +115,44 @@ class CommentTest &lt; ActiveSupport::TestCase
100 create_point_rule_definition('vote_voteable_author') 115 create_point_rule_definition('vote_voteable_author')
101 comment = create(Comment, :source => article, :author_id => author.id) 116 comment = create(Comment, :source => article, :author_id => author.id)
102 Vote.create!(:voter => person, :voteable => comment, :vote => -1) 117 Vote.create!(:voter => person, :voteable => comment, :vote => -1)
  118 + process_delayed_job_queue
103 119
104 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first 120 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first
105 assert_difference 'comment.author.points', c.weight do 121 assert_difference 'comment.author.points', c.weight do
106 Vote.where(:voteable_id => comment.id).destroy_all 122 Vote.where(:voteable_id => comment.id).destroy_all
  123 + process_delayed_job_queue
107 end 124 end
108 end 125 end
109 126
110 should 'add merit points to article author when create a new comment' do 127 should 'add merit points to article author when create a new comment' do
111 create_point_rule_definition('comment_article_author') 128 create_point_rule_definition('comment_article_author')
112 - assert_difference 'author.score_points.count' do  
113 - create(Comment, :source => article, :author_id => person.id)  
114 - end 129 + scores = author.score_points.count
  130 + create(Comment, :source => article, :author_id => person.id)
  131 + process_delayed_job_queue
  132 + assert_not_equal author.reload.score_points.count, scores
115 end 133 end
116 134
117 should 'add merit points to voter when he likes a comment' do 135 should 'add merit points to voter when he likes a comment' do
118 create_point_rule_definition('vote_voter') 136 create_point_rule_definition('vote_voter')
119 comment = create(Comment, :source => article, :author_id => person.id) 137 comment = create(Comment, :source => article, :author_id => person.id)
  138 + process_delayed_job_queue
120 139
121 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first 140 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first
122 assert_difference 'comment.author.points(:category => c.id.to_s)', c.weight do 141 assert_difference 'comment.author.points(:category => c.id.to_s)', c.weight do
123 Vote.create!(:voter => person, :voteable => comment, :vote => 1) 142 Vote.create!(:voter => person, :voteable => comment, :vote => 1)
  143 + process_delayed_job_queue
124 end 144 end
125 end 145 end
126 146
127 should 'add merit points to voter when he dislikes a comment' do 147 should 'add merit points to voter when he dislikes a comment' do
128 create_point_rule_definition('vote_voter') 148 create_point_rule_definition('vote_voter')
129 comment = create(Comment, :source => article, :author_id => person.id) 149 comment = create(Comment, :source => article, :author_id => person.id)
  150 + process_delayed_job_queue
130 151
131 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first 152 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first
132 assert_difference 'comment.author.points(:category => c.id.to_s)', c.weight do 153 assert_difference 'comment.author.points(:category => c.id.to_s)', c.weight do
133 Vote.create!(:voter => person, :voteable => comment, :vote => -1) 154 Vote.create!(:voter => person, :voteable => comment, :vote => -1)
  155 + process_delayed_job_queue
134 end 156 end
135 end 157 end
136 158
@@ -139,6 +161,7 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -139,6 +161,7 @@ class CommentTest &lt; ActiveSupport::TestCase
139 c = GamificationPlugin::PointsCategorization.for_type(:comment_article).first 161 c = GamificationPlugin::PointsCategorization.for_type(:comment_article).first
140 assert_difference 'article.points(:category => c.id.to_s)', c.weight do 162 assert_difference 'article.points(:category => c.id.to_s)', c.weight do
141 create(Comment, :source => article, :author_id => person.id) 163 create(Comment, :source => article, :author_id => person.id)
  164 + process_delayed_job_queue
142 end 165 end
143 end 166 end
144 167
@@ -146,10 +169,12 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -146,10 +169,12 @@ class CommentTest &lt; ActiveSupport::TestCase
146 create_point_rule_definition('comment_community') 169 create_point_rule_definition('comment_community')
147 community = fast_create(Community) 170 community = fast_create(Community)
148 article = create(TextileArticle, :profile_id => community.id, :author_id => author.id) 171 article = create(TextileArticle, :profile_id => community.id, :author_id => author.id)
  172 + process_delayed_job_queue
149 173
150 c = GamificationPlugin::PointsCategorization.for_type(:comment_community).first 174 c = GamificationPlugin::PointsCategorization.for_type(:comment_community).first
151 assert_difference 'community.points(:category => c.id.to_s)', c.weight do 175 assert_difference 'community.points(:category => c.id.to_s)', c.weight do
152 create(Comment, :source => article, :author_id => person.id) 176 create(Comment, :source => article, :author_id => person.id)
  177 + process_delayed_job_queue
153 end 178 end
154 end 179 end
155 180
@@ -157,8 +182,10 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -157,8 +182,10 @@ class CommentTest &lt; ActiveSupport::TestCase
157 should 'add merit community points to author when create a new comment in a community' do 182 should 'add merit community points to author when create a new comment in a community' do
158 community = fast_create(Community) 183 community = fast_create(Community)
159 article = create(TextArticle, profile_id: community.id, author_id: person.id) 184 article = create(TextArticle, profile_id: community.id, author_id: person.id)
  185 + process_delayed_job_queue
160 rule = create_point_rule_definition('comment_author', article.profile) 186 rule = create_point_rule_definition('comment_author', article.profile)
161 create(Comment, :source => article, :author_id => person.id) 187 create(Comment, :source => article, :author_id => person.id)
  188 + process_delayed_job_queue
162 assert_equal rule.weight, person.points_by_profile(article.profile.identifier) 189 assert_equal rule.weight, person.points_by_profile(article.profile.identifier)
163 end 190 end
164 191
@@ -167,6 +194,7 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -167,6 +194,7 @@ class CommentTest &lt; ActiveSupport::TestCase
167 article = create(TextArticle, profile_id: community.id, author_id: fast_create(Person).id) 194 article = create(TextArticle, profile_id: community.id, author_id: fast_create(Person).id)
168 rule = create_point_rule_definition('comment_author', article.profile) 195 rule = create_point_rule_definition('comment_author', article.profile)
169 comment = create(Comment, :source => article, :author_id => person.id) 196 comment = create(Comment, :source => article, :author_id => person.id)
  197 + process_delayed_job_queue
170 assert_equal rule.weight, person.points_by_profile(article.profile.identifier) 198 assert_equal rule.weight, person.points_by_profile(article.profile.identifier)
171 comment.destroy 199 comment.destroy
172 assert_equal 0, person.points_by_profile(article.profile.identifier) 200 assert_equal 0, person.points_by_profile(article.profile.identifier)
@@ -177,10 +205,12 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -177,10 +205,12 @@ class CommentTest &lt; ActiveSupport::TestCase
177 article = create(TextArticle, profile_id: community.id, author_id: person.id) 205 article = create(TextArticle, profile_id: community.id, author_id: person.id)
178 create_point_rule_definition('vote_voteable_author', community) 206 create_point_rule_definition('vote_voteable_author', community)
179 comment = create(Comment, :source => article, :author_id => person.id) 207 comment = create(Comment, :source => article, :author_id => person.id)
  208 + process_delayed_job_queue
180 209
181 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).where(profile_id: article.profile.id).first 210 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).where(profile_id: article.profile.id).first
182 assert_difference 'comment.author.points(:category => c.id.to_s)', c.weight do 211 assert_difference 'comment.author.points(:category => c.id.to_s)', c.weight do
183 Vote.create!(:voter => person, :voteable => comment, :vote => 1) 212 Vote.create!(:voter => person, :voteable => comment, :vote => 1)
  213 + process_delayed_job_queue
184 end 214 end
185 end 215 end
186 216
@@ -190,6 +220,7 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -190,6 +220,7 @@ class CommentTest &lt; ActiveSupport::TestCase
190 create_point_rule_definition('vote_voteable_author', community) 220 create_point_rule_definition('vote_voteable_author', community)
191 comment = create(Comment, :source => article, :author_id => author.id) 221 comment = create(Comment, :source => article, :author_id => author.id)
192 Vote.create!(:voter => person, :voteable => comment, :vote => 1) 222 Vote.create!(:voter => person, :voteable => comment, :vote => 1)
  223 + process_delayed_job_queue
193 224
194 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first 225 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first
195 assert_difference 'comment.author.points_by_profile(community.identifier)', -1*c.weight do 226 assert_difference 'comment.author.points_by_profile(community.identifier)', -1*c.weight do
@@ -202,10 +233,12 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -202,10 +233,12 @@ class CommentTest &lt; ActiveSupport::TestCase
202 article = create(TextArticle, profile_id: community.id, author_id: person.id) 233 article = create(TextArticle, profile_id: community.id, author_id: person.id)
203 create_point_rule_definition('vote_voteable_author', community) 234 create_point_rule_definition('vote_voteable_author', community)
204 comment = create(Comment, :source => article, :author_id => person.id) 235 comment = create(Comment, :source => article, :author_id => person.id)
  236 + process_delayed_job_queue
205 237
206 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).where(profile_id: article.profile.id).first 238 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).where(profile_id: article.profile.id).first
207 assert_difference 'comment.author.points(:category => c.id.to_s)', -1*c.weight do 239 assert_difference 'comment.author.points(:category => c.id.to_s)', -1*c.weight do
208 Vote.create!(:voter => person, :voteable => comment, :vote => -1) 240 Vote.create!(:voter => person, :voteable => comment, :vote => -1)
  241 + process_delayed_job_queue
209 end 242 end
210 end 243 end
211 244
@@ -215,6 +248,7 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -215,6 +248,7 @@ class CommentTest &lt; ActiveSupport::TestCase
215 create_point_rule_definition('vote_voteable_author', community) 248 create_point_rule_definition('vote_voteable_author', community)
216 comment = create(Comment, :source => article, :author_id => author.id) 249 comment = create(Comment, :source => article, :author_id => author.id)
217 Vote.create!(:voter => person, :voteable => comment, :vote => -1) 250 Vote.create!(:voter => person, :voteable => comment, :vote => -1)
  251 + process_delayed_job_queue
218 252
219 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first 253 c = GamificationPlugin::PointsCategorization.for_type(:vote_voteable_author).first
220 assert_difference 'comment.author.points_by_profile(community.identifier)', c.weight do 254 assert_difference 'comment.author.points_by_profile(community.identifier)', c.weight do
@@ -225,9 +259,11 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -225,9 +259,11 @@ class CommentTest &lt; ActiveSupport::TestCase
225 should 'add merit community points to article author when create a new comment inside a community' do 259 should 'add merit community points to article author when create a new comment inside a community' do
226 community = fast_create(Community) 260 community = fast_create(Community)
227 article = create(TextArticle, profile_id: community.id, author_id: author.id) 261 article = create(TextArticle, profile_id: community.id, author_id: author.id)
  262 + process_delayed_job_queue
228 rule = create_point_rule_definition('comment_article_author', community) 263 rule = create_point_rule_definition('comment_article_author', community)
229 assert_difference 'author.points_by_profile(community.identifier)', rule.weight do 264 assert_difference 'author.points_by_profile(community.identifier)', rule.weight do
230 create(Comment, :source => article, :author_id => author.id) 265 create(Comment, :source => article, :author_id => author.id)
  266 + process_delayed_job_queue
231 end 267 end
232 end 268 end
233 269
@@ -236,10 +272,12 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -236,10 +272,12 @@ class CommentTest &lt; ActiveSupport::TestCase
236 article = create(TextArticle, profile_id: community.id, author_id: person.id) 272 article = create(TextArticle, profile_id: community.id, author_id: person.id)
237 create_point_rule_definition('vote_voter') 273 create_point_rule_definition('vote_voter')
238 comment = create(Comment, :source => article, :author_id => person.id) 274 comment = create(Comment, :source => article, :author_id => person.id)
  275 + process_delayed_job_queue
239 276
240 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first 277 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first
241 assert_difference 'comment.author.points(:category => c.id.to_s)', c.weight do 278 assert_difference 'comment.author.points(:category => c.id.to_s)', c.weight do
242 Vote.create!(:voter => person, :voteable => comment, :vote => 1) 279 Vote.create!(:voter => person, :voteable => comment, :vote => 1)
  280 + process_delayed_job_queue
243 end 281 end
244 end 282 end
245 283
@@ -248,20 +286,24 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -248,20 +286,24 @@ class CommentTest &lt; ActiveSupport::TestCase
248 article = create(TextArticle, profile_id: community.id, author_id: person.id) 286 article = create(TextArticle, profile_id: community.id, author_id: person.id)
249 create_point_rule_definition('vote_voter') 287 create_point_rule_definition('vote_voter')
250 comment = create(Comment, :source => article, :author_id => person.id) 288 comment = create(Comment, :source => article, :author_id => person.id)
  289 + process_delayed_job_queue
251 290
252 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first 291 c = GamificationPlugin::PointsCategorization.for_type(:vote_voter).first
253 assert_difference 'comment.author.points(:category => c.id.to_s)', c.weight do 292 assert_difference 'comment.author.points(:category => c.id.to_s)', c.weight do
254 Vote.create!(:voter => person, :voteable => comment, :vote => -1) 293 Vote.create!(:voter => person, :voteable => comment, :vote => -1)
  294 + process_delayed_job_queue
255 end 295 end
256 end 296 end
257 297
258 should 'add merit community points to source article when create a comment inside a community' do 298 should 'add merit community points to source article when create a comment inside a community' do
259 community = fast_create(Community) 299 community = fast_create(Community)
260 article = create(TextArticle, profile_id: community.id, author_id: person.id) 300 article = create(TextArticle, profile_id: community.id, author_id: person.id)
  301 + process_delayed_job_queue
261 create_point_rule_definition('comment_article') 302 create_point_rule_definition('comment_article')
262 c = GamificationPlugin::PointsCategorization.for_type(:comment_article).first 303 c = GamificationPlugin::PointsCategorization.for_type(:comment_article).first
263 assert_difference 'article.points(:category => c.id.to_s)', c.weight do 304 assert_difference 'article.points(:category => c.id.to_s)', c.weight do
264 create(Comment, :source => article, :author_id => person.id) 305 create(Comment, :source => article, :author_id => person.id)
  306 + process_delayed_job_queue
265 end 307 end
266 end 308 end
267 309
@@ -269,12 +311,24 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -269,12 +311,24 @@ class CommentTest &lt; ActiveSupport::TestCase
269 create_point_rule_definition('comment_community') 311 create_point_rule_definition('comment_community')
270 community = fast_create(Community) 312 community = fast_create(Community)
271 article = create(TextileArticle, :profile_id => community.id, :author_id => author.id) 313 article = create(TextileArticle, :profile_id => community.id, :author_id => author.id)
  314 + process_delayed_job_queue
272 315
273 c = GamificationPlugin::PointsCategorization.for_type(:comment_community).first 316 c = GamificationPlugin::PointsCategorization.for_type(:comment_community).first
274 assert_difference 'community.points(:category => c.id.to_s)', c.weight do 317 assert_difference 'community.points(:category => c.id.to_s)', c.weight do
275 create(Comment, :source => article, :author_id => person.id) 318 create(Comment, :source => article, :author_id => person.id)
  319 + process_delayed_job_queue
276 end 320 end
277 end 321 end
278 322
  323 + should "add organization's merit badge to author when create 5 new comments" do
  324 + organization = fast_create(Organization)
  325 + GamificationPlugin::Badge.create!(:owner => organization, :name => 'comment_author')
  326 + GamificationPlugin.gamification_set_rules(environment)
  327 + article.profile = organization
  328 +
  329 + 5.times { create(Comment, :source => article, :author_id => person.id) }
  330 + process_delayed_job_queue
  331 + assert_equal 'comment_author', person.badges.first.name
  332 + end
279 333
280 end 334 end
test/unit/dashboard_helper_test.rb 0 → 100644
@@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
  1 +require_relative "../test_helper"
  2 +
  3 +class DashboardHelperTest < ActiveSupport::TestCase
  4 +
  5 + include GamificationPlugin::DashboardHelper
  6 +
  7 + should 'return title for global badges' do
  8 + owner = Environment.new
  9 + assert_equal 'Badges', badges_title(owner)
  10 + end
  11 +
  12 + should 'return title for organization badges' do
  13 + owner = Organization.new(:name => 'organization')
  14 + assert_equal 'Badges for organization', badges_title(owner)
  15 + end
  16 +
  17 + should 'return badges grouped by owner' do
  18 + environment = Environment.default
  19 + expects(:environment).at_least_once.returns(environment)
  20 + badge1 = GamificationPlugin::Badge.create!(:owner => fast_create(Organization))
  21 + badge2 = GamificationPlugin::Badge.create!(:owner => environment)
  22 + assert_equal [[badge2.owner, [badge2]], [badge1.owner, [badge1]]], grouped_badges
  23 + end
  24 +
  25 + should 'return category of a score point' do
  26 + point_type = GamificationPlugin::PointsType.create!(name: "point category", description: "point category")
  27 + score = Merit::Score.new
  28 + score.category = point_type.id.to_s
  29 + score.save!
  30 + point = score.score_points.create!
  31 + assert_equal "point category", score_point_category(point)
  32 + end
  33 +
  34 +end
test/unit/gamification_plugin_test.rb
1 -require_relative '../../../../test/test_helper' 1 +require_relative '../test_helper'
2 2
3 class GamificationPluginTest < ActiveSupport::TestCase 3 class GamificationPluginTest < ActiveSupport::TestCase
4 4
test/unit/merit_ext_test.rb 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +require_relative "../test_helper"
  2 +
  3 +class MeritExtTest < ActiveSupport::TestCase
  4 +
  5 + should 'check if the point was originated by an undo action' do
  6 + point = Merit::Score::Point.new
  7 + point_type = GamificationPlugin::PointsType.new(name: :comment_author)
  8 + point.expects(:point_type).returns(point_type)
  9 + action = mock
  10 + action.expects(:target_model).returns('comment')
  11 + action.expects(:action_method).returns('destroy')
  12 + point.expects(:action).at_least_once.returns(action)
  13 + assert point.undo_rule?
  14 + end
  15 +
  16 + should 'check if the point was originated by a do action' do
  17 + point = Merit::Score::Point.new
  18 + point_type = GamificationPlugin::PointsType.new(name: :comment_author)
  19 + point.expects(:point_type).returns(point_type)
  20 + action = mock
  21 + action.expects(:target_model).returns('comment')
  22 + action.expects(:action_method).returns('create')
  23 + point.expects(:action).at_least_once.returns(action)
  24 + assert !point.undo_rule?
  25 + end
  26 +
  27 +end
test/unit/person_test.rb
@@ -13,8 +13,10 @@ class PersonTest &lt; ActiveSupport::TestCase @@ -13,8 +13,10 @@ class PersonTest &lt; ActiveSupport::TestCase
13 GamificationPlugin.gamification_set_rules(environment) 13 GamificationPlugin.gamification_set_rules(environment)
14 14
15 4.times { Vote.create!(:voter => person, :voteable => fast_create(Comment), :vote => 1) } 15 4.times { Vote.create!(:voter => person, :voteable => fast_create(Comment), :vote => 1) }
  16 + process_delayed_job_queue
16 assert_equal [], person.badges 17 assert_equal [], person.badges
17 Vote.create!(:voter => person, :voteable => fast_create(Comment), :vote => 1) 18 Vote.create!(:voter => person, :voteable => fast_create(Comment), :vote => 1)
  19 + process_delayed_job_queue
18 assert_equal 'votes_performed', person.reload.badges.first.name 20 assert_equal 'votes_performed', person.reload.badges.first.name
19 end 21 end
20 22
@@ -23,6 +25,7 @@ class PersonTest &lt; ActiveSupport::TestCase @@ -23,6 +25,7 @@ class PersonTest &lt; ActiveSupport::TestCase
23 GamificationPlugin.gamification_set_rules(environment) 25 GamificationPlugin.gamification_set_rules(environment)
24 26
25 5.times { |i| person.add_friend(create_user("testuser#{i}").person) } 27 5.times { |i| person.add_friend(create_user("testuser#{i}").person) }
  28 + process_delayed_job_queue
26 assert_equal 'friendly', person.reload.badges.first.name 29 assert_equal 'friendly', person.reload.badges.first.name
27 end 30 end
28 31
@@ -30,6 +33,7 @@ class PersonTest &lt; ActiveSupport::TestCase @@ -30,6 +33,7 @@ class PersonTest &lt; ActiveSupport::TestCase
30 create_point_rule_definition('friends') 33 create_point_rule_definition('friends')
31 other_person = create_user("testuserfriend").person 34 other_person = create_user("testuserfriend").person
32 person.add_friend(other_person) 35 person.add_friend(other_person)
  36 + process_delayed_job_queue
33 c = GamificationPlugin::PointsCategorization.for_type(:friends).first 37 c = GamificationPlugin::PointsCategorization.for_type(:friends).first
34 assert_equal 5, person.score_points(:category => c.id.to_s).sum(:num_points) 38 assert_equal 5, person.score_points(:category => c.id.to_s).sum(:num_points)
35 end 39 end
test/unit/point_rules_test.rb
@@ -19,4 +19,23 @@ class PointRulesTest &lt; ActiveSupport::TestCase @@ -19,4 +19,23 @@ class PointRulesTest &lt; ActiveSupport::TestCase
19 assert point_rules.defined_rules.present? 19 assert point_rules.defined_rules.present?
20 end 20 end
21 21
  22 + should 'return target url for a point related to article creation' do
  23 + person = create_user('testuser').person
  24 + create_point_rule_definition('article_author')
  25 + article = create(TextArticle, :profile_id => person.id, :author => person)
  26 + process_delayed_job_queue
  27 + url = Merit::PointRules.target_url(person.score_points.last)
  28 + assert_equal article.url, url
  29 + end
  30 +
  31 + should 'return target url for a point related to comment creation' do
  32 + person = create_user('testuser').person
  33 + create_point_rule_definition('comment_author')
  34 + article = create(Article, :profile_id => person.id, :author => person)
  35 + comment = create(Comment, :source_id => article.id, :author => person)
  36 + process_delayed_job_queue
  37 + url = Merit::PointRules.target_url(person.score_points.last)
  38 + assert_equal comment.url, url
  39 + end
  40 +
22 end 41 end
test/unit/profile_test.rb
@@ -50,6 +50,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -50,6 +50,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
50 Person.any_instance.stubs(:is_profile_complete?).returns(true) 50 Person.any_instance.stubs(:is_profile_complete?).returns(true)
51 create_point_rule_definition('profile_completion', nil, {value: 0}) 51 create_point_rule_definition('profile_completion', nil, {value: 0})
52 GamificationPlugin.gamification_set_rules(environment) 52 GamificationPlugin.gamification_set_rules(environment)
  53 + process_delayed_job_queue
53 assert_equal 0, person.level 54 assert_equal 0, person.level
54 assert_nothing_raised do 55 assert_nothing_raised do
55 person.save 56 person.save
@@ -62,8 +63,10 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -62,8 +63,10 @@ class ProfileTest &lt; ActiveSupport::TestCase
62 GamificationPlugin.gamification_set_rules(environment) 63 GamificationPlugin.gamification_set_rules(environment)
63 64
64 person = create_user('testuser').person 65 person = create_user('testuser').person
  66 + process_delayed_job_queue
65 assert_equal 0, person.level 67 assert_equal 0, person.level
66 create(TextArticle, :profile_id => community.id, :author => person) 68 create(TextArticle, :profile_id => community.id, :author => person)
  69 + process_delayed_job_queue
67 assert_equal 3, person.reload.level 70 assert_equal 3, person.reload.level
68 end 71 end
69 72
views/gamification/_ranking.html.erb
1 -<% if ranking.empty? %> 1 +<% if ranking.blank? %>
2 <div class="ranking-empty"><%= _('Not enough points for this ranking yet') %></div> 2 <div class="ranking-empty"><%= _('Not enough points for this ranking yet') %></div>
3 <% else %> 3 <% else %>
4 <ul class="ranking <%= defined?(ranking_class) ? ranking_class : '' %>"> 4 <ul class="ranking <%= defined?(ranking_class) ? ranking_class : '' %>">
views/gamification/dashboard.html.erb
@@ -22,9 +22,9 @@ @@ -22,9 +22,9 @@
22 <div class="scores"> 22 <div class="scores">
23 <h3><%= _('Latest Score Points') %></h3> 23 <h3><%= _('Latest Score Points') %></h3>
24 <% @target.score_points.order('created_at desc').limit(5).each do |point| %> 24 <% @target.score_points.order('created_at desc').limit(5).each do |point| %>
25 - <div class="score <%= point.score.category %> <%= score_point_class(point) %>"> 25 + <div class="score <%= point.point_type.name %> <%= score_point_class(point) %> <%= score_point_action_class(point) %>">
26 <span class="value"><%= point.num_points %></span> 26 <span class="value"><%= point.num_points %></span>
27 - <span class="category"><%= _(score_point_category(point)) %></span> 27 + <span class="category"><%= score_point_target_link point, _(score_point_category(point)) %></span>
28 <span class="date timeago" title="<%= point.created_at %>"><%= point.created_at %></span> 28 <span class="date timeago" title="<%= point.created_at %>"><%= point.created_at %></span>
29 </div> 29 </div>
30 <% end %> 30 <% end %>
@@ -34,24 +34,26 @@ @@ -34,24 +34,26 @@
34 34
35 <% unless environment.gamification_plugin_badges.empty? %> 35 <% unless environment.gamification_plugin_badges.empty? %>
36 <div class="badges"> 36 <div class="badges">
37 - <h3><%= _('Badges') %></h3>  
38 - <ul class="badge-list">  
39 - <% environment.gamification_plugin_badges.group(:name).count.each do |badge_name, amount| %>  
40 - <% person_badge = @target.badges.where(:name => badge_name).last %>  
41 - <% badge = environment.gamification_plugin_badges.where(:name => badge_name).last %>  
42 - <li class="badge <%= badge.name %>">  
43 - <div class="badge" title="<%= badge.description %>">  
44 - <div class="image <%= badge.name %>"></div>  
45 - <ul class="level rating">  
46 - <% 1.upto(badge.level).map do |n|%>  
47 - <span class="star <%= (person_badge && person_badge.level >= n) ? 'earned' : 'not-earned' %>" >★</span>  
48 - <% end %>  
49 - </ul>  
50 - <div class="title"><%= badge.title %></div>  
51 - </div>  
52 - </li> 37 + <% grouped_badges.each do |owner, badges| %>
  38 + <h3><%= badges_title owner %></h3>
  39 + <ul class="badge-list">
  40 + <% badges.group_by(&:name).each do |badge_name, badges_group| %>
  41 + <% badge = badges_group.sort_by(&:level).last %>
  42 + <% person_badge = @target.badges.where(:name => badge.name).last %>
  43 + <li class="badge <%= badge.name %>">
  44 + <div class="badge" title="<%= badge.description %>">
  45 + <div class="image <%= badge.name %>"></div>
  46 + <ul class="level rating">
  47 + <% 1.upto(badge.level).map do |n|%>
  48 + <span class="star <%= (person_badge && person_badge.level >= n) ? 'earned' : 'not-earned' %>" >★</span>
  49 + <% end %>
  50 + </ul>
  51 + <div class="title"><%= badge.title %></div>
  52 + </div>
  53 + </li>
  54 + <% end %>
  55 + </ul>
53 <% end %> 56 <% end %>
54 - </ul>  
55 </div> 57 </div>
56 <% end %> 58 <% end %>
57 </div> 59 </div>
views/gamification_plugin_badges/_form.html.erb
@@ -29,24 +29,31 @@ @@ -29,24 +29,31 @@
29 <%= f.label :level %><br /> 29 <%= f.label :level %><br />
30 <%= f.text_field :level %> 30 <%= f.text_field :level %>
31 </div> 31 </div>
32 - <h4><%= _('Actions') %></h4>  
33 - <%= f.fields_for :custom_fields do |c| %>  
34 - <% rules.each do |name, settings| %>  
35 - <div class='controller-actions <%= "name_#{name}" %>'>  
36 - <% settings.each do |setting| %>  
37 - <%= c.label _(setting[:action]) %>  
38 - <%= c.fields_for setting[:action] do |d| %>  
39 - <% action = (@gamification_plugin_badge.custom_fields || {}).fetch(setting[:action], {}) %>  
40 - <div class="field">  
41 - <%= d.label :threshold %><br />  
42 - <%= d.text_field :threshold, {value: action.fetch('threshold', "")} %>  
43 - </div>  
44 - <br> 32 + <div class="field">
  33 + <%= f.label :profile_owner %><br />
  34 + <% tokenized_owner = @gamification_plugin_badge.owner.present? && @gamification_plugin_badge.owner.kind_of?(Organization) ? prepare_to_token_input([@gamification_plugin_badge.owner]) : nil %>
  35 + <%= token_input_field_tag('gamification_plugin_badge[owner_id]', 'badge-owner', {:action => 'search_owners'}, {:focus => false, :hint_text => _('Choose a profile or leave it blank for a global badge'), :token_limit => 1, :pre_populate => tokenized_owner}) %>
  36 + </div>
  37 + <div class="action-fields">
  38 + <h4><%= _('Actions') %></h4>
  39 + <%= f.fields_for :custom_fields do |c| %>
  40 + <% rules.each do |name, settings| %>
  41 + <div class='controller-actions <%= "name_#{name}" %>'>
  42 + <% settings.select {|s| s[:action].present?}.each do |setting| %>
  43 + <%= c.label _(setting[:action]) %>
  44 + <%= c.fields_for setting[:action] do |d| %>
  45 + <% action = (@gamification_plugin_badge.custom_fields || {}).fetch(setting[:action], {}) %>
  46 + <div class="field">
  47 + <%= d.label :threshold %><br />
  48 + <%= d.text_field :threshold, {value: action.fetch('threshold', "")} %>
  49 + </div>
  50 + <br>
  51 + <% end %>
45 <% end %> 52 <% end %>
46 - <% end %>  
47 - </div> 53 + </div>
  54 + <% end %>
48 <% end %> 55 <% end %>
49 - <% end %> 56 + </div>
50 <div class="actions"> 57 <div class="actions">
51 <%= f.submit %> 58 <%= f.submit %>
52 </div> 59 </div>
views/gamification_plugin_badges/index.html.erb
  1 +<%= stylesheet_link_tag 'plugins/gamification/admin.css' %>
  2 +
1 <h1><%= _('Gamification Settings: Listing Badges') %></h1> 3 <h1><%= _('Gamification Settings: Listing Badges') %></h1>
2 4
3 -<table> 5 +<table class="gamification-plugin-badges">
4 <tr> 6 <tr>
5 <th>Name</th> 7 <th>Name</th>
6 <th>Title</th> 8 <th>Title</th>
@@ -10,7 +12,11 @@ @@ -10,7 +12,11 @@
10 <th></th> 12 <th></th>
11 </tr> 13 </tr>
12 14
13 -<% @gamification_plugin_badges.each do |gamification_plugin_badge| %> 15 +<% @gamification_plugin_badges.each do |owner, badges| %>
  16 + <% if owner.present? %>
  17 + <tr><td class="badge-owner-group" colspan="6"><%= _("Badges for:") %> <%= owner.name %></td></tr>
  18 + <% end %>
  19 + <% badges.each do |gamification_plugin_badge| %>
14 <tr> 20 <tr>
15 <td><%= gamification_plugin_badge.name %></td> 21 <td><%= gamification_plugin_badge.name %></td>
16 <td><%= gamification_plugin_badge.title %></td> 22 <td><%= gamification_plugin_badge.title %></td>
@@ -19,6 +25,7 @@ @@ -19,6 +25,7 @@
19 <td><%= link_to 'Edit', :action => :edit, :id => gamification_plugin_badge.id %></td> 25 <td><%= link_to 'Edit', :action => :edit, :id => gamification_plugin_badge.id %></td>
20 <td><%= button_without_text :delete, _('Remove'), {:action => :destroy, :id => gamification_plugin_badge.id}, :method => :post, :confirm => _('Are you sure?') %></td> 26 <td><%= button_without_text :delete, _('Remove'), {:action => :destroy, :id => gamification_plugin_badge.id}, :method => :post, :confirm => _('Are you sure?') %></td>
21 </tr> 27 </tr>
  28 + <% end %>
22 <% end %> 29 <% end %>
23 </table> 30 </table>
24 31
views/gamification_plugin_badges/show.html.erb
@@ -22,6 +22,13 @@ @@ -22,6 +22,13 @@
22 <%= @gamification_plugin_badge.level %> 22 <%= @gamification_plugin_badge.level %>
23 </p> 23 </p>
24 24
  25 +<% if @gamification_plugin_badge.owner.kind_of?(Organization) %>
  26 +<p>
  27 + <b><%= _('Profile owner:') %></b>
  28 + <%= @gamification_plugin_badge.owner.name %>
  29 + </p>
  30 +<% end %>
  31 +
25 <p> 32 <p>
26 <b>Threshold:</b> 33 <b>Threshold:</b>
27 <% if @gamification_plugin_badge.custom_fields.is_a? Hash %> 34 <% if @gamification_plugin_badge.custom_fields.is_a? Hash %>