acts-as-approvable 0.6.1
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/.gitignore +6 -0
- data/Appraisals +18 -0
- data/CHANGELOG +10 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +50 -0
- data/MIT-LICENSE +20 -0
- data/README.md +108 -0
- data/Rakefile +81 -0
- data/VERSION +1 -0
- data/acts-as-approvable.gemspec +31 -0
- data/gemfiles/rails2.gemfile +7 -0
- data/gemfiles/rails2.gemfile.lock +50 -0
- data/gemfiles/rails30.gemfile +8 -0
- data/gemfiles/rails30.gemfile.lock +90 -0
- data/gemfiles/rails31.gemfile +8 -0
- data/gemfiles/rails31.gemfile.lock +101 -0
- data/gemfiles/rails32.gemfile +8 -0
- data/gemfiles/rails32.gemfile.lock +99 -0
- data/generators/acts_as_approvable/USAGE +3 -0
- data/generators/acts_as_approvable/acts_as_approvable_generator.rb +86 -0
- data/generators/acts_as_approvable/templates/approvals_controller.rb +97 -0
- data/generators/acts_as_approvable/templates/create_approvals.rb +26 -0
- data/generators/acts_as_approvable/templates/initializer.rb +3 -0
- data/generators/acts_as_approvable/templates/views/erb/_owner_select.html.erb +4 -0
- data/generators/acts_as_approvable/templates/views/erb/_table.html.erb +26 -0
- data/generators/acts_as_approvable/templates/views/erb/index.html.erb +15 -0
- data/generators/acts_as_approvable/templates/views/haml/_owner_select.html.haml +3 -0
- data/generators/acts_as_approvable/templates/views/haml/_table.html.haml +19 -0
- data/generators/acts_as_approvable/templates/views/haml/index.html.haml +13 -0
- data/init.rb +1 -0
- data/lib/acts-as-approvable/version.rb +3 -0
- data/lib/acts_as_approvable/acts_as_approvable.rb +291 -0
- data/lib/acts_as_approvable/approval.rb +179 -0
- data/lib/acts_as_approvable/error.rb +31 -0
- data/lib/acts_as_approvable/ownership.rb +117 -0
- data/lib/acts_as_approvable/railtie.rb +7 -0
- data/lib/acts_as_approvable.rb +66 -0
- data/lib/generators/acts_as_approvable/USAGE +1 -0
- data/lib/generators/acts_as_approvable/acts_as_approvable_generator.rb +73 -0
- data/lib/generators/acts_as_approvable/templates/approvals_controller.rb +97 -0
- data/lib/generators/acts_as_approvable/templates/create_approvals.rb +26 -0
- data/lib/generators/acts_as_approvable.rb +0 -0
- data/lib/generators/erb/acts_as_approvable_generator.rb +44 -0
- data/lib/generators/erb/templates/_owner_select.html.erb +4 -0
- data/lib/generators/erb/templates/_table.html.erb +26 -0
- data/lib/generators/erb/templates/index.html.erb +15 -0
- data/lib/generators/haml/acts_as_approvable_generator.rb +44 -0
- data/lib/generators/haml/templates/_owner_select.html.haml +3 -0
- data/lib/generators/haml/templates/_table.html.haml +19 -0
- data/lib/generators/haml/templates/index.html.haml +13 -0
- data/lib/tasks/acts_as_approvable.rake +4 -0
- data/rails/init.rb +1 -0
- data/test/acts_as_approvable_model_test.rb +428 -0
- data/test/acts_as_approvable_ownership_test.rb +132 -0
- data/test/acts_as_approvable_schema_test.rb +13 -0
- data/test/acts_as_approvable_test.rb +8 -0
- data/test/database.yml +7 -0
- data/test/schema.rb +44 -0
- data/test/support.rb +19 -0
- data/test/test_helper.rb +60 -0
- metadata +225 -0
@@ -0,0 +1,99 @@
|
|
1
|
+
PATH
|
2
|
+
remote: /Users/jlogsdon/Code/acts_as_approvable/acts_as_approvable
|
3
|
+
specs:
|
4
|
+
acts-as-approvable (0.6.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
actionpack (3.2.1)
|
10
|
+
activemodel (= 3.2.1)
|
11
|
+
activesupport (= 3.2.1)
|
12
|
+
builder (~> 3.0.0)
|
13
|
+
erubis (~> 2.7.0)
|
14
|
+
journey (~> 1.0.1)
|
15
|
+
rack (~> 1.4.0)
|
16
|
+
rack-cache (~> 1.1)
|
17
|
+
rack-test (~> 0.6.1)
|
18
|
+
sprockets (~> 2.1.2)
|
19
|
+
activemodel (3.2.1)
|
20
|
+
activesupport (= 3.2.1)
|
21
|
+
builder (~> 3.0.0)
|
22
|
+
activerecord (3.2.1)
|
23
|
+
activemodel (= 3.2.1)
|
24
|
+
activesupport (= 3.2.1)
|
25
|
+
arel (~> 3.0.0)
|
26
|
+
tzinfo (~> 0.3.29)
|
27
|
+
activesupport (3.2.1)
|
28
|
+
i18n (~> 0.6)
|
29
|
+
multi_json (~> 1.0)
|
30
|
+
appraisal (0.4.1)
|
31
|
+
bundler
|
32
|
+
rake
|
33
|
+
arel (3.0.0)
|
34
|
+
builder (3.0.0)
|
35
|
+
coderay (1.0.5)
|
36
|
+
erubis (2.7.0)
|
37
|
+
hike (1.2.1)
|
38
|
+
i18n (0.6.0)
|
39
|
+
journey (1.0.1)
|
40
|
+
json (1.6.5)
|
41
|
+
metaclass (0.0.1)
|
42
|
+
method_source (0.7.0)
|
43
|
+
mocha (0.10.4)
|
44
|
+
metaclass (~> 0.0.1)
|
45
|
+
multi_json (1.0.4)
|
46
|
+
pry (0.9.8)
|
47
|
+
coderay (~> 1.0.5)
|
48
|
+
method_source (~> 0.7)
|
49
|
+
slop (>= 2.4.3, < 3)
|
50
|
+
rack (1.4.1)
|
51
|
+
rack-cache (1.1)
|
52
|
+
rack (>= 0.4)
|
53
|
+
rack-ssl (1.3.2)
|
54
|
+
rack
|
55
|
+
rack-test (0.6.1)
|
56
|
+
rack (>= 1.0)
|
57
|
+
railties (3.2.1)
|
58
|
+
actionpack (= 3.2.1)
|
59
|
+
activesupport (= 3.2.1)
|
60
|
+
rack-ssl (~> 1.3.2)
|
61
|
+
rake (>= 0.8.7)
|
62
|
+
rdoc (~> 3.4)
|
63
|
+
thor (~> 0.14.6)
|
64
|
+
rake (0.9.2.2)
|
65
|
+
rdoc (3.12)
|
66
|
+
json (~> 1.4)
|
67
|
+
redcarpet (2.1.0)
|
68
|
+
shoulda (2.11.3)
|
69
|
+
simplecov (0.5.4)
|
70
|
+
multi_json (~> 1.0.3)
|
71
|
+
simplecov-html (~> 0.5.3)
|
72
|
+
simplecov-html (0.5.3)
|
73
|
+
slop (2.4.3)
|
74
|
+
sprockets (2.1.2)
|
75
|
+
hike (~> 1.2)
|
76
|
+
rack (~> 1.0)
|
77
|
+
tilt (~> 1.1, != 1.3.0)
|
78
|
+
sqlite3 (1.3.5)
|
79
|
+
thor (0.14.6)
|
80
|
+
tilt (1.3.3)
|
81
|
+
tzinfo (0.3.31)
|
82
|
+
yard (0.7.5)
|
83
|
+
|
84
|
+
PLATFORMS
|
85
|
+
ruby
|
86
|
+
|
87
|
+
DEPENDENCIES
|
88
|
+
activerecord (~> 3.2.0)
|
89
|
+
acts-as-approvable!
|
90
|
+
appraisal
|
91
|
+
mocha
|
92
|
+
pry
|
93
|
+
railties (~> 3.2.0)
|
94
|
+
rake
|
95
|
+
redcarpet
|
96
|
+
shoulda
|
97
|
+
simplecov
|
98
|
+
sqlite3
|
99
|
+
yard
|
@@ -0,0 +1,86 @@
|
|
1
|
+
class ActsAsApprovableGenerator < Rails::Generator::Base
|
2
|
+
default_options :base => 'ApplicationController'
|
3
|
+
|
4
|
+
def manifest
|
5
|
+
record do |m|
|
6
|
+
m.migration_template 'create_approvals.rb', 'db/migrate', :migration_file_name => 'create_approvals'
|
7
|
+
|
8
|
+
m.directory 'app/controllers'
|
9
|
+
m.template 'approvals_controller.rb', 'app/controllers/approvals_controller.rb'
|
10
|
+
|
11
|
+
m.directory 'app/views/approvals'
|
12
|
+
m.template "views/#{view_language}/index.html.#{view_language}", "app/views/approvals/index.html.#{view_language}"
|
13
|
+
m.template "views/#{view_language}/_table.html.#{view_language}", "app/views/approvals/_table.html.#{view_language}"
|
14
|
+
|
15
|
+
m.directory 'config/initializers'
|
16
|
+
m.template 'initializer.rb', 'config/initializers/acts_as_approvable.rb'
|
17
|
+
|
18
|
+
m.route route
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
def view_language
|
24
|
+
options[:haml] ? 'haml' : 'erb'
|
25
|
+
end
|
26
|
+
|
27
|
+
def owner?
|
28
|
+
options[:owner].present?
|
29
|
+
end
|
30
|
+
|
31
|
+
def collection_actions
|
32
|
+
actions = [:index, :history]
|
33
|
+
actions << :mine if owner?
|
34
|
+
actions.map { |a| ":#{a}" }
|
35
|
+
end
|
36
|
+
|
37
|
+
def member_actions
|
38
|
+
actions = [:approve, :reject]
|
39
|
+
actions << :assign if owner?
|
40
|
+
actions.map { |a| ":#{a}" }
|
41
|
+
end
|
42
|
+
|
43
|
+
def route
|
44
|
+
route = 'map.resources :approvals, :only => [:index], :collection => ['
|
45
|
+
route << collection_actions.reject { |a| a == ':index' }.join(', ')
|
46
|
+
route << '], :member => ['
|
47
|
+
route << member_actions.join(', ')
|
48
|
+
route << ']'
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_options!(opt)
|
52
|
+
opt.separator ''
|
53
|
+
opt.separator 'Options:'
|
54
|
+
opt.on('--base BASE', 'Base class for ApprovableController.') { |v| options[:base] = v }
|
55
|
+
opt.on('--haml', 'Generate HAML views instead of ERB.') { |v| options[:haml] = v }
|
56
|
+
opt.on('--owner [User]', 'Enable and, optionally, set the model for approval ownerships.') { |v| options[:owner] = v || 'User' }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Gross! But Rails 2 only allows us to define resources with no options.
|
61
|
+
module Rails
|
62
|
+
module Generator
|
63
|
+
module Commands
|
64
|
+
class Create
|
65
|
+
def route(route)
|
66
|
+
sentinel = 'ActionController::Routing::Routes.draw do |map|'
|
67
|
+
|
68
|
+
logger.route route
|
69
|
+
unless options[:pretend]
|
70
|
+
gsub_file 'config/routes.rb', /#{Regexp.escape(sentinel)}/mi do |match|
|
71
|
+
"#{match}\n #{route}\n"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Destroy
|
78
|
+
def route(route)
|
79
|
+
look_for = "\n #{Regexp.escape(route)}\n"
|
80
|
+
logger.route route
|
81
|
+
gsub_file 'config/routes.rb', /#{look_for}/mi, ''
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
class ApprovalsController < <%= options[:base] %>
|
2
|
+
before_filter :setup_conditions, :only => [<%= collection_actions.join(', ') %>]
|
3
|
+
before_filter :setup_partial, :only => [<%= collection_actions.join(', ') %>]
|
4
|
+
before_filter :find_approval, :only => [<%= member_actions.join(', ') %>]
|
5
|
+
around_filter :json_wrapper, :only => [<%= member_actions.join(', ') %>]
|
6
|
+
|
7
|
+
def index
|
8
|
+
state = params[:state] =~ /^\d+$/ ? params[:state].to_i : Approval.enumerate_state('pending')
|
9
|
+
@conditions[:state] = state if state > -1
|
10
|
+
|
11
|
+
@approvals = Approval.all(:conditions => @conditions, :order => 'created_at ASC')
|
12
|
+
end
|
13
|
+
|
14
|
+
def history
|
15
|
+
@conditions[:state] = Approval.enumerate_states('approved', 'rejected')
|
16
|
+
|
17
|
+
@approvals = Approval.all(:conditions => @conditions, :order => 'created_at DESC')
|
18
|
+
render :index
|
19
|
+
end
|
20
|
+
|
21
|
+
<% if owner? %> def mine
|
22
|
+
@conditions[:owner_id] = current_user.id
|
23
|
+
|
24
|
+
@approvals = Approval.all(:conditions => @conditions, :order => 'created_at ASC')
|
25
|
+
render :index
|
26
|
+
end
|
27
|
+
|
28
|
+
def assign
|
29
|
+
if params[:approval][:owner_id].empty?
|
30
|
+
@approval.unassign
|
31
|
+
else
|
32
|
+
user = <%= options[:owner] %>.find(params[:approval][:owner_id])
|
33
|
+
@approval.assign(user)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
<% end %> def approve
|
38
|
+
<% if owner? %> @approval.owner = current_user if respond_to?(:current_user)
|
39
|
+
<% end %> @approval.approve!
|
40
|
+
end
|
41
|
+
|
42
|
+
def reject
|
43
|
+
<% if owner? %> @approval.owner = current_user if respond_to?(:current_user)
|
44
|
+
<% end %> @approval.reject!(params[:reason])
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def json_wrapper
|
49
|
+
json = {:success => false}
|
50
|
+
|
51
|
+
begin
|
52
|
+
json[:success] = yield
|
53
|
+
rescue ActsAsApprovable::Error => e
|
54
|
+
json[:message] = e.message
|
55
|
+
rescue
|
56
|
+
json[:message] = 'An unknown error occured'
|
57
|
+
end
|
58
|
+
|
59
|
+
respond_to do |format|
|
60
|
+
format.html do
|
61
|
+
flash[:error] = json[:message] if json[:message]
|
62
|
+
redirect_to :action => :index
|
63
|
+
end
|
64
|
+
format.json { render :json => json }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def setup_conditions
|
69
|
+
@conditions ||= {}
|
70
|
+
|
71
|
+
<% if owner? %> if params[:owner_id]
|
72
|
+
@conditions[:owner_id] = params[:owner_id]
|
73
|
+
@conditions[:owner_id] = nil if params[:owner_id] == 0
|
74
|
+
end
|
75
|
+
<% end %> if params[:item_type]
|
76
|
+
@conditions[:item_type] = params[:item_type]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Check for the selected models partial, use the generic one if it doesn't exist
|
81
|
+
def setup_partial
|
82
|
+
@table_partial = @conditions.fetch(:item_type) { 'table' }
|
83
|
+
|
84
|
+
if @table_partial != 'table'
|
85
|
+
partial_path = Rails.root.join('app', 'views', 'approvals', "_#{@table_partial}.html.#{view_language}")
|
86
|
+
@table_partial = 'table' unless File.exist?(partial_path)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def find_approval
|
91
|
+
@approval = Approval.find(params[:id])
|
92
|
+
end
|
93
|
+
|
94
|
+
def view_language
|
95
|
+
ActsAsApprovable.view_language
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class CreateApprovals < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :approvals do |t|
|
4
|
+
t.string :item_type, :null => false
|
5
|
+
t.integer :item_id, :null => false
|
6
|
+
t.string :event, :null => false
|
7
|
+
t.integer :state, :null => false, :default => 0
|
8
|
+
<% if options[:owner] %> t.integer :owner_id
|
9
|
+
<% end %> t.text :object
|
10
|
+
t.text :reason
|
11
|
+
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
|
15
|
+
add_index :approvals, [:state, :event]
|
16
|
+
add_index :approvals, [:item_type, :item_id]
|
17
|
+
<% if options[:owner] %> add_index :approvals, [:owner_id]
|
18
|
+
<% end %> end
|
19
|
+
|
20
|
+
def self.down
|
21
|
+
remove_index :approvals, [:state, :event]
|
22
|
+
remove_index :approvals, [:item_type, :item_id]
|
23
|
+
<% if options[:owner] %> remove_index :approvals, [:owner_id]
|
24
|
+
<% end %> drop_table :approvals
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<table>
|
2
|
+
<thead>
|
3
|
+
<tr>
|
4
|
+
<th>Type</th>
|
5
|
+
<th>Record</th>
|
6
|
+
<% if owner? %> <th>Owner</th>
|
7
|
+
<% end %> <th>State</th>
|
8
|
+
<th> </th>
|
9
|
+
</tr>
|
10
|
+
</thead>
|
11
|
+
<tbody>
|
12
|
+
<%% @approvals.each do |approval| %>
|
13
|
+
<tr>
|
14
|
+
<td><%%= approval.item_type.classify %></td>
|
15
|
+
<td><%%= approval.item.try(:to_s) || approval.item.id %></td>
|
16
|
+
<% if owner? %> <td><%%= render :partial => 'owner_select', :locals => {:approval => approval} %></td>
|
17
|
+
<% end %> <td><%%= approval.state %></td>
|
18
|
+
<td class='actions'>
|
19
|
+
<%%= link_to('Approve', approve_approval_path(approval)) %>
|
20
|
+
<%%= link_to('Reject', reject_approval_path(approval)) %>
|
21
|
+
</td>
|
22
|
+
</tr>
|
23
|
+
<%% end %>
|
24
|
+
</tbody>
|
25
|
+
</table>
|
26
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<h1>Approval Queue</h1>
|
2
|
+
|
3
|
+
<%% form_for(:approval, :url => approvals_path, :html => {:method => :get}) do |f| %>
|
4
|
+
<%% unless @conditions[:state].is_a?(Array) # History page shouldn't allow selecting different states %>
|
5
|
+
<%%= f.label(:state) %>
|
6
|
+
<%%= f.select(:state, options_for_select(Approval.options_for_state, @conditions[:state])) %>
|
7
|
+
<%% end %>
|
8
|
+
<% if owner? %> <%%= f.label(:owner_id) %>
|
9
|
+
<%%= f.select(:owner_id, options_for_select(Approval.options_for_assigned_owners, @conditions[:owner_id]), :prompt => 'All Users') %>
|
10
|
+
<% end %> <%%= f.label(:item_type) %>
|
11
|
+
<%%= f.select(:item_type, options_for_select(Approval.options_for_type, @conditions[:item_type]), :prompt => 'All Types') %>
|
12
|
+
<%%= f.submit('Filter') %>
|
13
|
+
<%% end %>
|
14
|
+
|
15
|
+
<%%= render :partial => @table_partial %>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
%table
|
2
|
+
%thead
|
3
|
+
%tr
|
4
|
+
%th Type
|
5
|
+
%th Record
|
6
|
+
<% if owner? %> %th Owner
|
7
|
+
<% end %> %th State
|
8
|
+
%th
|
9
|
+
%tbody
|
10
|
+
- @approvals.each do |approval|
|
11
|
+
%tr
|
12
|
+
%td= approval.item_type.classify
|
13
|
+
%td= approval.item.try(:to_s) || approval.item.id
|
14
|
+
<% if owner? %> %td= render :partial => 'owner_select', :locals => {:approval => approval}
|
15
|
+
<% end %> %td= approval.state
|
16
|
+
%td.actions
|
17
|
+
= link_to('Approve', approve_approval_path(approval))
|
18
|
+
= link_to('Reject', reject_approval_path(approval))
|
19
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
%h1 Approval Queue
|
2
|
+
|
3
|
+
- form_for(:approval, :url => approvals_path, :html => {:method => :get}) do |f|
|
4
|
+
- unless @conditions[:state].is_a?(Array) # History page shouldn't allow selecting different states
|
5
|
+
= label_tag('state', 'State')
|
6
|
+
= select_tag('state', options_for_select(Approval.options_for_state, @conditions[:state]))
|
7
|
+
<% if owner? %> = label_tag('owner_id', 'Owner')
|
8
|
+
= select('owner_id', options_for_select(Approval.options_for_assigned_owners(true), @conditions[:owner_id]))
|
9
|
+
<% end %> = label_tag('item_type', 'Type')
|
10
|
+
= select_tag('item_type', options_for_select(Approval.options_for_type(true), @conditions[:item_type]))
|
11
|
+
%button{:type => 'Submit'} Filter
|
12
|
+
|
13
|
+
= render :partial => @table_partial
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/rails/init'
|