merit 0.2.5 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -0
- data/Gemfile.lock +103 -0
- data/README.markdown +17 -2
- data/app/models/badge.rb +27 -19
- data/app/models/merit_action.rb +5 -3
- data/app/models/sash.rb +5 -14
- data/lib/generators/active_record/merit_generator.rb +14 -14
- data/lib/generators/{merit → active_record}/templates/create_badges_sashes.rb +0 -0
- data/lib/generators/{merit → active_record}/templates/create_merit_actions.rb +0 -0
- data/lib/generators/{merit → active_record}/templates/create_sashes.rb +0 -0
- data/lib/generators/merit/install_generator.rb +3 -20
- data/lib/generators/merit/merit_generator.rb +12 -0
- data/lib/generators/merit/templates/merit.rb +10 -1
- data/lib/merit.rb +11 -2
- data/lib/merit/controller_extensions.rb +2 -2
- data/lib/merit/model_additions.rb +18 -17
- data/lib/merit/models/active_record/badges_sash.rb +12 -0
- data/lib/merit/models/active_record/merit_action.rb +2 -0
- data/lib/merit/models/active_record/sash.rb +12 -0
- data/lib/merit/models/mongo_mapper/merit_action.rb +12 -0
- data/lib/merit/models/mongo_mapper/sash.rb +15 -0
- data/lib/merit/rule.rb +2 -2
- data/lib/merit/rules_badge.rb +1 -1
- data/merit.gemspec +16 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/controllers/application_controller.rb +7 -0
- data/test/dummy/app/controllers/comments_controller.rb +90 -0
- data/test/dummy/app/controllers/registrations_controller.rb +15 -0
- data/test/dummy/app/controllers/users_controller.rb +67 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/comment.rb +4 -0
- data/test/dummy/app/models/merit_badge_rules.rb +41 -0
- data/test/dummy/app/models/merit_point_rules.rb +18 -0
- data/test/dummy/app/models/merit_rank_rules.rb +25 -0
- data/test/dummy/app/models/user.rb +9 -0
- data/test/dummy/app/views/comments/_form.html.erb +29 -0
- data/test/dummy/app/views/comments/edit.html.erb +6 -0
- data/test/dummy/app/views/comments/index.html.erb +35 -0
- data/test/dummy/app/views/comments/new.html.erb +5 -0
- data/test/dummy/app/views/comments/show.html.erb +23 -0
- data/test/dummy/app/views/layouts/application.html.haml +18 -0
- data/test/dummy/app/views/users/_form.html.erb +22 -0
- data/test/dummy/app/views/users/edit.html.erb +6 -0
- data/test/dummy/app/views/users/index.html.erb +26 -0
- data/test/dummy/app/views/users/new.html.erb +5 -0
- data/test/dummy/app/views/users/show.html.erb +18 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +24 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +22 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +26 -0
- data/test/dummy/config/environments/production.rb +49 -0
- data/test/dummy/config/environments/test.rb +35 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/badges_data.rb +40 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +9 -0
- data/test/dummy/db/migrate/20110421191249_create_users.rb +12 -0
- data/test/dummy/db/migrate/20110421191250_create_comments.rb +16 -0
- data/test/dummy/db/schema.rb +61 -0
- data/test/dummy/db/seeds.rb +17 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/javascripts/application.js +2 -0
- data/test/dummy/public/javascripts/controls.js +965 -0
- data/test/dummy/public/javascripts/dragdrop.js +974 -0
- data/test/dummy/public/javascripts/effects.js +1123 -0
- data/test/dummy/public/javascripts/prototype.js +6001 -0
- data/test/dummy/public/javascripts/rails.js +191 -0
- data/test/dummy/public/stylesheets/.gitkeep +0 -0
- data/test/dummy/public/stylesheets/scaffold.css +56 -0
- data/test/dummy/script/rails +6 -0
- data/test/integration/navigation_test.rb +132 -0
- data/test/merit_unit_test.rb +22 -0
- data/test/support/integration_case.rb +5 -0
- data/test/test_helper.rb +22 -0
- metadata +132 -13
- data/app/models/badges_sash.rb +0 -14
- 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,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
|
data/lib/merit/rule.rb
CHANGED
@@ -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.
|
76
|
-
badges = badges.
|
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
|
data/lib/merit/rules_badge.rb
CHANGED
@@ -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.
|
57
|
+
merit_action.check_rules(defined_rules)
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
data/merit.gemspec
ADDED
@@ -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
|
data/test/dummy/Rakefile
ADDED
@@ -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,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,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,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,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 %>
|