merit 0.2.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/Gemfile +2 -0
  2. data/Gemfile.lock +103 -0
  3. data/README.markdown +17 -2
  4. data/app/models/badge.rb +27 -19
  5. data/app/models/merit_action.rb +5 -3
  6. data/app/models/sash.rb +5 -14
  7. data/lib/generators/active_record/merit_generator.rb +14 -14
  8. data/lib/generators/{merit → active_record}/templates/create_badges_sashes.rb +0 -0
  9. data/lib/generators/{merit → active_record}/templates/create_merit_actions.rb +0 -0
  10. data/lib/generators/{merit → active_record}/templates/create_sashes.rb +0 -0
  11. data/lib/generators/merit/install_generator.rb +3 -20
  12. data/lib/generators/merit/merit_generator.rb +12 -0
  13. data/lib/generators/merit/templates/merit.rb +10 -1
  14. data/lib/merit.rb +11 -2
  15. data/lib/merit/controller_extensions.rb +2 -2
  16. data/lib/merit/model_additions.rb +18 -17
  17. data/lib/merit/models/active_record/badges_sash.rb +12 -0
  18. data/lib/merit/models/active_record/merit_action.rb +2 -0
  19. data/lib/merit/models/active_record/sash.rb +12 -0
  20. data/lib/merit/models/mongo_mapper/merit_action.rb +12 -0
  21. data/lib/merit/models/mongo_mapper/sash.rb +15 -0
  22. data/lib/merit/rule.rb +2 -2
  23. data/lib/merit/rules_badge.rb +1 -1
  24. data/merit.gemspec +16 -0
  25. data/test/dummy/Rakefile +7 -0
  26. data/test/dummy/app/controllers/application_controller.rb +7 -0
  27. data/test/dummy/app/controllers/comments_controller.rb +90 -0
  28. data/test/dummy/app/controllers/registrations_controller.rb +15 -0
  29. data/test/dummy/app/controllers/users_controller.rb +67 -0
  30. data/test/dummy/app/helpers/application_helper.rb +2 -0
  31. data/test/dummy/app/models/comment.rb +4 -0
  32. data/test/dummy/app/models/merit_badge_rules.rb +41 -0
  33. data/test/dummy/app/models/merit_point_rules.rb +18 -0
  34. data/test/dummy/app/models/merit_rank_rules.rb +25 -0
  35. data/test/dummy/app/models/user.rb +9 -0
  36. data/test/dummy/app/views/comments/_form.html.erb +29 -0
  37. data/test/dummy/app/views/comments/edit.html.erb +6 -0
  38. data/test/dummy/app/views/comments/index.html.erb +35 -0
  39. data/test/dummy/app/views/comments/new.html.erb +5 -0
  40. data/test/dummy/app/views/comments/show.html.erb +23 -0
  41. data/test/dummy/app/views/layouts/application.html.haml +18 -0
  42. data/test/dummy/app/views/users/_form.html.erb +22 -0
  43. data/test/dummy/app/views/users/edit.html.erb +6 -0
  44. data/test/dummy/app/views/users/index.html.erb +26 -0
  45. data/test/dummy/app/views/users/new.html.erb +5 -0
  46. data/test/dummy/app/views/users/show.html.erb +18 -0
  47. data/test/dummy/config.ru +4 -0
  48. data/test/dummy/config/application.rb +24 -0
  49. data/test/dummy/config/boot.rb +10 -0
  50. data/test/dummy/config/database.yml +22 -0
  51. data/test/dummy/config/environment.rb +5 -0
  52. data/test/dummy/config/environments/development.rb +26 -0
  53. data/test/dummy/config/environments/production.rb +49 -0
  54. data/test/dummy/config/environments/test.rb +35 -0
  55. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  56. data/test/dummy/config/initializers/badges_data.rb +40 -0
  57. data/test/dummy/config/initializers/inflections.rb +10 -0
  58. data/test/dummy/config/initializers/mime_types.rb +5 -0
  59. data/test/dummy/config/initializers/secret_token.rb +7 -0
  60. data/test/dummy/config/initializers/session_store.rb +8 -0
  61. data/test/dummy/config/locales/en.yml +5 -0
  62. data/test/dummy/config/routes.rb +9 -0
  63. data/test/dummy/db/migrate/20110421191249_create_users.rb +12 -0
  64. data/test/dummy/db/migrate/20110421191250_create_comments.rb +16 -0
  65. data/test/dummy/db/schema.rb +61 -0
  66. data/test/dummy/db/seeds.rb +17 -0
  67. data/test/dummy/public/404.html +26 -0
  68. data/test/dummy/public/422.html +26 -0
  69. data/test/dummy/public/500.html +26 -0
  70. data/test/dummy/public/favicon.ico +0 -0
  71. data/test/dummy/public/javascripts/application.js +2 -0
  72. data/test/dummy/public/javascripts/controls.js +965 -0
  73. data/test/dummy/public/javascripts/dragdrop.js +974 -0
  74. data/test/dummy/public/javascripts/effects.js +1123 -0
  75. data/test/dummy/public/javascripts/prototype.js +6001 -0
  76. data/test/dummy/public/javascripts/rails.js +191 -0
  77. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  78. data/test/dummy/public/stylesheets/scaffold.css +56 -0
  79. data/test/dummy/script/rails +6 -0
  80. data/test/integration/navigation_test.rb +132 -0
  81. data/test/merit_unit_test.rb +22 -0
  82. data/test/support/integration_case.rb +5 -0
  83. data/test/test_helper.rb +22 -0
  84. metadata +132 -13
  85. data/app/models/badges_sash.rb +0 -14
  86. data/lib/generators/merit/templates/create_badges.rb +0 -19
@@ -0,0 +1,12 @@
1
+ class BadgesSash < ActiveRecord::Base
2
+ belongs_to :badge
3
+ belongs_to :sash
4
+
5
+ # To be used in the application, mark badge granting as notified to user
6
+ def set_notified!(badge, sash)
7
+ # With composite keys ARel complained, had to use SQL
8
+ ActiveRecord::Base.connection.execute("UPDATE badges_sashes
9
+ SET notified_user = TRUE
10
+ WHERE badge_id = #{badge.id} AND sash_id = #{sash.id}")
11
+ end
12
+ end
@@ -0,0 +1,2 @@
1
+ class MeritAction < ActiveRecord::Base
2
+ end
@@ -0,0 +1,12 @@
1
+ class Sash < ActiveRecord::Base
2
+ has_many :badges_sashes
3
+ has_many :badges, :through => :badges_sashes
4
+
5
+ def add_badge(badge_id)
6
+ BadgesSash.create(sash: self, badge_id: badge_id)
7
+ end
8
+ def rm_badge(badge_id)
9
+ ActiveRecord::Base.connection.execute("DELETE FROM badges_sashes
10
+ WHERE badge_id = #{badge_id} AND sash_id = #{self.id}")
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ class MeritAction
2
+ include MongoMapper::Document
3
+
4
+ key :user_id, String
5
+ key :action_method, String
6
+ key :action_value, Integer
7
+ key :had_errors, Boolean
8
+ key :target_model, String
9
+ key :target_id, String
10
+ key :processed, Boolean, :default => false
11
+ timestamps!
12
+ end
@@ -0,0 +1,15 @@
1
+ class Sash
2
+ include MongoMapper::Document
3
+
4
+ key :badge_ids, Array
5
+ timestamps!
6
+
7
+ def add_badge(badge_id)
8
+ self.badge_ids << badge_id
9
+ self.save
10
+ end
11
+ def rm_badge(badge_id)
12
+ self.badge_ids -= [badge_id]
13
+ self.save
14
+ end
15
+ end
@@ -72,8 +72,8 @@ module Merit
72
72
  # Get rule's related Badge.
73
73
  def badge
74
74
  if @badge.nil?
75
- badges = Badge.where(:name => badge_name)
76
- badges = badges.where(:level => level.to_s) unless level.nil?
75
+ badges = Badge.by_name(badge_name)
76
+ badges = badges.by_level(level) unless level.nil?
77
77
  @badge = badges.first
78
78
  end
79
79
  @badge
@@ -54,7 +54,7 @@ module Merit
54
54
  # Check non processed actions and grant badges if applies
55
55
  def check_new_actions
56
56
  MeritAction.where(:processed => false).each do |merit_action|
57
- merit_action.check_badge_rules(defined_rules)
57
+ merit_action.check_rules(defined_rules)
58
58
  end
59
59
  end
60
60
 
@@ -0,0 +1,16 @@
1
+ # Provide a simple gemspec so you can easily use your enginex
2
+ # project in your rails apps through git.
3
+ Gem::Specification.new do |s|
4
+ s.name = "merit"
5
+ s.summary = "General reputation Rails engine."
6
+ s.description = "General reputation Rails engine."
7
+ s.files = `git ls-files`.split("\n").reject{|f| f =~ /^\./ }
8
+ s.version = "0.3.0"
9
+ s.authors = ["Tute Costa"]
10
+ s.email = 'tutecosta@gmail.com'
11
+ s.add_dependency 'ambry'
12
+ s.add_development_dependency 'rails'
13
+ s.add_development_dependency 'sqlite3'
14
+ s.add_development_dependency 'haml'
15
+ s.add_development_dependency 'capybara'
16
+ end
@@ -0,0 +1,7 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+ require 'rake'
6
+
7
+ Dummy::Application.load_tasks
@@ -0,0 +1,7 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery
3
+
4
+ def current_user
5
+ @current_user ||= User.first
6
+ end
7
+ end
@@ -0,0 +1,90 @@
1
+ class CommentsController < ApplicationController
2
+ # GET /comments
3
+ # GET /comments.xml
4
+ def index
5
+ @comments = Comment.all
6
+
7
+ respond_to do |format|
8
+ format.html # index.html.erb
9
+ format.xml { render :xml => @comments }
10
+ end
11
+ end
12
+
13
+ # GET /comments/1
14
+ # GET /comments/1.xml
15
+ def show
16
+ @comment = Comment.find(params[:id])
17
+
18
+ respond_to do |format|
19
+ format.html # show.html.erb
20
+ format.xml { render :xml => @comment }
21
+ end
22
+ end
23
+
24
+ # GET /comments/new
25
+ # GET /comments/new.xml
26
+ def new
27
+ @comment = Comment.new
28
+
29
+ respond_to do |format|
30
+ format.html # new.html.erb
31
+ format.xml { render :xml => @comment }
32
+ end
33
+ end
34
+
35
+ # GET /comments/1/edit
36
+ def edit
37
+ @comment = Comment.find(params[:id])
38
+ end
39
+
40
+ def vote
41
+ @comment = Comment.find(params[:id])
42
+ @comment.votes += params[:value].to_i
43
+ @comment.save
44
+ redirect_to(comments_url, :notice => 'Vote added!')
45
+ end
46
+
47
+ # POST /comments
48
+ # POST /comments.xml
49
+ def create
50
+ @comment = Comment.new(params[:comment])
51
+
52
+ respond_to do |format|
53
+ if @comment.save
54
+ format.html { redirect_to(@comment, :notice => 'Comment was successfully created.') }
55
+ format.xml { render :xml => @comment, :status => :created, :location => @comment }
56
+ else
57
+ format.html { render "new" }
58
+ format.xml { render :xml => @comment.errors, :status => :unprocessable_entity }
59
+ end
60
+ end
61
+ end
62
+
63
+ # PUT /comments/1
64
+ # PUT /comments/1.xml
65
+ def update
66
+ @comment = Comment.find(params[:id])
67
+
68
+ respond_to do |format|
69
+ if @comment.update_attributes(params[:comment])
70
+ format.html { redirect_to(@comment, :notice => 'Comment was successfully updated.') }
71
+ format.xml { head :ok }
72
+ else
73
+ format.html { render "edit" }
74
+ format.xml { render :xml => @comment.errors, :status => :unprocessable_entity }
75
+ end
76
+ end
77
+ end
78
+
79
+ # DELETE /comments/1
80
+ # DELETE /comments/1.xml
81
+ def destroy
82
+ @comment = Comment.find(params[:id])
83
+ @comment.destroy
84
+
85
+ respond_to do |format|
86
+ format.html { redirect_to(comments_url) }
87
+ format.xml { head :ok }
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,15 @@
1
+ class RegistrationsController < ApplicationController
2
+ def update
3
+ @user = User.find(params[:id])
4
+
5
+ respond_to do |format|
6
+ if @user.update_attributes(params[:user])
7
+ format.html { redirect_to(@user, :notice => 'User was successfully updated.') }
8
+ format.xml { head :ok }
9
+ else
10
+ format.html { render "edit" }
11
+ format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,67 @@
1
+ class UsersController < ApplicationController
2
+ # GET /users
3
+ # GET /users.xml
4
+ def index
5
+ @users = User.all
6
+
7
+ respond_to do |format|
8
+ format.html # index.html.erb
9
+ format.xml { render :xml => @users }
10
+ end
11
+ end
12
+
13
+ # GET /users/1
14
+ # GET /users/1.xml
15
+ def show
16
+ @user = User.find(params[:id])
17
+
18
+ respond_to do |format|
19
+ format.html # show.html.erb
20
+ format.xml { render :xml => @user }
21
+ end
22
+ end
23
+
24
+ # GET /users/new
25
+ # GET /users/new.xml
26
+ def new
27
+ @user = User.new
28
+
29
+ respond_to do |format|
30
+ format.html # new.html.erb
31
+ format.xml { render :xml => @user }
32
+ end
33
+ end
34
+
35
+ # GET /users/1/edit
36
+ def edit
37
+ @user = User.find(params[:id])
38
+ end
39
+
40
+ # POST /users
41
+ # POST /users.xml
42
+ def create
43
+ @user = User.new(params[:user])
44
+
45
+ respond_to do |format|
46
+ if @user.save
47
+ format.html { redirect_to(@user, :notice => 'User was successfully created.') }
48
+ format.xml { render :xml => @user, :status => :created, :location => @user }
49
+ else
50
+ format.html { render "new" }
51
+ format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
52
+ end
53
+ end
54
+ end
55
+
56
+ # DELETE /users/1
57
+ # DELETE /users/1.xml
58
+ def destroy
59
+ @user = User.find(params[:id])
60
+ @user.destroy
61
+
62
+ respond_to do |format|
63
+ format.html { redirect_to(users_url) }
64
+ format.xml { head :ok }
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,4 @@
1
+ class Comment < ActiveRecord::Base
2
+ belongs_to :user
3
+ validates :name, :comment, :user_id, :presence => true
4
+ end
@@ -0,0 +1,41 @@
1
+ # +grant_on+ accepts:
2
+ # * Nothing (always grants)
3
+ # * A block which evaluates to boolean (recieves the object as parameter)
4
+ # * A block with a hash composed of methods to run on the target object with
5
+ # expected values (+:votes => 5+ for instance).
6
+ #
7
+ # +grant_on+ can have a +:to+ method name, which called over the target object
8
+ # should retrieve the object to badge (could be +:user+, +:self+, +:follower+,
9
+ # etc). If it's not defined merit will apply the badge to the user who
10
+ # triggered the action (:action_user by default). If it's :itself, it badges
11
+ # the created object (new user for instance).
12
+ #
13
+ # The :temporary option indicates that if the condition doesn't hold but the
14
+ # badge is granted, then it's removed. It's false by default (badges are kept
15
+ # forever).
16
+
17
+ class MeritBadgeRules
18
+ include Merit::BadgeRules
19
+
20
+ def initialize
21
+ # If it creates user, grant badge
22
+ # Should be "current_user" after registration for badge to be granted.
23
+ grant_on 'users#create', :badge => 'just-registered', :to => :itself
24
+
25
+ # If it has 10 comments, grant commenter-10 badge
26
+ grant_on 'comments#create', :badge => 'commenter', :level => 10 do
27
+ { :user => { :comments => { :count => 10 } } }
28
+ end
29
+
30
+ # If it has at least 10 votes, grant relevant-commenter badge
31
+ grant_on 'comments#vote', :badge => 'relevant-commenter', :to => :user do |comment|
32
+ comment.votes >= 10
33
+ end
34
+
35
+ # Changes his name by one wider than 4 chars (arbitrary ruby code and custom model_name)
36
+ # This badge is temporary (user may lose it)
37
+ grant_on 'registrations#update', :badge => 'autobiographer', :temporary => true, :model_name => 'User' do |user|
38
+ user.name.length > 4
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,18 @@
1
+ # Points are a simple integer value which are given to "meritable" resources
2
+ # according to rules in +app/models/merit_point_rules.rb+. They are given on
3
+ # actions-triggered.
4
+
5
+ class MeritPointRules
6
+ include Merit::PointRules
7
+
8
+ def initialize
9
+ score 5, :to => :user, :on => [
10
+ 'comments#vote'
11
+ ]
12
+
13
+ score 20, :on => [
14
+ 'comments#create',
15
+ 'registrations#update'
16
+ ]
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ # Rankings are very similar to badges. They give "badges" which have a hierarchy
2
+ # defined by +level+'s lexicografical order (greater is better). If a rank is
3
+ # granted, lower level ranks are taken off. 5 stars is a common ranking use
4
+ # case.
5
+ #
6
+ # They are not given at specified actions like badges, you should define a cron
7
+ # job to test if ranks are to be granted.
8
+ #
9
+ # +set_rank+ accepts:
10
+ # * +badge_name+ name of this ranking
11
+ # * :+level+ ranking level (greater is better)
12
+ # * :+to+ model or scope to check if new rankings apply
13
+
14
+ class MeritRankRules
15
+ include Merit::RankRules
16
+
17
+ def initialize
18
+ # i stars for i chars name
19
+ (1..5).each do |i|
20
+ set_rank :stars, :level => i, :to => User do |user|
21
+ user.name.length == i
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ class User < ActiveRecord::Base
2
+ has_merit
3
+
4
+ has_many :comments
5
+
6
+ def show_badges
7
+ badges.collect{|b| "#{b.name.capitalize} (#{b.level})" }.join(', ')
8
+ end
9
+ end
@@ -0,0 +1,29 @@
1
+ <%= form_for(@comment) do |f| %>
2
+ <% if @comment.errors.any? %>
3
+ <div id="error_explanation">
4
+ <h2><%= pluralize(@comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
5
+
6
+ <ul>
7
+ <% @comment.errors.full_messages.each do |msg| %>
8
+ <li><%= msg %></li>
9
+ <% end %>
10
+ </ul>
11
+ </div>
12
+ <% end %>
13
+
14
+ <div class="field">
15
+ <%= f.label :name %><br />
16
+ <%= f.text_field :name %>
17
+ </div>
18
+ <div class="field">
19
+ <%= f.label :comment %><br />
20
+ <%= f.text_area :comment %>
21
+ </div>
22
+ <div class="field">
23
+ <%= f.label :user_id %><br />
24
+ <%= f.text_field :user_id %>
25
+ </div>
26
+ <div class="actions">
27
+ <%= f.submit %>
28
+ </div>
29
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <h1>Editing comment</h1>
2
+
3
+ <%= render 'form' %>
4
+
5
+ <%= link_to 'Show', @comment %> |
6
+ <%= link_to 'Back', comments_path %>
@@ -0,0 +1,35 @@
1
+ <h1>Listing comments</h1>
2
+
3
+ <table>
4
+ <tr>
5
+ <th>Name</th>
6
+ <th>Comment</th>
7
+ <th>User</th>
8
+ <th>Votes</th>
9
+ <th>Vote up!</th>
10
+ <th></th>
11
+ <th></th>
12
+ <th></th>
13
+ </tr>
14
+
15
+ <% @comments.each do |comment| %>
16
+ <tr id="c_<%= comment.id %>">
17
+ <td><%= comment.name %></td>
18
+ <td><%= comment.comment %></td>
19
+ <td><%= comment.user_id %></td>
20
+ <td><%= comment.votes %></td>
21
+ <td>
22
+ <% (1..5).each do |i| %>
23
+ <%= link_to "#{i}", "/comments/#{comment.id}/vote/#{i}" %>
24
+ <% end %>
25
+ </td>
26
+ <td><%= link_to 'Show', comment %></td>
27
+ <td><%= link_to 'Edit', edit_comment_path(comment) %></td>
28
+ <td><%= link_to 'Destroy', comment, :confirm => 'Are you sure?', :method => :delete %></td>
29
+ </tr>
30
+ <% end %>
31
+ </table>
32
+
33
+ <br />
34
+
35
+ <%= link_to 'New Comment', new_comment_path %>