saucy 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +15 -1
- data/Gemfile.lock +67 -1
- data/Rakefile +26 -0
- data/app/controllers/memberships_controller.rb +33 -1
- data/app/models/invitation.rb +1 -1
- data/app/models/membership.rb +22 -0
- data/app/models/permission.rb +17 -0
- data/app/models/signup.rb +3 -3
- data/app/views/memberships/edit.html.erb +18 -0
- data/app/views/memberships/index.html.erb +4 -4
- data/config/routes.rb +2 -3
- data/features/run_features.feature +4 -3
- data/features/step_definitions/rails_steps.rb +3 -0
- data/lib/generators/saucy/features/templates/factories.rb +4 -4
- data/lib/generators/saucy/features/templates/step_definitions/session_steps.rb +6 -3
- data/lib/generators/saucy/features/templates/step_definitions/user_steps.rb +6 -4
- data/lib/generators/saucy/install/templates/create_saucy_tables.rb +8 -6
- data/lib/saucy/account.rb +9 -5
- data/lib/saucy/project.rb +28 -5
- data/lib/saucy/user.rb +5 -12
- data/spec/controllers/memberships_controller_spec.rb +87 -5
- data/spec/environment.rb +91 -0
- data/spec/models/account_spec.rb +17 -6
- data/spec/models/membership_spec.rb +37 -0
- data/spec/models/permission_spec.rb +19 -0
- data/spec/models/project_spec.rb +39 -9
- data/spec/models/user_spec.rb +16 -42
- data/spec/scaffold/config/routes.rb +5 -0
- data/spec/spec_helper.rb +8 -1
- data/spec/support/authentication_helpers.rb +16 -6
- metadata +75 -74
- data/app/controllers/permissions_controller.rb +0 -17
- data/app/models/account_membership.rb +0 -8
- data/app/models/project_membership.rb +0 -14
- data/app/views/permissions/edit.html.erb +0 -15
- data/spec/controllers/permissions_controller_spec.rb +0 -69
- data/spec/models/account_membership_spec.rb +0 -13
- data/spec/models/project_membership_spec.rb +0 -22
data/Gemfile
CHANGED
@@ -2,7 +2,21 @@ source "http://rubygems.org"
|
|
2
2
|
gem "cucumber"
|
3
3
|
gem "aruba"
|
4
4
|
gem "rake"
|
5
|
-
gem "rspec", :require => false
|
5
|
+
gem "rspec-rails", :require => false
|
6
6
|
gem "rails", ">= 3.0.3"
|
7
7
|
gem "thin"
|
8
|
+
gem "clearance", "0.9.0.rc9", :require => false
|
9
|
+
gem "shoulda", :require => false
|
10
|
+
gem "bourne", :require => false
|
11
|
+
gem "sqlite3-ruby", :require => false
|
12
|
+
gem "factory_girl", :require => false
|
13
|
+
|
14
|
+
# used by the rails app in cucumber
|
15
|
+
gem "cucumber-rails", :require => false
|
16
|
+
gem "capybara", :require => false
|
17
|
+
gem "factory_girl_rails", :require => false
|
18
|
+
gem "formtastic", :require => false
|
19
|
+
gem "database_cleaner", :require => false
|
20
|
+
gem "dynamic_form", :require => false
|
21
|
+
gem "launchy", :require => false
|
8
22
|
|
data/Gemfile.lock
CHANGED
@@ -33,29 +33,68 @@ GEM
|
|
33
33
|
background_process
|
34
34
|
cucumber (~> 0.9.4)
|
35
35
|
background_process (1.2)
|
36
|
+
bourne (1.0)
|
37
|
+
mocha (= 0.9.8)
|
36
38
|
builder (2.1.2)
|
39
|
+
capybara (0.4.0)
|
40
|
+
celerity (>= 0.7.9)
|
41
|
+
culerity (>= 0.2.4)
|
42
|
+
mime-types (>= 1.16)
|
43
|
+
nokogiri (>= 1.3.3)
|
44
|
+
rack (>= 1.0.0)
|
45
|
+
rack-test (>= 0.5.4)
|
46
|
+
selenium-webdriver (>= 0.0.27)
|
47
|
+
xpath (~> 0.1.2)
|
48
|
+
celerity (0.8.5)
|
49
|
+
childprocess (0.1.4)
|
50
|
+
ffi (~> 0.6.3)
|
51
|
+
clearance (0.9.0.rc9)
|
52
|
+
rails (~> 3.0.0)
|
53
|
+
configuration (1.2.0)
|
37
54
|
cucumber (0.9.4)
|
38
55
|
builder (~> 2.1.2)
|
39
56
|
diff-lcs (~> 1.1.2)
|
40
57
|
gherkin (~> 2.2.9)
|
41
58
|
json (~> 1.4.6)
|
42
59
|
term-ansicolor (~> 1.0.5)
|
60
|
+
cucumber-rails (0.3.2)
|
61
|
+
cucumber (>= 0.8.0)
|
62
|
+
culerity (0.2.12)
|
43
63
|
daemons (1.1.0)
|
64
|
+
database_cleaner (0.6.0)
|
44
65
|
diff-lcs (1.1.2)
|
66
|
+
dynamic_form (1.1.3)
|
45
67
|
erubis (2.6.6)
|
46
68
|
abstract (>= 1.0.0)
|
47
69
|
eventmachine (0.12.10)
|
70
|
+
factory_girl (1.3.2)
|
71
|
+
factory_girl_rails (1.0)
|
72
|
+
factory_girl (~> 1.3)
|
73
|
+
rails (>= 3.0.0.beta4)
|
74
|
+
ffi (0.6.3)
|
75
|
+
rake (>= 0.8.7)
|
76
|
+
formtastic (1.2.2)
|
77
|
+
actionpack (>= 2.3.7)
|
78
|
+
activesupport (>= 2.3.7)
|
79
|
+
i18n (>= 0.4.0)
|
48
80
|
gherkin (2.2.9)
|
49
81
|
json (~> 1.4.6)
|
50
82
|
term-ansicolor (~> 1.0.5)
|
51
83
|
i18n (0.5.0)
|
52
84
|
json (1.4.6)
|
85
|
+
json_pure (1.4.6)
|
86
|
+
launchy (0.3.7)
|
87
|
+
configuration (>= 0.0.5)
|
88
|
+
rake (>= 0.8.1)
|
53
89
|
mail (2.2.11)
|
54
90
|
activesupport (>= 2.3.6)
|
55
91
|
i18n (~> 0.5.0)
|
56
92
|
mime-types (~> 1.16)
|
57
93
|
treetop (~> 1.4.8)
|
58
94
|
mime-types (1.16)
|
95
|
+
mocha (0.9.8)
|
96
|
+
rake
|
97
|
+
nokogiri (1.4.4)
|
59
98
|
polyglot (0.3.1)
|
60
99
|
rack (1.2.1)
|
61
100
|
rack-mount (0.6.13)
|
@@ -84,6 +123,19 @@ GEM
|
|
84
123
|
rspec-expectations (2.2.0)
|
85
124
|
diff-lcs (~> 1.1.2)
|
86
125
|
rspec-mocks (2.2.0)
|
126
|
+
rspec-rails (2.2.1)
|
127
|
+
actionpack (~> 3.0)
|
128
|
+
activesupport (~> 3.0)
|
129
|
+
railties (~> 3.0)
|
130
|
+
rspec (~> 2.2.0)
|
131
|
+
rubyzip (0.9.4)
|
132
|
+
selenium-webdriver (0.1.1)
|
133
|
+
childprocess (= 0.1.4)
|
134
|
+
ffi (~> 0.6.3)
|
135
|
+
json_pure
|
136
|
+
rubyzip
|
137
|
+
shoulda (2.11.3)
|
138
|
+
sqlite3-ruby (1.3.2)
|
87
139
|
term-ansicolor (1.0.5)
|
88
140
|
thin (1.2.7)
|
89
141
|
daemons (>= 1.0.9)
|
@@ -93,14 +145,28 @@ GEM
|
|
93
145
|
treetop (1.4.9)
|
94
146
|
polyglot (>= 0.3.1)
|
95
147
|
tzinfo (0.3.23)
|
148
|
+
xpath (0.1.2)
|
149
|
+
nokogiri (~> 1.3)
|
96
150
|
|
97
151
|
PLATFORMS
|
98
152
|
ruby
|
99
153
|
|
100
154
|
DEPENDENCIES
|
101
155
|
aruba
|
156
|
+
bourne
|
157
|
+
capybara
|
158
|
+
clearance (= 0.9.0.rc9)
|
102
159
|
cucumber
|
160
|
+
cucumber-rails
|
161
|
+
database_cleaner
|
162
|
+
dynamic_form
|
163
|
+
factory_girl
|
164
|
+
factory_girl_rails
|
165
|
+
formtastic
|
166
|
+
launchy
|
103
167
|
rails (>= 3.0.3)
|
104
168
|
rake
|
105
|
-
rspec
|
169
|
+
rspec-rails
|
170
|
+
shoulda
|
171
|
+
sqlite3-ruby
|
106
172
|
thin
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'cucumber/rake/task'
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
|
8
|
+
desc 'Default: run all tests'
|
9
|
+
task :default => [:spec, :cucumber]
|
10
|
+
|
11
|
+
Cucumber::Rake::Task.new(:cucumber) do |t|
|
12
|
+
t.fork = true
|
13
|
+
t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'progress')]
|
14
|
+
end
|
15
|
+
|
16
|
+
RSpec::Core::RakeTask.new do |t|
|
17
|
+
t.pattern = "spec/**/*_spec.rb"
|
18
|
+
t.rspec_opts = "--format progress"
|
19
|
+
end
|
20
|
+
|
21
|
+
eval("$specification = begin; #{IO.read('saucy.gemspec')}; end")
|
22
|
+
Rake::GemPackageTask.new($specification) do |package|
|
23
|
+
package.need_zip = true
|
24
|
+
package.need_tar = true
|
25
|
+
end
|
26
|
+
|
@@ -3,7 +3,39 @@ class MembershipsController < ApplicationController
|
|
3
3
|
layout Saucy::Layouts.to_proc
|
4
4
|
|
5
5
|
def index
|
6
|
-
@
|
6
|
+
@memberships = current_account.memberships_by_name
|
7
7
|
render
|
8
8
|
end
|
9
|
+
|
10
|
+
def edit
|
11
|
+
find_membership
|
12
|
+
@projects = current_account.projects_by_name
|
13
|
+
render
|
14
|
+
end
|
15
|
+
|
16
|
+
def update
|
17
|
+
find_membership.update_attributes!(params[:membership])
|
18
|
+
flash[:success] = "Permissions updated."
|
19
|
+
redirect_to account_memberships_url(current_account)
|
20
|
+
end
|
21
|
+
|
22
|
+
def destroy
|
23
|
+
find_membership.destroy
|
24
|
+
flash[:success] = "User removed."
|
25
|
+
redirect_to account_memberships_url(current_account)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def find_membership
|
31
|
+
@membership ||= Membership.find(params[:id], :include => :account)
|
32
|
+
end
|
33
|
+
|
34
|
+
def current_account
|
35
|
+
if params[:id]
|
36
|
+
find_membership.account
|
37
|
+
else
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
9
41
|
end
|
data/app/models/invitation.rb
CHANGED
@@ -22,7 +22,7 @@ class Invitation < ActiveRecord::Base
|
|
22
22
|
@user = existing_user || new_user
|
23
23
|
if valid?
|
24
24
|
@user.save!
|
25
|
-
@user.
|
25
|
+
@user.memberships.create!(:account => account, :admin => admin)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Membership < ActiveRecord::Base
|
2
|
+
belongs_to :user
|
3
|
+
belongs_to :account
|
4
|
+
has_many :permissions
|
5
|
+
has_many :projects, :through => :permissions
|
6
|
+
|
7
|
+
validates_presence_of :user_id
|
8
|
+
validates_presence_of :account_id
|
9
|
+
validates_uniqueness_of :user_id, :scope => :account_id
|
10
|
+
|
11
|
+
def name
|
12
|
+
user.name
|
13
|
+
end
|
14
|
+
|
15
|
+
def email
|
16
|
+
user.email
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.by_name
|
20
|
+
joins(:user).order('users.name')
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Permission < ActiveRecord::Base
|
2
|
+
belongs_to :membership
|
3
|
+
belongs_to :project
|
4
|
+
belongs_to :user
|
5
|
+
|
6
|
+
before_validation :assign_user_id_from_membership
|
7
|
+
|
8
|
+
def user=(ignored)
|
9
|
+
raise NotImplementedError, "Use Permission#membership= instead"
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def assign_user_id_from_membership
|
15
|
+
self.user_id = membership.user_id
|
16
|
+
end
|
17
|
+
end
|
data/app/models/signup.rb
CHANGED
@@ -66,8 +66,8 @@ class Signup
|
|
66
66
|
@existing_user ||= User.find_by_email(email)
|
67
67
|
end
|
68
68
|
|
69
|
-
def
|
70
|
-
@
|
69
|
+
def membership
|
70
|
+
@membership ||= Membership.new(:user => user,
|
71
71
|
:account => account,
|
72
72
|
:admin => true)
|
73
73
|
end
|
@@ -128,7 +128,7 @@ class Signup
|
|
128
128
|
Account.transaction do
|
129
129
|
account.save!
|
130
130
|
user.save!
|
131
|
-
|
131
|
+
membership.save!
|
132
132
|
end
|
133
133
|
end
|
134
134
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<h2>Permissions for <span><%= @membership.name %></span> on <%= current_account.name %></h2>
|
2
|
+
|
3
|
+
<%= render :partial => 'accounts/tab_bar' %>
|
4
|
+
|
5
|
+
<%= semantic_form_for @membership do |form| -%>
|
6
|
+
<%= form.inputs do -%>
|
7
|
+
<%= form.input :admin %>
|
8
|
+
<%= form.input :projects, :as => :check_boxes, :collection => @projects %>
|
9
|
+
<% end -%>
|
10
|
+
<%= form.buttons do -%>
|
11
|
+
<%= form.commit_button "Update" %>
|
12
|
+
<li><%= link_to "Remove from account",
|
13
|
+
@membership,
|
14
|
+
:method => :delete,
|
15
|
+
:confirm => "Are you sure?" %></li>
|
16
|
+
<% end -%>
|
17
|
+
<% end -%>
|
18
|
+
|
@@ -3,10 +3,10 @@
|
|
3
3
|
<%= render :partial => 'accounts/tab_bar' %>
|
4
4
|
|
5
5
|
<ul class="users">
|
6
|
-
<% @
|
7
|
-
<%= content_tag_for :li, user do -%>
|
8
|
-
<%= link_to
|
9
|
-
<%=
|
6
|
+
<% @memberships.each do |membership| -%>
|
7
|
+
<%= content_tag_for :li, membership.user do -%>
|
8
|
+
<%= link_to [:edit, membership] do %>
|
9
|
+
<%= membership.name %> (<%= membership.email %>)
|
10
10
|
<% end -%>
|
11
11
|
<% end -%>
|
12
12
|
<% end -%>
|
data/config/routes.rb
CHANGED
@@ -3,11 +3,10 @@ Rails.application.routes.draw do
|
|
3
3
|
resources :projects, :only => [:new, :create, :index, :show]
|
4
4
|
resources :memberships, :only => [:index]
|
5
5
|
resources :invitations, :only => [:new, :create]
|
6
|
-
resources :users, :only => [] do
|
7
|
-
resource :permissions, :only => [:edit, :update]
|
8
|
-
end
|
9
6
|
end
|
10
7
|
|
8
|
+
resources :memberships, :only => [:edit, :update, :destroy]
|
9
|
+
|
11
10
|
resources :plans, :only => [:index] do
|
12
11
|
resources :accounts, :only => [:new, :create]
|
13
12
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
@puts @announce
|
1
|
+
@disable-bundler @puts @announce
|
2
2
|
Feature: generate a saucy application and run rake
|
3
3
|
|
4
4
|
Background:
|
@@ -16,9 +16,10 @@ Feature: generate a saucy application and run rake
|
|
16
16
|
gem "rspec-rails"
|
17
17
|
gem "bourne"
|
18
18
|
gem "shoulda"
|
19
|
+
gem "launchy"
|
19
20
|
"""
|
20
21
|
When I add the "saucy" gem from this project as a dependency
|
21
|
-
And I successfully run "bundle install"
|
22
|
+
And I successfully run "bundle install --local"
|
22
23
|
And I bootstrap the application for clearance
|
23
24
|
|
24
25
|
Scenario: generate a saucy application and run rake
|
@@ -70,4 +71,4 @@ Feature: generate a saucy application and run rake
|
|
70
71
|
"""
|
71
72
|
0 failures
|
72
73
|
"""
|
73
|
-
Then
|
74
|
+
Then at least one example should have run
|
@@ -22,7 +22,7 @@ Factory.define :account do |f|
|
|
22
22
|
f.url { Factory.next(:name) }
|
23
23
|
end
|
24
24
|
|
25
|
-
Factory.define :
|
25
|
+
Factory.define :membership do |f|
|
26
26
|
f.association :user
|
27
27
|
f.association :account
|
28
28
|
end
|
@@ -40,9 +40,9 @@ Factory.define :project do |f|
|
|
40
40
|
f.association :account
|
41
41
|
end
|
42
42
|
|
43
|
-
Factory.define :
|
44
|
-
f.association :
|
45
|
-
f.project {|a| a.association(:project, :account => a.
|
43
|
+
Factory.define :permission do |f|
|
44
|
+
f.association :membership
|
45
|
+
f.project {|a| a.association(:project, :account => a.membership.account)}
|
46
46
|
end
|
47
47
|
|
48
48
|
Factory.define :invitation do |f|
|
@@ -1,15 +1,18 @@
|
|
1
1
|
Given /^I (?:am signed in|sign in) as an admin of the "([^"]+)" project$/ do |project_name|
|
2
2
|
project = Project.find_by_name!(project_name)
|
3
3
|
user = Factory(:email_confirmed_user)
|
4
|
-
Factory(:
|
5
|
-
|
4
|
+
membership = Factory(:membership, :user => user,
|
5
|
+
:account => project.account,
|
6
|
+
:admin => true)
|
7
|
+
Factory(:permission, :membership => membership,
|
8
|
+
:project => project)
|
6
9
|
When %{I sign in as "#{user.email}"}
|
7
10
|
end
|
8
11
|
|
9
12
|
Given /^I am signed in as an admin of the "([^"]*)" account$/ do |account_name|
|
10
13
|
account = Account.find_by_name!(account_name)
|
11
14
|
user = Factory(:email_confirmed_user)
|
12
|
-
Factory(:
|
15
|
+
Factory(:membership, :user => user,
|
13
16
|
:account => account,
|
14
17
|
:admin => true)
|
15
18
|
When %{I sign in as "#{user.email}"}
|
@@ -1,20 +1,22 @@
|
|
1
1
|
Given /^"([^"]*)" is a member of the "([^"]*)" project$/ do |email, project_name|
|
2
2
|
user = User.find_by_email!(email)
|
3
3
|
project = Project.find_by_name!(project_name)
|
4
|
-
Factory(:
|
5
|
-
|
4
|
+
membership = Factory(:membership, :user => user,
|
5
|
+
:account => project.account)
|
6
|
+
Factory(:permission, :membership => membership,
|
7
|
+
:project => project)
|
6
8
|
end
|
7
9
|
|
8
10
|
Given /^"([^"]*)" is a member of the "([^"]*)" account/ do |email, account_name|
|
9
11
|
user = User.find_by_email!(email)
|
10
12
|
account = Account.find_by_name!(account_name)
|
11
|
-
Factory(:
|
13
|
+
Factory(:membership, :user => user, :account => account)
|
12
14
|
end
|
13
15
|
|
14
16
|
Given /^"([^"]*)" is an admin of the "([^"]*)" account/ do |email, account_name|
|
15
17
|
user = User.find_by_email!(email)
|
16
18
|
account = Account.find_by_name!(account_name)
|
17
|
-
Factory(:
|
19
|
+
Factory(:membership, :user => user, :account => account, :admin => true)
|
18
20
|
end
|
19
21
|
|
20
22
|
Then /^the user "([^"]*)" should be an admin of "([^"]*)"$/ do |email, account_name|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class CreateSaucyTables < ActiveRecord::Migration
|
2
2
|
def self.up
|
3
|
-
create_table :
|
3
|
+
create_table :memberships do |table|
|
4
4
|
table.integer :account_id
|
5
5
|
table.integer :user_id
|
6
6
|
table.boolean :admin
|
@@ -8,7 +8,7 @@ class CreateSaucyTables < ActiveRecord::Migration
|
|
8
8
|
table.datetime :updated_at
|
9
9
|
end
|
10
10
|
|
11
|
-
add_index :
|
11
|
+
add_index :memberships, [:account_id, :user_id], :unique => true
|
12
12
|
|
13
13
|
create_table :accounts do |table|
|
14
14
|
table.belongs_to :plan
|
@@ -29,14 +29,16 @@ class CreateSaucyTables < ActiveRecord::Migration
|
|
29
29
|
|
30
30
|
add_index :invitations, [:account_id]
|
31
31
|
|
32
|
-
create_table :
|
32
|
+
create_table :permissions do |table|
|
33
|
+
table.integer :membership_id
|
33
34
|
table.integer :user_id
|
34
35
|
table.integer :project_id
|
35
36
|
table.datetime :created_at
|
36
37
|
table.datetime :updated_at
|
37
38
|
end
|
38
39
|
|
39
|
-
add_index :
|
40
|
+
add_index :permissions, [:user_id, :project_id]
|
41
|
+
add_index :permissions, [:membership_id, :project_id], :name => [:membership_and_project]
|
40
42
|
|
41
43
|
create_table :projects do |table|
|
42
44
|
table.string :name
|
@@ -63,10 +65,10 @@ class CreateSaucyTables < ActiveRecord::Migration
|
|
63
65
|
remove_column :users, :name
|
64
66
|
drop_table :plans
|
65
67
|
drop_table :projects
|
66
|
-
drop_table :
|
68
|
+
drop_table :permissions
|
67
69
|
drop_table :invitations
|
68
70
|
drop_table :accounts
|
69
|
-
drop_table :
|
71
|
+
drop_table :memberships
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|