merit 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. data/Gemfile.lock +2 -2
  2. data/README.md +2 -3
  3. data/TESTING.txt +2 -5
  4. data/UPGRADING.md +32 -4
  5. data/app/models/merit/action.rb +0 -4
  6. data/app/models/merit/badge.rb +54 -0
  7. data/lib/generators/active_record/install_generator.rb +1 -0
  8. data/lib/generators/active_record/templates/create_merit_actions.rb +0 -1
  9. data/lib/generators/active_record/templates/create_merit_activity_logs.rb +15 -0
  10. data/lib/generators/merit/templates/merit.rb +1 -1
  11. data/lib/merit.rb +3 -2
  12. data/lib/merit/judge.rb +25 -10
  13. data/lib/merit/model_additions.rb +1 -1
  14. data/lib/merit/models/active_record/merit/action.rb +2 -0
  15. data/lib/merit/models/active_record/merit/activity_log.rb +10 -0
  16. data/lib/merit/models/active_record/merit/badges_sash.rb +20 -0
  17. data/lib/merit/models/active_record/merit/sash.rb +55 -0
  18. data/lib/merit/models/active_record/merit/score.rb +2 -1
  19. data/merit.gemspec +1 -1
  20. data/test/dummy/app/models/comment.rb +1 -0
  21. data/test/dummy/config/initializers/merit.rb +1 -1
  22. data/test/dummy/db/migrate/{20120318022217_create_merit_actions.rb → 20130329224406_create_merit_actions.rb} +1 -2
  23. data/test/dummy/db/migrate/20130329224407_create_merit_activity_logs.rb +15 -0
  24. data/test/dummy/db/migrate/{20120318022218_create_sashes.rb → 20130329224408_create_sashes.rb} +0 -0
  25. data/test/dummy/db/migrate/{20120318022219_create_badges_sashes.rb → 20130329224409_create_badges_sashes.rb} +0 -0
  26. data/test/dummy/db/migrate/{20121013174256_create_scores_and_points.rb → 20130329224410_create_scores_and_points.rb} +0 -0
  27. data/test/dummy/db/schema.rb +10 -3
  28. data/test/integration/navigation_test.rb +27 -14
  29. data/test/merit_unit_test.rb +15 -24
  30. data/test/sash_finder_test.rb +2 -2
  31. metadata +12 -9
  32. data/app/models/badge.rb +0 -52
  33. data/lib/merit/models/active_record/badges_sash.rb +0 -15
  34. data/lib/merit/models/active_record/sash.rb +0 -52
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- merit (1.4.0)
4
+ merit (1.5.0)
5
5
  ambry (~> 0.3.0)
6
6
 
7
7
  GEM
@@ -101,7 +101,7 @@ GEM
101
101
  rake (>= 0.8.7)
102
102
  rdoc (~> 3.4)
103
103
  thor (~> 0.14.6)
104
- rake (0.9.3.beta.1)
104
+ rake (10.0.4)
105
105
  rdoc (3.12)
106
106
  json (~> 1.4)
107
107
  rubyzip (0.9.8)
data/README.md CHANGED
@@ -167,8 +167,7 @@ end
167
167
 
168
168
  # To-do list
169
169
 
170
- * Should namespace Badge, BadgesSash and Sash into Merit module.
171
170
  * Move level from meritable model into Sash
172
- * Could have a Merit::Action - Activity - {BadgesSash|Merit::Score::Point}
173
- join model with datetimes to serve as "log"
171
+ * `ActivityLog` should replace `add_points` `log` parameter
172
+ * Extract logging from `Judge` to an Observer. See http://www.rubytapas.com/episodes/21-Domain-Model-Events
174
173
  * FIXMES and TODOS.
@@ -3,12 +3,9 @@ rake
3
3
 
4
4
  # Or spin up self contained testing Rails application
5
5
  cd test/dummy
6
- rails g merit:install # n's for not overriding already defined badges & rules
7
- n
8
- n
9
- n
10
- n
6
+ rails g merit:install
11
7
  rails g merit user
8
+ rails g merit comment
12
9
  rake db:migrate db:seed
13
10
 
14
11
  # see it in the browser
@@ -1,14 +1,42 @@
1
1
  # Upgrading
2
2
 
3
+ ## 1.5.0
4
+
5
+ * Adds `Merit::ActivityLog` join model between `Merit::Action` and
6
+ `Merit::BadgesSash` and `Merit::Score::Point` for logging purposes. Every
7
+ time a badge is granted or removed, or points are changed, a new
8
+ `ActivityLog` object gets created.
9
+ * Namespaces `Badge`, `Sash` and `BadgesSash` into `Merit` module. If your app
10
+ uses any of those class names, you should add a `Merit::` prefix.
11
+ * Removes undocumented `log:string` column from `merit_actions`.
12
+
13
+ Run the following migration to upgrade from 1.4.0:
14
+
15
+ ```ruby
16
+ class UpgradeMeritTo150 < ActiveRecord::Migration
17
+ def self.up
18
+ remove_column :merit_actions, :log
19
+ create_table "merit_activity_logs", :force => true do |t|
20
+ t.integer "action_id"
21
+ t.string "related_change_type"
22
+ t.integer "related_change_id"
23
+ t.string "description"
24
+ t.datetime "created_at"
25
+ end
26
+ end
27
+ end
28
+ ```
29
+
3
30
  ## 1.4.0
4
31
 
5
32
  * Removed `BadgesSash#set_notified!` undocumented method from code base.
6
33
  * `:to` option for points and badges granting may now return an array of
7
34
  objects. For instance:
8
- ```ruby
9
- # All user's comments earn points
10
- score 2, to: :user_comments, on: 'comments#vote'
11
- ```
35
+
36
+ ```ruby
37
+ # All user's comments earn points
38
+ score 2, to: :user_comments, on: 'comments#vote'
39
+ ```
12
40
 
13
41
  ## to 1.3.0
14
42
 
@@ -29,10 +29,6 @@ module Merit
29
29
  check_rules point_rules, :points
30
30
  end
31
31
 
32
- def log_activity(str)
33
- self.update_attribute :log, "#{self.log}#{str}|"[0,240]
34
- end
35
-
36
32
  private
37
33
 
38
34
  def check_rules(rules_array, badges_or_points)
@@ -0,0 +1,54 @@
1
+ module Merit
2
+ require 'ambry'
3
+ require 'ambry/active_model'
4
+
5
+ class Badge
6
+ extend Ambry::Model
7
+ extend Ambry::ActiveModel
8
+
9
+ field :id, :name, :level, :image, :description
10
+
11
+ validates_presence_of :id, :name
12
+ validates_uniqueness_of :id
13
+
14
+ filters do
15
+ def find_by_id(ids)
16
+ ids = Array.wrap(ids)
17
+ find{|b| ids.include? b[:id] }
18
+ end
19
+ def by_name(name)
20
+ find{|b| b.name == name.to_s }
21
+ end
22
+ def by_level(level)
23
+ find{|b| b.level.to_s == level.to_s }
24
+ end
25
+ end
26
+
27
+ class << self
28
+ def find_by_name_and_level(name, level)
29
+ badges = Badge.by_name(name)
30
+ badges = badges.by_level(level) unless level.nil?
31
+ if !(badge = badges.first)
32
+ raise ::Merit::BadgeNotFound, "No badge '#{name}'#{level.nil? ? '' : " with level #{level}"} found. Define it in 'config/initializers/merit.rb'."
33
+ end
34
+ badge
35
+ end
36
+
37
+ # Last badges granted
38
+ def last_granted(options = {})
39
+ options[:since_date] ||= 1.month.ago
40
+ options[:limit] ||= 10
41
+ BadgesSash.last_granted(options)
42
+ end
43
+
44
+ # Defines Badge#meritable_models method, to get related
45
+ # entries with certain badge. For instance, Badge.find(3).users
46
+ def _define_related_entries_method(meritable_class_name)
47
+ define_method(:"#{meritable_class_name.underscore.pluralize}") do
48
+ sashes = BadgesSash.where(badge_id: self.id).pluck(:sash_id)
49
+ meritable_class_name.constantize.where(sash_id: sashes)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -14,6 +14,7 @@ module ActiveRecord
14
14
 
15
15
  def copy_migrations_and_model
16
16
  migration_template 'create_merit_actions.rb', 'db/migrate/create_merit_actions.rb'
17
+ migration_template 'create_merit_activity_logs.rb', 'db/migrate/create_merit_activity_logs.rb'
17
18
  migration_template 'create_sashes.rb', 'db/migrate/create_sashes.rb'
18
19
  migration_template 'create_badges_sashes.rb', 'db/migrate/create_badges_sashes.rb'
19
20
  migration_template 'create_scores_and_points.rb', 'db/migrate/create_scores_and_points.rb'
@@ -8,7 +8,6 @@ class CreateMeritActions < ActiveRecord::Migration
8
8
  t.string :target_model
9
9
  t.integer :target_id
10
10
  t.boolean :processed, :default => false
11
- t.string :log, :default => nil
12
11
  t.timestamps
13
12
  end
14
13
  end
@@ -0,0 +1,15 @@
1
+ class CreateMeritActivityLogs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :merit_activity_logs do |t|
4
+ t.integer :action_id
5
+ t.string :related_change_type
6
+ t.integer :related_change_id
7
+ t.string :description
8
+ t.datetime :created_at
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :merit_activity_logs
14
+ end
15
+ end
@@ -14,7 +14,7 @@ Merit.setup do |config|
14
14
  end
15
15
 
16
16
  # Create application badges (uses https://github.com/norman/ambry)
17
- # Badge.create!({
17
+ # Merit::Badge.create!({
18
18
  # :id => 1,
19
19
  # :name => 'just-registered'
20
20
  # })
@@ -45,8 +45,9 @@ module Merit
45
45
 
46
46
  initializer 'merit.controller' do |app|
47
47
  if Merit.orm == :active_record
48
- require 'merit/models/active_record/sash'
49
- require 'merit/models/active_record/badges_sash'
48
+ require 'merit/models/active_record/merit/activity_log'
49
+ require 'merit/models/active_record/merit/badges_sash'
50
+ require 'merit/models/active_record/merit/sash'
50
51
  require 'merit/models/active_record/merit/score'
51
52
  elsif Merit.orm == :mongoid
52
53
  require "merit/models/mongoid/sash"
@@ -12,7 +12,7 @@ module Merit
12
12
  # then remove it.
13
13
  def apply_badges
14
14
  if rule_applies?
15
- grant_badges if new_or_multiple?
15
+ grant_badges
16
16
  else
17
17
  remove_badges if @rule.temporary
18
18
  end
@@ -21,26 +21,41 @@ module Merit
21
21
  def apply_points
22
22
  return unless rule_applies?
23
23
  @sashes.each do |sash|
24
- sash.add_points @rule.score, @action.inspect[0..240]
24
+ points = sash.add_points @rule.score
25
+ ActivityLog.create(
26
+ action_id: @action.id,
27
+ related_change: points
28
+ )
25
29
  end
26
- @action.log_activity "points_granted:#{@rule.score}"
27
30
  end
28
31
 
29
32
  private
30
33
 
31
34
  def grant_badges
32
- @sashes.each { |sash| sash.add_badge badge.id }
33
- to_action_user = (@rule.to.to_sym == :action_user ? '_to_action_user' : '')
34
- @action.log_activity "badge_granted#{to_action_user}:#{badge.id}"
35
+ @sashes.each do |sash|
36
+ next unless new_or_multiple?(sash)
37
+ badge_sash = sash.add_badge badge.id
38
+ ActivityLog.create(
39
+ action_id: @action.id,
40
+ related_change: badge_sash,
41
+ description: 'granted'
42
+ )
43
+ end
35
44
  end
36
45
 
37
46
  def remove_badges
38
- @sashes.each { |sash| sash.rm_badge badge.id }
39
- @action.log_activity "badge_removed:#{badge.id}"
47
+ @sashes.each do |sash|
48
+ badge_sash = sash.rm_badge badge.id
49
+ ActivityLog.create(
50
+ action_id: @action.id,
51
+ related_change: badge_sash,
52
+ description: 'removed'
53
+ )
54
+ end
40
55
  end
41
56
 
42
- def new_or_multiple?
43
- !@sashes.map(&:badge_ids).include?(badge.id) || @rule.multiple
57
+ def new_or_multiple?(sash)
58
+ !sash.badge_ids.include?(badge.id) || @rule.multiple
44
59
  end
45
60
 
46
61
  def rule_applies?
@@ -7,7 +7,7 @@ module Merit
7
7
  # That's why MeritableModel belongs_to Sash. Can't use
8
8
  # :dependent => destroy as it may raise FK constraint exceptions. See:
9
9
  # https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1079-belongs_to-dependent-destroy-should-destroy-self-before-assocation
10
- belongs_to :sash
10
+ belongs_to :sash, class_name: 'Merit::Sash'
11
11
 
12
12
  _merit_orm_specific_config
13
13
  _merit_delegate_methods_to_sash
@@ -2,6 +2,8 @@ module Merit
2
2
  class Action < ActiveRecord::Base
3
3
  self.table_name = :merit_actions
4
4
 
5
+ has_many :activity_logs, class_name: Merit::ActivityLog
6
+
5
7
  attr_accessible :user_id, :action_method, :action_value, :had_errors,
6
8
  :target_model, :target_id, :processed, :log
7
9
  end
@@ -0,0 +1,10 @@
1
+ module Merit
2
+ class ActivityLog < ActiveRecord::Base
3
+ self.table_name = :merit_activity_logs
4
+
5
+ belongs_to :action, class_name: Merit::Action
6
+ belongs_to :related_change, polymorphic: true
7
+
8
+ attr_accessible :action_id, :related_change, :description, :created_at
9
+ end
10
+ end
@@ -0,0 +1,20 @@
1
+ module Merit
2
+ class BadgesSash < ActiveRecord::Base
3
+ belongs_to :sash
4
+ has_many :activity_logs, class_name: Merit::ActivityLog, as: :related_change
5
+
6
+ attr_accessible :badge_id
7
+
8
+ def self.last_granted(options = {})
9
+ options[:since_date] ||= 1.month.ago
10
+ options[:limit] ||= 10
11
+ where("created_at > '#{options[:since_date]}'").
12
+ limit(options[:limit]).
13
+ map(&:badge)
14
+ end
15
+
16
+ def badge
17
+ Badge.find(badge_id)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,55 @@
1
+ module Merit
2
+ # Sash is a container for reputation data for meritable models. It's an
3
+ # indirection between meritable models and badges and scores (one to one
4
+ # relationship).
5
+ #
6
+ # It's existence make join models like badges_users and scores_users
7
+ # unnecessary. It should be transparent at the application.
8
+ class Sash < ActiveRecord::Base
9
+ has_many :badges_sashes, :dependent => :destroy
10
+ has_many :scores, :dependent => :destroy, :class_name => 'Merit::Score'
11
+
12
+ after_create :create_scores
13
+
14
+ def badges
15
+ badge_ids.collect { |b_id| Badge.find(b_id) }
16
+ end
17
+
18
+ def badge_ids
19
+ badges_sashes.map(&:badge_id)
20
+ end
21
+
22
+ def add_badge(badge_id)
23
+ bs = BadgesSash.new(badge_id: badge_id)
24
+ self.badges_sashes << bs
25
+ bs
26
+ end
27
+
28
+ def rm_badge(badge_id)
29
+ badges_sashes.find_by_badge_id(badge_id).try(:destroy)
30
+ end
31
+
32
+
33
+ def points(category = 'default')
34
+ scores.where(:category => category).first.points
35
+ end
36
+
37
+ def add_points(num_points, log = 'Manually granted through `add_points`', category = 'default')
38
+ point = Merit::Score::Point.new
39
+ point.log = log
40
+ point.num_points = num_points
41
+ self.scores.where(:category => category).first.score_points << point
42
+ point
43
+ end
44
+
45
+ def substract_points(num_points, log = 'Manually granted through `add_points`', category = 'default')
46
+ add_points -num_points, log, category
47
+ end
48
+
49
+ private
50
+
51
+ def create_scores
52
+ self.scores << Merit::Score.create
53
+ end
54
+ end
55
+ end
@@ -2,7 +2,7 @@ module Merit
2
2
  class Score < ActiveRecord::Base
3
3
  self.table_name = :merit_scores
4
4
  belongs_to :sash
5
- has_many :score_points, :dependent => :destroy, :class_name => 'Merit::Score::Point'
5
+ has_many :score_points, :dependent => :destroy, class_name: 'Merit::Score::Point'
6
6
 
7
7
  # Meant to display a leaderboard. Accepts options :table_name (users by
8
8
  # default), :since_date (1.month.ago by default) and :limit (10 by
@@ -44,6 +44,7 @@ SQL
44
44
 
45
45
  class Point < ActiveRecord::Base
46
46
  belongs_to :score, :class_name => 'Merit::Score'
47
+ has_many :activity_logs, class_name: Merit::ActivityLog, as: :related_change
47
48
  end
48
49
  end
49
50
  end
@@ -4,7 +4,7 @@ Gem::Specification.new do |s|
4
4
  s.description = "Manage badges, points and rankings (reputation) of resources in a Rails application."
5
5
  s.homepage = "http://github.com/tute/merit"
6
6
  s.files = `git ls-files`.split("\n").reject{|f| f =~ /^\./ }
7
- s.version = '1.4.0'
7
+ s.version = '1.5.0'
8
8
  s.authors = ["Tute Costa"]
9
9
  s.email = 'tutecosta@gmail.com'
10
10
 
@@ -1,5 +1,6 @@
1
1
  class Comment < ActiveRecord::Base
2
2
  has_merit
3
+
3
4
  belongs_to :user
4
5
 
5
6
  attr_accessible :name, :comment, :user_id, :votes
@@ -41,5 +41,5 @@ badge_id = 0
41
41
  :id => (badge_id = badge_id+1),
42
42
  :name => 'gossip'
43
43
  }].each do |badge|
44
- Badge.create! badge
44
+ Merit::Badge.create! badge
45
45
  end
@@ -4,11 +4,10 @@ class CreateMeritActions < ActiveRecord::Migration
4
4
  t.integer :user_id # source
5
5
  t.string :action_method
6
6
  t.integer :action_value
7
- t.boolean :had_errors
7
+ t.boolean :had_errors, :default => false
8
8
  t.string :target_model
9
9
  t.integer :target_id
10
10
  t.boolean :processed, :default => false
11
- t.string :log, :default => nil
12
11
  t.timestamps
13
12
  end
14
13
  end
@@ -0,0 +1,15 @@
1
+ class CreateMeritActivityLogs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :merit_activity_logs do |t|
4
+ t.integer :action_id
5
+ t.string :related_change_type
6
+ t.integer :related_change_id
7
+ t.string :description
8
+ t.datetime :created_at
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :merit_activity_logs
14
+ end
15
+ end
@@ -11,7 +11,7 @@
11
11
  #
12
12
  # It's strongly recommended to check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(:version => 20130321082817) do
14
+ ActiveRecord::Schema.define(:version => 20130329222238) do
15
15
 
16
16
  create_table "badges_sashes", :force => true do |t|
17
17
  t.integer "badge_id"
@@ -39,15 +39,22 @@ ActiveRecord::Schema.define(:version => 20130321082817) do
39
39
  t.integer "user_id"
40
40
  t.string "action_method"
41
41
  t.integer "action_value"
42
- t.boolean "had_errors"
42
+ t.boolean "had_errors", :default => false
43
43
  t.string "target_model"
44
44
  t.integer "target_id"
45
45
  t.boolean "processed", :default => false
46
- t.string "log"
47
46
  t.datetime "created_at", :null => false
48
47
  t.datetime "updated_at", :null => false
49
48
  end
50
49
 
50
+ create_table "merit_activity_logs", :force => true do |t|
51
+ t.integer "action_id"
52
+ t.string "related_change_type"
53
+ t.integer "related_change_id"
54
+ t.string "description"
55
+ t.datetime "created_at"
56
+ end
57
+
51
58
  create_table "merit_score_points", :force => true do |t|
52
59
  t.integer "score_id"
53
60
  t.integer "num_points", :default => 0
@@ -4,17 +4,19 @@ class NavigationTest < ActiveSupport::IntegrationCase
4
4
  test 'user sign up should grant badge to itself' do
5
5
  visit '/users/new'
6
6
  fill_in 'Name', :with => 'Jack'
7
- click_button('Create User')
7
+ assert_difference('Merit::ActivityLog.count') do
8
+ click_button('Create User')
9
+ end
8
10
 
9
11
  user = User.where(:name => 'Jack').first
10
- assert_equal [Badge.by_name('just-registered').first], user.badges
12
+ assert_equal [Merit::Badge.by_name('just-registered').first], user.badges
11
13
  end
12
14
 
13
15
  test 'User#add_badge should add one badge, #rm_badge should delete one' do
14
16
  user = User.create(:name => 'test-user')
15
17
  assert_equal [], user.badges
16
18
 
17
- badge = Badge.first
19
+ badge = Merit::Badge.first
18
20
  user.add_badge badge.id
19
21
  user.add_badge badge.id
20
22
  assert_equal [badge, badge], user.badges
@@ -36,13 +38,13 @@ class NavigationTest < ActiveSupport::IntegrationCase
36
38
  visit '/users'
37
39
  visit '/users'
38
40
  visit '/users'
39
- gossip = Badge.by_name('gossip').first
41
+ gossip = Merit::Badge.by_name('gossip').first
40
42
  assert_equal 3, User.first.badges.count
41
43
  assert_equal [gossip, gossip, gossip], User.first.badges
42
44
 
43
45
  # Testing with namespaced controllers
44
46
  visit '/admin/users'
45
- visited_admin = Badge.by_name('visited_admin').first
47
+ visited_admin = Merit::Badge.by_name('visited_admin').first
46
48
  assert_equal 4, User.first.badges.count
47
49
  assert User.first.badges.include?(visited_admin)
48
50
  end
@@ -76,10 +78,12 @@ class NavigationTest < ActiveSupport::IntegrationCase
76
78
  fill_in 'Name', :with => 'Hi!'
77
79
  fill_in 'Comment', :with => 'Hi bro!'
78
80
  fill_in 'User', :with => user.id
79
- click_button('Create Comment')
81
+ assert_difference('Merit::ActivityLog.count', 2) do
82
+ click_button('Create Comment')
83
+ end
80
84
 
81
- assert_equal [Badge.by_name('commenter').by_level(10).first], user.reload.badges
82
- assert_equal [Badge.by_name('has_commenter_friend').first], friend.reload.badges
85
+ assert_equal [Merit::Badge.by_name('commenter').by_level(10).first], user.reload.badges
86
+ assert_equal [Merit::Badge.by_name('has_commenter_friend').first], friend.reload.badges
83
87
 
84
88
  # Vote (to 5) a user's comment, assert relevant-commenter badge granted
85
89
  relevant_comment = user.comments.where(:votes => 8).first
@@ -88,7 +92,7 @@ class NavigationTest < ActiveSupport::IntegrationCase
88
92
  click_link '2'
89
93
  end
90
94
 
91
- relevant_badge = Badge.by_name('relevant-commenter').first
95
+ relevant_badge = Merit::Badge.by_name('relevant-commenter').first
92
96
  user_badges = User.where(:name => 'test-user').first.badges
93
97
  assert user_badges.include?(relevant_badge), "User badges: #{user.badges.collect(&:name).inspect} should contain relevant-commenter badge."
94
98
 
@@ -102,14 +106,18 @@ class NavigationTest < ActiveSupport::IntegrationCase
102
106
  click_button('Update User')
103
107
 
104
108
  user = User.where(:name => 'long_name!').first
105
- autobiographer_badge = Badge.by_name('autobiographer').first
109
+ autobiographer_badge = Merit::Badge.by_name('autobiographer').first
106
110
  assert user.badges.include?(autobiographer_badge), "User badges: #{user.badges.collect(&:name).inspect} should contain autobiographer badge."
107
111
 
108
112
  # Edit user's name by short name
109
113
  # tests ruby code in grant_on is being executed, and removes badge
110
114
  visit "/users/#{user.id}/edit"
111
115
  fill_in 'Name', :with => 'abc'
112
- click_button('Update User')
116
+ assert_difference('Merit::ActivityLog.count', 2) do
117
+ click_button('Update User')
118
+ end
119
+ # Last one is point granting, previous one is badge removing
120
+ assert_equal 'removed', Merit::ActivityLog.all[-2].description
113
121
 
114
122
  user = User.where(:name => 'abc').first
115
123
  assert !user.badges.include?(autobiographer_badge), "User badges: #{user.badges.collect(&:name).inspect} should remove autobiographer badge."
@@ -122,7 +130,9 @@ class NavigationTest < ActiveSupport::IntegrationCase
122
130
 
123
131
  visit "/users/#{user.id}/edit"
124
132
  fill_in 'Name', :with => 'a'
125
- click_button('Update User')
133
+ assert_difference('Merit::ActivityLog.count', 2) do
134
+ click_button('Update User')
135
+ end
126
136
 
127
137
  user = User.where(:name => 'a').first
128
138
  assert_equal 20, user.points, 'Updating info should grant 20 points'
@@ -198,8 +208,11 @@ class NavigationTest < ActiveSupport::IntegrationCase
198
208
  comment_2 = commenter.comments.create(:name => 'comment_2', :comment => 'b')
199
209
 
200
210
  visit comments_path
201
- within "tr#c_#{comment_2.id}" do
202
- click_link '1'
211
+ # Thanks for voting point, to voted user and it's comments
212
+ assert_difference('Merit::ActivityLog.count', 4) do
213
+ within "tr#c_#{comment_2.id}" do
214
+ click_link '1'
215
+ end
203
216
  end
204
217
 
205
218
  comment_1.reload.points.must_be :==, 2
@@ -21,18 +21,9 @@ class MeritUnitTest < ActiveSupport::TestCase
21
21
  rule.badge_name = 'inexistent'
22
22
  assert_raise(Merit::BadgeNotFound) { rule.badge }
23
23
 
24
- badge = Badge.create(id: 98, name: 'test-badge-98')
24
+ badge = Merit::Badge.create(id: 98, name: 'test-badge-98')
25
25
  rule.badge_name = badge.name
26
- assert_equal Badge.find(98), rule.badge
27
- end
28
-
29
- test "Merit::Action#log_activity doesn't grow larger than 240 chars" do
30
- msg = 'a' * 250
31
- m = Merit::Action.create
32
- m.log_activity(msg)
33
-
34
- valid_lengths = msg.length > 240 && m.log.length <= 240
35
- assert valid_lengths, 'Log shouldn\'t grow larger than 240 chars'
26
+ assert_equal Merit::Badge.find(98), rule.badge
36
27
  end
37
28
 
38
29
  test "extends only meritable ActiveRecord models" do
@@ -57,33 +48,33 @@ class MeritUnitTest < ActiveSupport::TestCase
57
48
  def self.columns; @columns ||= []; end
58
49
  has_merit
59
50
  end
60
- assert Badge.method_defined?(:soldiers), 'Badge#soldiers should be defined'
61
- assert Badge.method_defined?(:players), 'Badge#players should be defined'
51
+ assert Merit::Badge.method_defined?(:soldiers), 'Badge#soldiers should be defined'
52
+ assert Merit::Badge.method_defined?(:players), 'Badge#players should be defined'
62
53
  end
63
54
 
64
55
  test "Badge#last_granted returns recently granted badges" do
65
56
  # Create sashes, badges and badges_sashes
66
- sash = Sash.create
67
- badge = Badge.create(id: 20, name: 'test-badge-21')
57
+ sash = Merit::Sash.create
58
+ badge = Merit::Badge.create(id: 20, name: 'test-badge-21')
68
59
  sash.add_badge badge.id
69
- BadgesSash.last.update_attribute :created_at, 1.day.ago
60
+ Merit::BadgesSash.last.update_attribute :created_at, 1.day.ago
70
61
  sash.add_badge badge.id
71
- BadgesSash.last.update_attribute :created_at, 8.days.ago
62
+ Merit::BadgesSash.last.update_attribute :created_at, 8.days.ago
72
63
  sash.add_badge badge.id
73
- BadgesSash.last.update_attribute :created_at, 15.days.ago
64
+ Merit::BadgesSash.last.update_attribute :created_at, 15.days.ago
74
65
 
75
66
  # Test method options
76
- assert_equal Badge.last_granted(since_date: Time.now), []
77
- assert_equal Badge.last_granted(since_date: 1.week.ago), [badge]
78
- assert_equal Badge.last_granted(since_date: 2.weeks.ago).count, 2
79
- assert_equal Badge.last_granted(since_date: 2.weeks.ago, limit: 1), [badge]
67
+ assert_equal Merit::Badge.last_granted(since_date: Time.now), []
68
+ assert_equal Merit::Badge.last_granted(since_date: 1.week.ago), [badge]
69
+ assert_equal Merit::Badge.last_granted(since_date: 2.weeks.ago).count, 2
70
+ assert_equal Merit::Badge.last_granted(since_date: 2.weeks.ago, limit: 1), [badge]
80
71
  end
81
72
 
82
73
  test "Merit::Score.top_scored returns scores leaderboard" do
83
74
  # Create sashes and add points
84
- sash_1 = Sash.create
75
+ sash_1 = Merit::Sash.create
85
76
  sash_1.add_points(10); sash_1.add_points(10)
86
- sash_2 = Sash.create
77
+ sash_2 = Merit::Sash.create
87
78
  sash_2.add_points(5); sash_2.add_points(5)
88
79
 
89
80
  # Test method options
@@ -3,11 +3,11 @@ require 'test_helper'
3
3
  describe Merit::SashFinder do
4
4
 
5
5
  it 'should return an array of sashes of the target objects' do
6
- sash_1 = Sash.new
6
+ sash_1 = Merit::Sash.new
7
7
  user_1 = User.new(:_sash => sash_1)
8
8
  user_1.stubs(:_sash).returns(sash_1)
9
9
 
10
- sash_2 = Sash.new
10
+ sash_2 = Merit::Sash.new
11
11
  user_2 = User.new
12
12
  user_2.stubs(:_sash).returns(sash_2)
13
13
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: merit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-26 00:00:00.000000000 Z
12
+ date: 2013-03-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ambry
@@ -201,13 +201,14 @@ files:
201
201
  - Rakefile
202
202
  - TESTING.txt
203
203
  - UPGRADING.md
204
- - app/models/badge.rb
205
204
  - app/models/merit/action.rb
205
+ - app/models/merit/badge.rb
206
206
  - lib/generators/active_record/install_generator.rb
207
207
  - lib/generators/active_record/merit_generator.rb
208
208
  - lib/generators/active_record/templates/add_fields_to_model.rb
209
209
  - lib/generators/active_record/templates/create_badges_sashes.rb
210
210
  - lib/generators/active_record/templates/create_merit_actions.rb
211
+ - lib/generators/active_record/templates/create_merit_activity_logs.rb
211
212
  - lib/generators/active_record/templates/create_sashes.rb
212
213
  - lib/generators/active_record/templates/create_scores_and_points.rb
213
214
  - lib/generators/merit/install_generator.rb
@@ -221,10 +222,11 @@ files:
221
222
  - lib/merit/controller_extensions.rb
222
223
  - lib/merit/judge.rb
223
224
  - lib/merit/model_additions.rb
224
- - lib/merit/models/active_record/badges_sash.rb
225
225
  - lib/merit/models/active_record/merit/action.rb
226
+ - lib/merit/models/active_record/merit/activity_log.rb
227
+ - lib/merit/models/active_record/merit/badges_sash.rb
228
+ - lib/merit/models/active_record/merit/sash.rb
226
229
  - lib/merit/models/active_record/merit/score.rb
227
- - lib/merit/models/active_record/sash.rb
228
230
  - lib/merit/models/mongo_mapper/merit/action.rb
229
231
  - lib/merit/models/mongo_mapper/sash.rb
230
232
  - lib/merit/models/mongoid/merit/action.rb
@@ -331,12 +333,13 @@ files:
331
333
  - test/dummy/config/routes.rb
332
334
  - test/dummy/db/migrate/20110421191249_create_users.rb
333
335
  - test/dummy/db/migrate/20110421191250_create_comments.rb
334
- - test/dummy/db/migrate/20120318022217_create_merit_actions.rb
335
- - test/dummy/db/migrate/20120318022218_create_sashes.rb
336
- - test/dummy/db/migrate/20120318022219_create_badges_sashes.rb
337
336
  - test/dummy/db/migrate/20120318022220_add_fields_to_users.rb
338
- - test/dummy/db/migrate/20121013174256_create_scores_and_points.rb
339
337
  - test/dummy/db/migrate/20130321082817_add_fields_to_comments.rb
338
+ - test/dummy/db/migrate/20130329224406_create_merit_actions.rb
339
+ - test/dummy/db/migrate/20130329224407_create_merit_activity_logs.rb
340
+ - test/dummy/db/migrate/20130329224408_create_sashes.rb
341
+ - test/dummy/db/migrate/20130329224409_create_badges_sashes.rb
342
+ - test/dummy/db/migrate/20130329224410_create_scores_and_points.rb
340
343
  - test/dummy/db/schema.rb
341
344
  - test/dummy/db/seeds.rb
342
345
  - test/dummy/public/404.html
@@ -1,52 +0,0 @@
1
- require 'ambry'
2
- require 'ambry/active_model'
3
-
4
- class Badge
5
- extend Ambry::Model
6
- extend Ambry::ActiveModel
7
-
8
- field :id, :name, :level, :image, :description
9
-
10
- validates_presence_of :id, :name
11
- validates_uniqueness_of :id
12
-
13
- filters do
14
- def find_by_id(ids)
15
- ids = Array.wrap(ids)
16
- find{|b| ids.include? b[:id] }
17
- end
18
- def by_name(name)
19
- find{|b| b.name == name.to_s }
20
- end
21
- def by_level(level)
22
- find{|b| b.level.to_s == level.to_s }
23
- end
24
- end
25
-
26
- class << self
27
- def find_by_name_and_level(name, level)
28
- badges = Badge.by_name(name)
29
- badges = badges.by_level(level) unless level.nil?
30
- if !(badge = badges.first)
31
- raise ::Merit::BadgeNotFound, "No badge '#{name}'#{level.nil? ? '' : " with level #{level}"} found. Define it in 'config/initializers/merit.rb'."
32
- end
33
- badge
34
- end
35
-
36
- # Last badges granted
37
- def last_granted(options = {})
38
- options[:since_date] ||= 1.month.ago
39
- options[:limit] ||= 10
40
- BadgesSash.last_granted(options)
41
- end
42
-
43
- # Defines Badge#meritable_models method, to get related
44
- # entries with certain badge. For instance, Badge.find(3).users
45
- def _define_related_entries_method(meritable_class_name)
46
- define_method(:"#{meritable_class_name.underscore.pluralize}") do
47
- sashes = BadgesSash.where(badge_id: self.id).pluck(:sash_id)
48
- meritable_class_name.constantize.where(sash_id: sashes)
49
- end
50
- end
51
- end
52
- end
@@ -1,15 +0,0 @@
1
- class BadgesSash < ActiveRecord::Base
2
- belongs_to :sash
3
-
4
- def self.last_granted(options = {})
5
- options[:since_date] ||= 1.month.ago
6
- options[:limit] ||= 10
7
- where("created_at > '#{options[:since_date]}'").
8
- limit(options[:limit]).
9
- map(&:badge)
10
- end
11
-
12
- def badge
13
- Badge.find(badge_id)
14
- end
15
- end
@@ -1,52 +0,0 @@
1
- # Sash is a container for reputation data for meritable models. It's an
2
- # indirection between meritable models and badges and scores (one to one
3
- # relationship).
4
- #
5
- # It's existence make join models like badges_users and scores_users
6
- # unnecessary. It should be transparent at the application.
7
- class Sash < ActiveRecord::Base
8
- has_many :badges_sashes, :dependent => :destroy
9
- has_many :scores, :dependent => :destroy, :class_name => 'Merit::Score'
10
-
11
- after_create :create_scores
12
-
13
- def badges
14
- badge_ids.collect { |b_id| Badge.find(b_id) }
15
- end
16
-
17
- def badge_ids
18
- badges_sashes.map(&:badge_id)
19
- end
20
-
21
- def add_badge(badge_id)
22
- bs = BadgesSash.new
23
- bs.badge_id = badge_id
24
- self.badges_sashes << bs
25
- end
26
-
27
- def rm_badge(badge_id)
28
- badges_sashes.find_by_badge_id(badge_id).try(:destroy)
29
- end
30
-
31
-
32
- def points(category = 'default')
33
- scores.where(:category => category).first.points
34
- end
35
-
36
- def add_points(num_points, log = 'Manually granted through `add_points`', category = 'default')
37
- point = Merit::Score::Point.new
38
- point.log = log
39
- point.num_points = num_points
40
- self.scores.where(:category => category).first.score_points << point
41
- end
42
-
43
- def substract_points(num_points, log = 'Manually granted through `add_points`', category = 'default')
44
- add_points -num_points, log, category
45
- end
46
-
47
- private
48
-
49
- def create_scores
50
- self.scores << Merit::Score.create
51
- end
52
- end