Commit 5bf066b67fef435bd941844f06edf5020a8420c4

Authored by Hugo Melo
2 parents 77c756f9 f0f12c2a

Merge branch 'gamification_test_updated' into gamification_tests1

Conflicts:
	lib/ext/person.rb
	lib/merit/point_rules.rb
db/migrate/20151003000212_move_badge_threshold_to_action_key.rb 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +class MoveBadgeThresholdToActionKey < ActiveRecord::Migration
  2 + def up
  3 + change_table :gamification_plugin_badges do |t|
  4 + t.change :custom_fields, :text
  5 + end
  6 + GamificationPlugin::Badge.all.each do |badge|
  7 + next if Merit::BadgeRules::AVAILABLE_RULES[badge.name.to_sym].nil?
  8 + Merit::BadgeRules::AVAILABLE_RULES[badge.name.to_sym].each do |setting|
  9 + badge.custom_fields = {} unless badge.custom_fields.is_a? Hash
  10 + badge.custom_fields[setting[:action]] = {threshold: badge.custom_fields[:threshold]} unless badge.custom_fields[:threshold].nil?
  11 + badge.save
  12 + end
  13 + end
  14 + end
  15 +
  16 + def down
  17 + GamificationPlugin::Badge.all.each do |badge|
  18 + next if Merit::BadgeRules::AVAILABLE_RULES[badge.name.to_sym].nil?
  19 + setting = Merit::BadgeRules::AVAILABLE_RULES[badge.name.to_sym].first
  20 + badge.custom_fields = {threshold: badge.custom_fields.fetch(setting[:action], {}).fetch(:threshold, "")}
  21 + badge.save
  22 + end
  23 + change_table :gamification_plugin_badges do |t|
  24 + t.change :custom_fields, :string
  25 + end
  26 + end
  27 +end
... ...
lib/ext/article_follower.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +require_dependency 'article_follower'
  2 +
  3 +class ArticleFollower
  4 +
  5 + has_merit_actions
  6 +
  7 +end
... ...
lib/ext/person.rb
... ... @@ -5,12 +5,21 @@ class Person
5 5 # TODO why this relationship doesn't exists in core?
6 6 has_many :comments, :foreign_key => 'author_id'
7 7  
  8 + after_save { |obj| obj.new_merit_action(:update, {}) }
  9 +
8 10 def profile_completion_score_condition
9   - self.points(category: 'profile_completion') == 0 and self.is_profile_complete?
  11 + categories = []
  12 + GamificationPlugin::PointsCategorization.for_type('profile_completion').each {|i| categories << i.id.to_s}
  13 + self.points(category: categories) == 0 and self.is_profile_complete?
10 14 end
  15 +
11 16 def is_profile_complete?
12   - # FIXME: FIND OUT A WAY TO CHECK EVERY REGISTRY FIELD
13   - false
  17 + !(self.name.blank? or
  18 + (self.data[:identidade_genero].blank? and self.data[:transgenero].blank?) or
  19 + self.data[:etnia].blank? or
  20 + self.data[:orientacao_sexual].blank? or
  21 + self.data[:state].blank? or
  22 + self.data[:city].blank?)
14 23 end
15 24  
16 25 def points_by_type type
... ...
lib/gamification_plugin.rb
... ... @@ -50,7 +50,7 @@ class GamificationPlugin &lt; Noosfero::Plugin
50 50 end
51 51  
52 52 def js_files
53   - ['jquery.noty.packaged.min.js', 'jquery.easypiechart.min.js', 'main.js']
  53 + ['jquery.noty.packaged.min.js', 'jquery.easypiechart.min.js', 'main.js', 'admin.js']
54 54 end
55 55  
56 56  
... ...
lib/gamification_plugin/api.rb
... ... @@ -11,6 +11,7 @@ class GamificationPlugin::API &lt; Grape::API
11 11 authenticate!
12 12 present current_person.badges, :with => Noosfero::API::Entities::Badge
13 13 end
  14 +
14 15 get 'points' do
15 16 authenticate!
16 17 {points: current_person.points}
... ...
lib/merit/badge_rules.rb
... ... @@ -9,58 +9,160 @@ module Merit
9 9 include Merit::BadgeRulesMethods
10 10  
11 11 AVAILABLE_RULES = {
12   - :comment_author => {
13   - :action => 'comment#create',
14   - :default_threshold => 5,
15   - :to => :author,
16   - :value => lambda { |comment| comment.author.present? ? comment.author.comments.count : 0 }
17   - },
18   - :comment_received => {
19   - :action => 'comment#create',
20   - :default_threshold => 5,
21   - :to => lambda {|comment| comment.source.author},
22   - :value => lambda { |comment| comment.source.author.present? ? Comment.where(:source_id => Article.where(:author_id => comment.source.author.id)).count : 0 }
23   - },
24   - :article_author => {
25   - :action => 'article#create',
26   - :default_threshold => 5,
27   - :to => :author,
28   - :value => lambda { |article| article.author.present? ? article.environment.articles.text_articles.where(:author_id => article.author.id).count : 0 }
29   - },
30   - :positive_votes_received => {
31   - :action => 'vote#create',
32   - :default_threshold => 5,
33   - :to => lambda {|vote| vote.voteable.author},
34   - :value => lambda { |vote| Vote.for_voteable(vote.voteable).where('vote > 0').count }
35   - },
36   - :negative_votes_received => {
37   - :action => 'vote#create',
38   - :default_threshold => 5,
39   - :to => lambda {|vote| vote.voteable.author},
40   - :value => lambda { |vote| Vote.for_voteable(vote.voteable).where('vote < 0').count }
41   - },
42   - :votes_performed => {
43   - :action => 'vote#create',
44   - :default_threshold => 5,
45   - :to => lambda {|vote| vote.voter},
46   - :value => lambda { |vote| Vote.for_voter(vote.voter).count }
47   - },
48   - :friendly => {
49   - :action => 'friendship#create',
50   - :default_threshold => 5,
51   - :to => lambda {|friendship| friendship.person},
52   - :value => lambda { |friendship| friendship.person.friends.count }
53   - }
  12 + comment_author: [
  13 + {
  14 + action: 'comment#create',
  15 + default_threshold: 5,
  16 + to: :author,
  17 + value: lambda { |comment, author| author.present? ? author.comments.count : 0 }
  18 + }
  19 + ],
  20 + comment_received: [
  21 + {
  22 + action: 'comment#create',
  23 + default_threshold: 5,
  24 + to: lambda {|comment| comment.source.author},
  25 + value: lambda { |comment, author| author.present? ? Comment.where(source_id: Article.where(author_id: author.id)).count : 0 }
  26 + }
  27 + ],
  28 + article_author: [
  29 + {
  30 + action: 'article#create',
  31 + default_threshold: 5,
  32 + to: :author,
  33 + value: lambda { |article, author| author.present? ? TextArticle.where(author_id: author.id).count : 0 }
  34 + },
  35 + ],
  36 + positive_votes_received: [
  37 + {
  38 + action: 'vote#create',
  39 + default_threshold: 5,
  40 + to: lambda {|vote| vote.voteable.author},
  41 + value: lambda { |vote, author| Vote.for_voteable(vote.voteable).where('vote > 0').count }
  42 + }
  43 + ],
  44 + negative_votes_received: [
  45 + {
  46 + action: 'vote#create',
  47 + default_threshold: 5,
  48 + to: lambda {|vote| vote.voteable.author},
  49 + value: lambda { |vote, author| Vote.for_voteable(vote.voteable).where('vote < 0').count }
  50 + }
  51 + ],
  52 + votes_performed: [
  53 + {
  54 + action: 'vote#create',
  55 + default_threshold: 5,
  56 + to: lambda {|vote| vote.voter},
  57 + value: lambda { |vote, voter| Vote.for_voter(voter).count }
  58 + }
  59 + ],
  60 + friendly: [
  61 + {
  62 + action: 'friendship#create',
  63 + default_threshold: 5,
  64 + to: lambda {|friendship| friendship.person},
  65 + value: lambda { |friendship, person| person.friends.count }
  66 + }
  67 + ],
  68 + creative: [
  69 + {
  70 + action: 'comment#create',
  71 + default_threshold: 5,
  72 + to: :author,
  73 + value: lambda { |comment, author| author.present? ? author.comments.count : 0 }
  74 + },
  75 + {
  76 + action: 'article#create',
  77 + default_threshold: 5,
  78 + to: :author,
  79 + value: lambda { |article, author| author.present? ? author.articles.count : 0 }
  80 + },
  81 + ],
  82 + observer: [
  83 + {
  84 + action: 'articlefollower#create',
  85 + default_threshold: 5,
  86 + to: lambda {|article| article.person },
  87 + model: 'ArticleFollower',
  88 + value: lambda { |article, person| person.present? ? person.article_followers.count : 0 }
  89 + }
  90 + ],
  91 + mobilizer: [
  92 + {
  93 + action: 'Vote#create',
  94 + default_threshold: 5,
  95 + to: lambda { |vote| vote.voter },
  96 + value: lambda { |vote, voter| Vote.for_voter(voter).count }
  97 + },
  98 + {
  99 + action: 'Event#create',
  100 + default_threshold: 5,
  101 + to: lambda { |article| article.author },
  102 + value: lambda { |event, author| author.events.count }
  103 + },
  104 + ],
  105 + generous: [
  106 + {
  107 + action: 'vote#create',
  108 + default_threshold: 5,
  109 + to: lambda {|vote| vote.voter},
  110 + value: lambda { |vote, voter| voter.votes.where('vote > 0').count }
  111 + },
  112 + {
  113 + action: 'comment#create',
  114 + default_threshold: 5,
  115 + to: :author,
  116 + value: lambda { |comment, author| author.present? ? author.comments.count : 0 }
  117 + }
  118 + ],
  119 + articulator: [
  120 + {
  121 + action: 'articlefollower#create',
  122 + default_threshold: 5,
  123 + to: :person,
  124 + model: 'ArticleFollower',
  125 + value: lambda { |article_follower, person| person.present? ? person.article_followers.count : 0 }
  126 + },
  127 + {
  128 + action: 'comment#create',
  129 + default_threshold: 5,
  130 + to: :author,
  131 + value: lambda { |comment, author| author.present? ? author.comments.count : 0 }
  132 + },
  133 + ]
54 134 }
55 135  
56 136 def initialize(environment=nil)
57 137 return if environment.nil?
58 138 @environment = environment
59 139  
  140 + rules = AVAILABLE_RULES
  141 + rules.merge! CONFERENCE_RULES if defined? CONFERENCE_RULES
  142 +
60 143 environment.gamification_plugin_badges.all.each do |badge|
61   - setting = AVAILABLE_RULES[badge.name.to_sym]
62   - grant_on setting[:action], :badge => badge.name, :level => badge.level, :to => setting[:to] do |source|
63   - setting[:value].call(source) >= (badge.custom_fields || {}).fetch(:threshold, setting[:default_threshold]).to_i
  144 + next if rules[badge.name.to_sym].nil?
  145 + rules[badge.name.to_sym].each do |setting|
  146 + options = {badge: badge.name, level: badge.level, to: setting[:to]}
  147 + options[:model_name] = setting[:model] unless setting[:model].nil?
  148 + grant_on setting[:action], options do |source|
  149 + can_be_granted = true
  150 + rules[badge.name.to_sym].each do |s|
  151 + if setting[:to].is_a? Symbol
  152 + to = source.send(setting[:to])
  153 + else
  154 + begin
  155 + to = setting[:to].call(source)
  156 + rescue
  157 + to = nil
  158 + end
  159 + end
  160 + # pass source and to for different situations
  161 + action = (badge.custom_fields || {}).fetch(s[:action], {})
  162 + can_be_granted &= s[:value].call(source, to) >= action.fetch(:threshold, s[:default_threshold]).to_i
  163 + end
  164 + can_be_granted
  165 + end
64 166 end
65 167 end
66 168 end
... ...
lib/merit/point_rules.rb
... ... @@ -10,7 +10,7 @@ module Merit
10 10 value: 1,
11 11 description: _('Comment author'),
12 12 default_weight: 40,
13   - condition: lambda {|comment, profile| comment.source.profile == profile},
  13 + condition: lambda {|comment, profile| profile.nil? or comment.source.profile == profile},
14 14 },
15 15 comment_article_author: {
16 16 action: 'comment#create',
... ... @@ -19,7 +19,7 @@ module Merit
19 19 value: 1,
20 20 description: _('Article author of a comment'),
21 21 default_weight: 50,
22   - condition: lambda {|comment, profile| comment.source.profile == profile},
  22 + condition: lambda {|comment, profile| profile.nil? or comment.source.profile == profile},
23 23 },
24 24 comment_article: {
25 25 action: 'comment#create',
... ... @@ -28,7 +28,7 @@ module Merit
28 28 value: 1,
29 29 description: _('Source article of a comment'),
30 30 default_weight: 50,
31   - condition: lambda {|comment, profile| comment.source.profile == profile},
  31 + condition: lambda {|comment, profile| profile.nil? or comment.source.profile == profile},
32 32 },
33 33 comment_community: {
34 34 action: 'comment#create',
... ... @@ -37,7 +37,7 @@ module Merit
37 37 value: 1,
38 38 description: _('Article community of a comment'),
39 39 default_weight: 50,
40   - condition: lambda {|comment, profile| comment.profile.community? and comment.profile == profile }
  40 + condition: lambda {|comment, profile| profile.nil? or (comment.profile.community? and comment.profile == profile) }
41 41 },
42 42 article_author: {
43 43 action: 'article#create',
... ... @@ -45,8 +45,8 @@ module Merit
45 45 to: :author,
46 46 value: 1,
47 47 description: _('Article author'),
48   - default_weight: 10,
49   - condition: lambda {|article, profile| article.profile == profile},
  48 + default_weight: 50,
  49 + condition: lambda {|article, profile| profile.nil? or article.profile == profile},
50 50 },
51 51 article_community: {
52 52 action: 'article#create',
... ... @@ -55,7 +55,7 @@ module Merit
55 55 value: 1,
56 56 description: _('Article community'),
57 57 default_weight: 10,
58   - condition: lambda {|article, profile| article.profile.present? and article.profile.community? and article.profile == profile }
  58 + condition: lambda {|article, profile| profile.nil? or (article.profile.present? and article.profile.community? and article.profile == profile) }
59 59 },
60 60 vote_voteable_author: {
61 61 action: 'vote#create',
... ... @@ -65,7 +65,7 @@ module Merit
65 65 value: lambda {|vote| vote.vote},
66 66 description: _('Author of a voted content'),
67 67 default_weight: 20,
68   - condition: lambda {|vote, profile| vote.voteable.profile == profile }
  68 + condition: lambda {|vote, profile| profile.nil? or vote.voteable.profile == profile }
69 69 },
70 70 vote_voteable: {
71 71 action: 'vote#create',
... ... @@ -75,7 +75,7 @@ module Merit
75 75 value: lambda {|vote| vote.vote},
76 76 description: _('Voted content'),
77 77 default_weight: 30,
78   - condition: lambda {|vote, profile| vote.voteable.profile == profile }
  78 + condition: lambda {|vote, profile| profile.nil? or vote.voteable.profile == profile }
79 79 },
80 80 vote_voter: {
81 81 action: 'vote#create',
... ... @@ -84,7 +84,7 @@ module Merit
84 84 value: lambda {|vote| 1},
85 85 description: _('Voter'),
86 86 default_weight: 10,
87   - condition: lambda {|vote, profile| vote.voteable.profile == profile }
  87 + condition: lambda {|vote, profile| profile.nil? or vote.voteable.profile == profile }
88 88 },
89 89 friends: {
90 90 action: 'friendship#create',
... ... @@ -96,34 +96,36 @@ module Merit
96 96 profile_action: false
97 97 },
98 98 profile_completion: {
99   - action: ['account#create', 'account#update'],
100   - undo_action: 'account#destroy',
101   - to: lambda {|user| user.person},
  99 + action: ['profile#create', 'profile#update'],
  100 + undo_action: 'profile#destroy',
  101 + to: :itself,
102 102 value: 1,
103 103 description: _('Profile Completion'),
104 104 default_weight: 100,
105 105 model_name: "User",
106   - condition: lambda {|user| user.person.profile_completion_score_condition },
  106 + condition: lambda {|person| person.person? and person.profile_completion_score_condition },
107 107 profile_action: false
108 108 },
109 109 follower: {
110   - action: 'follow#create',
111   - undo_action: 'follow#destroy',
112   - to: lambda {|follow| follow.profile },
  110 + action: 'articlefollower#create',
  111 + undo_action: 'articlefollower#destroy',
  112 + to: :person,
113 113 value: 1,
114 114 description: _('Follower'),
115 115 default_weight: 10,
116   - condition: lambda {|follow, profile| follow.source.profile == profile },
  116 + model: 'ArticleFollower',
  117 + condition: lambda {|follow, profile| profile.nil? or follow.article.profile == profile },
117 118 profile_action: true
118 119 },
119 120 followed_article_author: {
120   - action: 'follow#create',
121   - undo_action: 'follow#destroy',
122   - to: lambda {|follow| follow.source.author },
  121 + action: 'articlefollower#create',
  122 + undo_action: 'articlefollower#destroy',
  123 + to: lambda {|follow| follow.article.author },
123 124 value: 1,
124 125 description: _('Followed'),
125 126 default_weight: 20,
126   - condition: lambda {|follow, profile| follow.source.profile == profile },
  127 + model: 'ArticleFollower',
  128 + condition: lambda {|follow, profile| profile.nil? or follow.article.profile == profile },
127 129 profile_action: true
128 130 },
129 131 #mobilizer: {
... ... @@ -133,7 +135,7 @@ module Merit
133 135 #value: 1,
134 136 #description: _('Mobilized Article Author'),
135 137 #default_weight: 60,
136   - #condition: lambda {|target, profile| target.source.profile == profile },
  138 + #condition: lambda {|target, profile| profile.nil? or target.source.profile == profile },
137 139 #profile_action: true
138 140 #},
139 141 #mobilized_article_author: {
... ... @@ -143,7 +145,7 @@ module Merit
143 145 #value: 1,
144 146 #description: _('Mobilized Article Author'),
145 147 #default_weight: 70,
146   - #condition: lambda {|follow, profile| follow.source.profile == profile },
  148 + #condition: lambda {|follow, profile| profile.nil? or follow.source.profile == profile },
147 149 #profile_action: true
148 150 #},
149 151 #mobilized_article: {
... ... @@ -153,7 +155,7 @@ module Merit
153 155 #value: 1,
154 156 #description: _('Mobilized Article Author'),
155 157 #default_weight: 70,
156   - #condition: lambda {|follow, profile| follow.source.profile == profile },
  158 + #condition: lambda {|follow, profile| profile.nil? or follow.source.profile == profile },
157 159 #profile_action: true
158 160 #}
159 161 }
... ... @@ -183,7 +185,9 @@ module Merit
183 185 AVAILABLE_RULES.each do |point_type, setting|
184 186 GamificationPlugin::PointsCategorization.for_type(point_type).includes(:profile).each do |categorization|
185 187 [setting[:action], setting[:undo_action]].compact.zip([1, -1]).each do |action, signal|
186   - score lambda {|target| signal * calculate_score(target, categorization.weight, setting[:value])}, on: action, to: setting[:to], category: categorization.id.to_s do |target|
  188 + options = {on: action, to: setting[:to], category: categorization.id.to_s}
  189 + options[:model_name] = setting[:model] unless setting[:model].nil?
  190 + score lambda {|target| signal * calculate_score(target, categorization.weight, setting[:value])}, options do |target|
187 191 condition(setting, target, categorization.profile)
188 192 end
189 193 end
... ...
po/gamification.pot
... ... @@ -119,7 +119,7 @@ msgid &quot;All Time&quot;
119 119 msgstr ""
120 120  
121 121 #: plugins/gamification/views/gamification/notification_badge.html.erb:2
122   -msgid "You earn a new badge!"
  122 +msgid "You earned a new badge!"
123 123 msgstr ""
124 124  
125 125 #: plugins/gamification/views/gamification/notification_badge.html.erb:6
... ...
po/pt/gamification.po
... ... @@ -7,7 +7,7 @@ msgid &quot;&quot;
7 7 msgstr ""
8 8 "Project-Id-Version: 1.1-3172-g3455bd0\n"
9 9 "POT-Creation-Date: 2015-08-17 16:21-0300\n"
10   -"PO-Revision-Date: 2015-06-05 08:42-0300\n"
  10 +"PO-Revision-Date: 2015-10-08 21:35-0300\n"
11 11 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12 12 "Language-Team: LANGUAGE <LL@li.org>\n"
13 13 "Language: \n"
... ... @@ -119,7 +119,7 @@ msgid &quot;All Time&quot;
119 119 msgstr "Todo o Período"
120 120  
121 121 #: plugins/gamification/views/gamification/notification_badge.html.erb:2
122   -msgid "You earn a new badge!"
  122 +msgid "You earned a new badge!"
123 123 msgstr "Você ganhou um troféu!"
124 124  
125 125 #: plugins/gamification/views/gamification/notification_badge.html.erb:6
... ...
public/admin.js
... ... @@ -4,5 +4,20 @@ var gamificationPluginAdmin = {
4 4 var template = $('.gamification-plugin-rank-rules .template-level > div').clone();
5 5 template.find('.level-value').text($('.gamification-plugin-rank-rules .rank-rules .items .level').length + 1);
6 6 $('.gamification-plugin-rank-rules .rank-rules .items').append(template);
  7 + },
  8 +
  9 + selectCustomFieldsOnNameChange: function() {
  10 + jQuery('.controller-actions').find('input').attr('disabled', 'disabled');
  11 + jQuery('.controller-actions').hide();
  12 + console.log('.name_'+jQuery('#gamification-plugin-form-badge-name').val());
  13 + var name = jQuery('#gamification-plugin-form-badge-name').find('option:selected').text();
  14 + jQuery('.name_'+name).show();
  15 + jQuery('.name_'+name).find('input').removeAttr('disabled');
7 16 }
  17 +
8 18 }
  19 +
  20 +jQuery(function() {
  21 + $('#gamification-plugin-form-badge-name').on('change', gamificationPluginAdmin.selectCustomFieldsOnNameChange);
  22 + gamificationPluginAdmin.selectCustomFieldsOnNameChange();
  23 +});
... ...
test/unit/api_test.rb
... ... @@ -7,6 +7,8 @@ class APITest &lt; ActiveSupport::TestCase
7 7 login_api
8 8 environment = Environment.default
9 9 environment.enable_plugin(GamificationPlugin)
  10 + @community = create_merit_categorization
  11 + GamificationPlugin.gamification_set_rules(@environment)
10 12 end
11 13  
12 14 should 'get my own badges' do
... ... @@ -14,7 +16,7 @@ class APITest &lt; ActiveSupport::TestCase
14 16 person.add_badge(badge.id)
15 17 get "/api/v1/gamification_plugin/my/badges?#{params.to_query}"
16 18 json = JSON.parse(last_response.body)
17   - assert_equal 'test_badge', json.first['name']
  19 + assert_equal 'test_badge', json['badges'].first['name']
18 20 end
19 21  
20 22 should 'get my level' do
... ... @@ -71,7 +73,7 @@ class APITest &lt; ActiveSupport::TestCase
71 73 another_person.visible=false
72 74 another_person.save
73 75 get "/api/v1/gamification_plugin/people/#{another_person.id}/level?#{params.to_query}"
74   - json = JSON.parse(last_response.body)
  76 + JSON.parse(last_response.body)
75 77 assert_equal 404, last_response.status
76 78 end
77 79  
... ...
test/unit/comment_test.rb
... ... @@ -78,7 +78,7 @@ class CommentTest &lt; ActiveSupport::TestCase
78 78 comment = create(Comment, :source => article, :author_id => author.id)
79 79 Vote.create!(:voter => person, :voteable => comment, :vote => 1)
80 80  
81   - assert_difference 'comment.author.points', -50 do
  81 + assert_difference 'comment.author.points', -20 do
82 82 Vote.where(:voteable_id => comment.id).destroy_all
83 83 end
84 84 end
... ... @@ -96,7 +96,7 @@ class CommentTest &lt; ActiveSupport::TestCase
96 96 comment = create(Comment, :source => article, :author_id => author.id)
97 97 Vote.create!(:voter => person, :voteable => comment, :vote => -1)
98 98  
99   - assert_difference 'comment.author.points', 50 do
  99 + assert_difference 'comment.author.points', 20 do
100 100 Vote.where(:voteable_id => comment.id).destroy_all
101 101 end
102 102 end
... ...
views/gamification/notification_badge.html.erb
1 1 <div class="gamification-notification">
2   - <h2 class="message"><%= _('You earn a new badge!') %></h2>
  2 + <h2 class="message"><%= _('You earned a new badge!') %></h2>
3 3 <div class="badge">
4 4 <div class="image <%= badge.name %>"></div>
5 5 <div class="description"><%= badge.description %></div>
... ...
views/gamification_plugin_badges/_form.html.erb
... ... @@ -11,9 +11,11 @@
11 11 </div>
12 12 <% end %>
13 13  
14   - <div class="field">
  14 + <% rules = Merit::BadgeRules::AVAILABLE_RULES %>
  15 + <% rules.merge! Merit::BadgeRules::CONFERENCE_RULES if defined? Merit::BadgeRules::CONFERENCE_RULES %>
  16 + <div class="field" id="gamification-plugin-form-badge-name">
15 17 <%= f.label :name %><br />
16   - <%= f.select :name, Merit::BadgeRules::AVAILABLE_RULES.map{ |key, rule| key } %>
  18 + <%= f.select :name, rules.map{ |key, rule| key } %>
17 19 </div>
18 20 <div class="field">
19 21 <%= f.label :title %><br />
... ... @@ -27,11 +29,22 @@
27 29 <%= f.label :level %><br />
28 30 <%= f.text_field :level %>
29 31 </div>
  32 + <h4><%= _('Actions') %></h4>
30 33 <%= f.fields_for :custom_fields do |c| %>
31   - <div class="field">
32   - <%= c.label :threshold %><br />
33   - <%= c.text_field :threshold %>
34   - </div>
  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 + <% end %>
  45 + <% end %>
  46 + </div>
  47 + <% end %>
35 48 <% end %>
36 49 <div class="actions">
37 50 <%= f.submit %>
... ...