merit 0.2.5 → 0.3.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.
- 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 %>
|