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/lib/saucy/account.rb
CHANGED
@@ -3,12 +3,12 @@ module Saucy
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
has_many :
|
7
|
-
has_many :users, :through => :
|
6
|
+
has_many :memberships, :dependent => :destroy
|
7
|
+
has_many :users, :through => :memberships
|
8
8
|
has_many :projects, :dependent => :destroy
|
9
|
-
has_many :admins, :through => :
|
9
|
+
has_many :admins, :through => :memberships,
|
10
10
|
:source => :user,
|
11
|
-
:conditions => { '
|
11
|
+
:conditions => { 'memberships.admin' => true }
|
12
12
|
|
13
13
|
belongs_to :plan
|
14
14
|
|
@@ -31,7 +31,7 @@ module Saucy
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def has_member?(user)
|
34
|
-
|
34
|
+
memberships.exists?(:user_id => user.id)
|
35
35
|
end
|
36
36
|
|
37
37
|
def users_by_name
|
@@ -45,6 +45,10 @@ module Saucy
|
|
45
45
|
def projects_visible_to(user)
|
46
46
|
projects.visible_to(user)
|
47
47
|
end
|
48
|
+
|
49
|
+
def memberships_by_name
|
50
|
+
memberships.by_name
|
51
|
+
end
|
48
52
|
end
|
49
53
|
end
|
50
54
|
end
|
data/lib/saucy/project.rb
CHANGED
@@ -4,12 +4,19 @@ module Saucy
|
|
4
4
|
|
5
5
|
included do
|
6
6
|
belongs_to :account
|
7
|
-
has_many :
|
8
|
-
has_many :users, :through => :
|
7
|
+
has_many :permissions, :dependent => :destroy
|
8
|
+
has_many :users, :through => :permissions
|
9
9
|
|
10
10
|
validates_presence_of :account_id
|
11
11
|
|
12
12
|
after_create :assign_default_memberships
|
13
|
+
after_save :update_memberships
|
14
|
+
|
15
|
+
# We have to define this here instead of mixing it in,
|
16
|
+
# because ActiveRecord does the same
|
17
|
+
def user_ids=(new_user_ids)
|
18
|
+
@new_user_ids = new_user_ids.reject { |user_id| user_id.blank? }
|
19
|
+
end
|
13
20
|
end
|
14
21
|
|
15
22
|
module ClassMethods
|
@@ -24,14 +31,30 @@ module Saucy
|
|
24
31
|
|
25
32
|
module InstanceMethods
|
26
33
|
def has_member?(user)
|
27
|
-
|
34
|
+
permissions.
|
35
|
+
joins(:membership).
|
36
|
+
exists?(:memberships => { :user_id => user.id })
|
28
37
|
end
|
29
38
|
|
30
39
|
private
|
31
40
|
|
32
41
|
def assign_default_memberships
|
33
|
-
account.
|
34
|
-
self.
|
42
|
+
account.memberships.where(:admin => true).each do |membership|
|
43
|
+
self.permissions.create(:membership => membership)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def update_memberships
|
48
|
+
if @new_user_ids
|
49
|
+
removed_user_ids = self.user_ids - @new_user_ids
|
50
|
+
added_user_ids = @new_user_ids - self.user_ids
|
51
|
+
|
52
|
+
permissions.where(:user_id => removed_user_ids).destroy_all
|
53
|
+
added_user_ids.each do |added_user_id|
|
54
|
+
membership =
|
55
|
+
account.memberships.where(:user_id => added_user_id).first
|
56
|
+
permissions.create!(:membership => membership)
|
57
|
+
end
|
35
58
|
end
|
36
59
|
end
|
37
60
|
end
|
data/lib/saucy/user.rb
CHANGED
@@ -4,28 +4,21 @@ module Saucy
|
|
4
4
|
|
5
5
|
included do
|
6
6
|
attr_accessible :name, :project_ids, :email, :password_confirmation, :password
|
7
|
-
has_many :
|
8
|
-
has_many :
|
9
|
-
has_many :
|
10
|
-
has_many :
|
7
|
+
has_many :memberships
|
8
|
+
has_many :accounts, :through => :memberships
|
9
|
+
has_many :permissions
|
10
|
+
has_many :projects, :through => :permissions
|
11
11
|
validates_presence_of :name
|
12
12
|
end
|
13
13
|
|
14
14
|
module InstanceMethods
|
15
15
|
def admin_of?(account)
|
16
|
-
|
16
|
+
memberships.exists?(:account_id => account.id, :admin => true)
|
17
17
|
end
|
18
18
|
|
19
19
|
def member_of?(account_or_project)
|
20
20
|
account_or_project.has_member?(self)
|
21
21
|
end
|
22
|
-
|
23
|
-
def update_permissions_for(account, project_ids)
|
24
|
-
project_ids_for_other_accounts = projects.
|
25
|
-
reject { |project| project.account_id == account.id }.
|
26
|
-
map { |project| project.id }
|
27
|
-
self.project_ids = project_ids + project_ids_for_other_accounts
|
28
|
-
end
|
29
22
|
end
|
30
23
|
|
31
24
|
module ClassMethods
|
@@ -3,20 +3,30 @@ require 'spec_helper'
|
|
3
3
|
describe MembershipsController, "routes" do
|
4
4
|
it { should route(:get, "/accounts/abc/memberships").
|
5
5
|
to(:action => :index, :account_id => 'abc') }
|
6
|
+
it { should route(:get, "/memberships/abc/edit").
|
7
|
+
to(:action => :edit, :id => 'abc') }
|
8
|
+
it { should route(:put, "/memberships/abc").
|
9
|
+
to(:action => :update, :id => 'abc') }
|
10
|
+
it { should route(:delete, "/memberships/abc").
|
11
|
+
to(:action => :destroy, :id => 'abc') }
|
6
12
|
end
|
7
13
|
|
8
14
|
describe MembershipsController, "permissions", :as => :account_member do
|
15
|
+
let(:membership) { Factory(:membership, :account => account) }
|
9
16
|
it { should deny_access.
|
10
17
|
on(:get, :index, :account_id => account.to_param).
|
11
18
|
flash(/admin/) }
|
19
|
+
it { should deny_access.
|
20
|
+
on(:get, :edit, :id => membership.to_param).
|
21
|
+
flash(/admin/) }
|
12
22
|
end
|
13
23
|
|
14
24
|
describe MembershipsController, "index", :as => :account_admin do
|
15
|
-
let(:
|
25
|
+
let(:memberships) { [Factory.stub(:membership), Factory.stub(:membership)] }
|
16
26
|
|
17
27
|
before do
|
18
28
|
Account.stubs(:find_by_url! => account)
|
19
|
-
account.stubs(:
|
29
|
+
account.stubs(:memberships_by_name => memberships)
|
20
30
|
get :index, :account_id => account.to_param
|
21
31
|
end
|
22
32
|
|
@@ -25,9 +35,81 @@ describe MembershipsController, "index", :as => :account_admin do
|
|
25
35
|
should render_template(:index)
|
26
36
|
end
|
27
37
|
|
28
|
-
it "assigns
|
29
|
-
account.should have_received(:
|
30
|
-
should assign_to(:
|
38
|
+
it "assigns memberships by name" do
|
39
|
+
account.should have_received(:memberships_by_name)
|
40
|
+
should assign_to(:memberships).with(memberships)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe MembershipsController, "edit", :as => :account_admin do
|
45
|
+
let(:edited_membership) { Factory.stub(:membership, :account => account) }
|
46
|
+
let(:projects) { [Factory.stub(:project)] }
|
47
|
+
|
48
|
+
before do
|
49
|
+
Membership.stubs(:find => edited_membership)
|
50
|
+
account.stubs(:projects_by_name => projects)
|
51
|
+
get :edit, :id => edited_membership.to_param
|
52
|
+
end
|
53
|
+
|
54
|
+
it "renders the edit template" do
|
55
|
+
should respond_with(:success)
|
56
|
+
should render_template(:edit)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "assigns projects by name" do
|
60
|
+
account.should have_received(:projects_by_name)
|
61
|
+
should assign_to(:projects).with(projects)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "assigns the membership being edited" do
|
65
|
+
Membership.should have_received(:find).with(edited_membership.to_param,
|
66
|
+
:include => :account)
|
67
|
+
should assign_to(:membership).with(edited_membership)
|
31
68
|
end
|
32
69
|
end
|
33
70
|
|
71
|
+
describe MembershipsController, "update", :as => :account_admin do
|
72
|
+
let(:edited_membership) { Factory.stub(:membership, :account => account) }
|
73
|
+
let(:attributes) { 'some attributes' }
|
74
|
+
|
75
|
+
before do
|
76
|
+
Membership.stubs(:find => edited_membership)
|
77
|
+
edited_membership.stubs(:update_attributes!)
|
78
|
+
put :update, :id => edited_membership.to_param,
|
79
|
+
:membership => attributes
|
80
|
+
end
|
81
|
+
|
82
|
+
it "redirects to the account memberships index" do
|
83
|
+
should redirect_to(account_memberships_url(account))
|
84
|
+
end
|
85
|
+
|
86
|
+
it "update the membership" do
|
87
|
+
edited_membership.should have_received(:update_attributes!).with(attributes)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "sets a flash message" do
|
91
|
+
should set_the_flash.to(/update/i)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe MembershipsController, "destroy", :as => :account_admin do
|
96
|
+
let(:removed_membership) { Factory.stub(:membership, :account => account) }
|
97
|
+
|
98
|
+
before do
|
99
|
+
Membership.stubs(:find => removed_membership)
|
100
|
+
removed_membership.stubs(:destroy)
|
101
|
+
delete :destroy, :id => removed_membership.to_param
|
102
|
+
end
|
103
|
+
|
104
|
+
it "redirects to the account memberships index" do
|
105
|
+
should redirect_to(account_memberships_url(account))
|
106
|
+
end
|
107
|
+
|
108
|
+
it "removes the membership" do
|
109
|
+
removed_membership.should have_received(:destroy)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "sets a flash message" do
|
113
|
+
should set_the_flash.to(/remove/i)
|
114
|
+
end
|
115
|
+
end
|
data/spec/environment.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
PROJECT_ROOT = File.expand_path("../..", __FILE__)
|
2
|
+
$LOAD_PATH << File.join(PROJECT_ROOT, "lib")
|
3
|
+
|
4
|
+
require 'rails/all'
|
5
|
+
require 'saucy'
|
6
|
+
require 'clearance'
|
7
|
+
require 'factory_girl'
|
8
|
+
require 'bourne'
|
9
|
+
|
10
|
+
class ApplicationController < ActionController::Base
|
11
|
+
include Clearance::Authentication
|
12
|
+
include Saucy::AccountAuthorization
|
13
|
+
end
|
14
|
+
|
15
|
+
class ProjectsController < ApplicationController
|
16
|
+
include Saucy::ProjectsController
|
17
|
+
end
|
18
|
+
|
19
|
+
class User < ActiveRecord::Base
|
20
|
+
include Clearance::User
|
21
|
+
include Saucy::User
|
22
|
+
end
|
23
|
+
|
24
|
+
module Testapp
|
25
|
+
class Application < Rails::Application
|
26
|
+
config.action_mailer.default_url_options = { :host => 'localhost' }
|
27
|
+
config.encoding = "utf-8"
|
28
|
+
config.paths.config.database = "spec/scaffold/config/database.yml"
|
29
|
+
config.paths.app.models << "lib/generators/saucy/install/templates/models"
|
30
|
+
config.paths.config.routes << "spec/scaffold/config/routes.rb"
|
31
|
+
config.paths.app.views << "spec/scaffold/views"
|
32
|
+
config.paths.log = "tmp/log"
|
33
|
+
config.cache_classes = true
|
34
|
+
config.whiny_nils = true
|
35
|
+
config.consider_all_requests_local = true
|
36
|
+
config.action_controller.perform_caching = false
|
37
|
+
config.action_dispatch.show_exceptions = false
|
38
|
+
config.action_controller.allow_forgery_protection = false
|
39
|
+
config.action_mailer.delivery_method = :test
|
40
|
+
config.active_support.deprecation = :stderr
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
Testapp::Application.initialize!
|
45
|
+
|
46
|
+
require "lib/generators/saucy/features/templates/factories"
|
47
|
+
require "lib/generators/saucy/install/templates/create_saucy_tables"
|
48
|
+
|
49
|
+
class ClearanceCreateUsers < ActiveRecord::Migration
|
50
|
+
def self.up
|
51
|
+
create_table(:users) do |t|
|
52
|
+
t.string :email
|
53
|
+
t.string :encrypted_password, :limit => 128
|
54
|
+
t.string :salt, :limit => 128
|
55
|
+
t.string :confirmation_token, :limit => 128
|
56
|
+
t.string :remember_token, :limit => 128
|
57
|
+
t.boolean :email_confirmed, :default => false, :null => false
|
58
|
+
t.timestamps
|
59
|
+
end
|
60
|
+
|
61
|
+
add_index :users, :email
|
62
|
+
add_index :users, :remember_token
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class ClearanceMailer
|
67
|
+
def self.change_password(user)
|
68
|
+
new
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.confirmation(user)
|
72
|
+
new
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.deliver_change_password(user)
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.deliver_confirmation(user)
|
79
|
+
end
|
80
|
+
|
81
|
+
def deliver
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
Clearance.configure do |config|
|
86
|
+
end
|
87
|
+
|
88
|
+
FileUtils.rm_f(File.join(PROJECT_ROOT, 'tmp', 'test.sqlite3'))
|
89
|
+
ClearanceCreateUsers.suppress_messages { ClearanceCreateUsers.migrate(:up) }
|
90
|
+
CreateSaucyTables.suppress_messages { CreateSaucyTables.migrate(:up) }
|
91
|
+
|
data/spec/models/account_spec.rb
CHANGED
@@ -3,8 +3,8 @@ require 'spec_helper'
|
|
3
3
|
describe Account do
|
4
4
|
subject { Factory(:account) }
|
5
5
|
|
6
|
-
it { should have_many(:
|
7
|
-
it { should have_many(:users).through(:
|
6
|
+
it { should have_many(:memberships) }
|
7
|
+
it { should have_many(:users).through(:memberships) }
|
8
8
|
it { should have_many(:projects) }
|
9
9
|
|
10
10
|
it { should validate_uniqueness_of(:name) }
|
@@ -39,9 +39,9 @@ describe Account do
|
|
39
39
|
non_admin = Factory(:user)
|
40
40
|
non_member = Factory(:user)
|
41
41
|
admins.each do |admin|
|
42
|
-
Factory(:
|
42
|
+
Factory(:membership, :user => admin, :account => subject, :admin => true)
|
43
43
|
end
|
44
|
-
Factory(:
|
44
|
+
Factory(:membership, :user => non_admin, :account => subject, :admin => false)
|
45
45
|
|
46
46
|
result = subject.admins
|
47
47
|
|
@@ -49,13 +49,24 @@ describe Account do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
it "has a member with a membership" do
|
52
|
-
membership = Factory(:
|
52
|
+
membership = Factory(:membership, :account => subject)
|
53
53
|
should have_member(membership.user)
|
54
54
|
end
|
55
55
|
|
56
56
|
it "doesn't have a member without a membership" do
|
57
|
-
membership = Factory(:
|
57
|
+
membership = Factory(:membership, :account => subject)
|
58
58
|
should_not have_member(Factory(:user))
|
59
59
|
end
|
60
|
+
|
61
|
+
it "finds memberships by name" do
|
62
|
+
expected = 'expected result'
|
63
|
+
memberships = stub('memberships', :by_name => expected)
|
64
|
+
account = Factory.stub(:account)
|
65
|
+
account.stubs(:memberships => memberships)
|
66
|
+
|
67
|
+
result = account.memberships_by_name
|
68
|
+
|
69
|
+
result.should == expected
|
70
|
+
end
|
60
71
|
end
|
61
72
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Membership do
|
4
|
+
it { should belong_to(:account) }
|
5
|
+
it { should belong_to(:user) }
|
6
|
+
it { should validate_presence_of(:account_id) }
|
7
|
+
it { should validate_presence_of(:user_id) }
|
8
|
+
it { should have_many(:permissions) }
|
9
|
+
it { should have_many(:projects).through(:permissions) }
|
10
|
+
|
11
|
+
describe "given an existing account membership" do
|
12
|
+
before { Factory(:membership) }
|
13
|
+
it { should validate_uniqueness_of(:user_id).scoped_to(:account_id) }
|
14
|
+
end
|
15
|
+
|
16
|
+
it "delegates the user's name" do
|
17
|
+
user = Factory(:user)
|
18
|
+
membership = Factory(:membership, :user => user)
|
19
|
+
|
20
|
+
membership.name.should == user.name
|
21
|
+
end
|
22
|
+
|
23
|
+
it "delegates the user's email" do
|
24
|
+
user = Factory(:user)
|
25
|
+
membership = Factory(:membership, :user => user)
|
26
|
+
|
27
|
+
membership.email.should == user.email
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns memberships by name" do
|
31
|
+
Factory(:membership, :user => Factory(:user, :name => "def"))
|
32
|
+
Factory(:membership, :user => Factory(:user, :name => "abc"))
|
33
|
+
Factory(:membership, :user => Factory(:user, :name => "ghi"))
|
34
|
+
|
35
|
+
Membership.by_name.map(&:name).should == %w(abc def ghi)
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Permission do
|
4
|
+
it { should belong_to(:project) }
|
5
|
+
it { should belong_to(:membership) }
|
6
|
+
it { should belong_to(:user) }
|
7
|
+
|
8
|
+
it "caches the user from the account membership" do
|
9
|
+
membership = Factory(:membership)
|
10
|
+
permission = Factory(:permission,
|
11
|
+
:membership => membership)
|
12
|
+
permission.user_id.should == membership.user_id
|
13
|
+
end
|
14
|
+
|
15
|
+
it "doesn't allow the user to be assigned" do
|
16
|
+
expect { subject.user = Factory.build(:user) }.to raise_error
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
data/spec/models/project_spec.rb
CHANGED
@@ -3,18 +3,19 @@ require 'spec_helper'
|
|
3
3
|
describe Project do
|
4
4
|
it { should belong_to(:account) }
|
5
5
|
it { should validate_presence_of(:account_id) }
|
6
|
-
it { should have_many(:
|
7
|
-
it { should have_many(:users) }
|
6
|
+
it { should have_many(:permissions) }
|
7
|
+
it { should have_many(:users).through(:permissions) }
|
8
8
|
|
9
9
|
it "finds projects visible to a user" do
|
10
10
|
account = Factory(:account)
|
11
11
|
user = Factory(:user)
|
12
|
-
Factory(:
|
12
|
+
membership = Factory(:membership, :user => user, :account => account)
|
13
13
|
visible_projects = [Factory(:project, :account => account),
|
14
14
|
Factory(:project, :account => account)]
|
15
15
|
invisible_project = Factory(:project, :account => account)
|
16
16
|
visible_projects.each do |visible_project|
|
17
|
-
Factory(:
|
17
|
+
Factory(:permission, :project => visible_project,
|
18
|
+
:membership => membership)
|
18
19
|
end
|
19
20
|
|
20
21
|
Project.visible_to(user).to_a.should =~ visible_projects
|
@@ -38,12 +39,12 @@ describe Project, "for an account with admin and non-admin users" do
|
|
38
39
|
subject { Factory(:project, :account => account) }
|
39
40
|
|
40
41
|
before do
|
41
|
-
Factory(:
|
42
|
-
Factory(:
|
42
|
+
Factory(:membership, :account => account, :user => non_admin, :admin => false)
|
43
|
+
Factory(:membership, :account => other_account,
|
43
44
|
:user => non_member,
|
44
45
|
:admin => true)
|
45
46
|
admins.each do |admin|
|
46
|
-
Factory(:
|
47
|
+
Factory(:membership, :user => admin, :account => account, :admin => true)
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
@@ -68,8 +69,10 @@ describe Project, "saved" do
|
|
68
69
|
|
69
70
|
it "has a member with a membership" do
|
70
71
|
user = Factory(:user)
|
71
|
-
Factory(:
|
72
|
-
|
72
|
+
membership = Factory(:membership, :account => subject.account,
|
73
|
+
:user => user)
|
74
|
+
membership = Factory(:permission, :project => subject,
|
75
|
+
:membership => membership)
|
73
76
|
should have_member(user)
|
74
77
|
end
|
75
78
|
|
@@ -78,3 +81,30 @@ describe Project, "saved" do
|
|
78
81
|
should_not have_member(user)
|
79
82
|
end
|
80
83
|
end
|
84
|
+
|
85
|
+
describe Project, "assigning a new user list" do
|
86
|
+
subject { Factory(:project) }
|
87
|
+
|
88
|
+
let(:account) { subject.account }
|
89
|
+
let!(:member) { Factory(:user) }
|
90
|
+
let!(:non_member) { Factory(:user) }
|
91
|
+
|
92
|
+
before do
|
93
|
+
member_membership =
|
94
|
+
Factory(:membership, :account => account, :user => member)
|
95
|
+
non_member_membership =
|
96
|
+
Factory(:membership, :account => account, :user => non_member)
|
97
|
+
Factory(:permission, :membership => member_membership,
|
98
|
+
:project => subject)
|
99
|
+
|
100
|
+
subject.reload.update_attributes!(:user_ids => [non_member.id, ""])
|
101
|
+
end
|
102
|
+
|
103
|
+
it "adds an added user" do
|
104
|
+
member.should_not be_member_of(subject)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "removes a removed user" do
|
108
|
+
non_member.should be_member_of(subject)
|
109
|
+
end
|
110
|
+
end
|