saucy 0.15.2 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. data/.gitignore +2 -0
  2. data/CHANGELOG.md +3 -7
  3. data/Gemfile +1 -10
  4. data/Gemfile.lock +42 -3
  5. data/README.md +5 -0
  6. data/Rakefile +12 -3
  7. data/app/controllers/accounts_controller.rb +2 -1
  8. data/app/mailers/billing_mailer.rb +8 -0
  9. data/app/models/canceled_account.rb +12 -7
  10. data/app/views/accounts/_projects.html.erb +1 -1
  11. data/app/views/billing_mailer/cancelation_notification.text.erb +3 -0
  12. data/app/views/invitation_mailer/invitation.text.erb +1 -1
  13. data/app/views/invitations/show.html.erb +1 -1
  14. data/app/views/memberships/edit.html.erb +2 -2
  15. data/app/views/memberships/index.html.erb +1 -1
  16. data/app/views/projects/_form.html.erb +5 -5
  17. data/app/views/projects/edit.html.erb +2 -2
  18. data/app/views/projects/index.html.erb +3 -3
  19. data/app/views/projects/new.html.erb +1 -1
  20. data/app/views/shared/_project_dropdown.html.erb +3 -3
  21. data/config/routes.rb +2 -6
  22. data/cucumber.yml +1 -0
  23. data/{lib/generators/saucy/features/templates/features → features/engine}/admin_reporting.feature +0 -0
  24. data/{lib/generators/saucy/features/templates/features → features/engine}/edit_profile.feature +0 -0
  25. data/{lib/generators/saucy/features/templates/features → features/engine}/edit_project_permissions.feature +0 -0
  26. data/{lib/generators/saucy/features/templates/features → features/engine}/edit_user_permissions.feature +0 -0
  27. data/{lib/generators/saucy/features/templates/features → features/engine}/manage_account.feature +0 -0
  28. data/{lib/generators/saucy/features/templates/features → features/engine}/manage_billing.feature +1 -1
  29. data/{lib/generators/saucy/features/templates/features → features/engine}/manage_plan.feature +0 -0
  30. data/{lib/generators/saucy/features/templates/features → features/engine}/manage_projects.feature +0 -0
  31. data/{lib/generators/saucy/features/templates/features → features/engine}/manage_users.feature +0 -0
  32. data/{lib/generators/saucy/features/templates/features → features/engine}/new_account.feature +0 -0
  33. data/{lib/generators/saucy/features/templates/features → features/engine}/project_dropdown.feature +0 -0
  34. data/{lib/generators/saucy/features/templates/features → features/engine}/sign_up.feature +0 -0
  35. data/{lib/generators/saucy/features/templates/features → features/engine}/sign_up_coupon.feature +0 -0
  36. data/{lib/generators/saucy/features/templates/features → features/engine}/sign_up_paid.feature +0 -0
  37. data/{lib/generators/saucy/features/templates/features → features/engine}/trial_plans.feature +0 -0
  38. data/features/integration/run_features.feature +46 -0
  39. data/features/step_definitions/clearance_steps.rb +123 -0
  40. data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/account_steps.rb +0 -0
  41. data/features/step_definitions/engine/braintree_steps.rb +24 -0
  42. data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/country_steps.rb +0 -0
  43. data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/cron_steps.rb +3 -5
  44. data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/email_steps.rb +0 -0
  45. data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/factory_girl_steps.rb +0 -0
  46. data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/html_steps.rb +0 -0
  47. data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/plan_steps.rb +0 -0
  48. data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/project_steps.rb +0 -0
  49. data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/session_steps.rb +0 -0
  50. data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/user_steps.rb +0 -0
  51. data/features/step_definitions/rails_steps.rb +26 -8
  52. data/features/step_definitions/saucy_steps.rb +5 -0
  53. data/features/step_definitions/web_steps.rb +253 -0
  54. data/features/support/engine/braintree.rb +5 -0
  55. data/features/support/env.rb +18 -0
  56. data/features/support/factory_girl.rb +2 -0
  57. data/features/support/paths.rb +68 -0
  58. data/features/support/rails.rb +4 -0
  59. data/features/support/selectors.rb +11 -0
  60. data/lib/generators/saucy/features/features_generator.rb +7 -3
  61. data/lib/saucy/account.rb +55 -57
  62. data/lib/saucy/account_authorization.rb +39 -42
  63. data/lib/saucy/plan.rb +14 -16
  64. data/lib/saucy/project.rb +42 -44
  65. data/lib/saucy/projects_controller.rb +53 -55
  66. data/lib/saucy/subscription.rb +189 -191
  67. data/lib/saucy/user.rb +5 -7
  68. data/lib/saucy/version.rb +1 -1
  69. data/saucy.gemspec +21 -5
  70. data/spec/controllers/accounts_controller_spec.rb +2 -1
  71. data/spec/controllers/projects_controller_spec.rb +1 -1
  72. data/spec/dummy/Rakefile +7 -0
  73. data/spec/dummy/app/assets/javascripts/application.js +9 -0
  74. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  75. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  76. data/spec/dummy/app/controllers/homes_controller.rb +2 -0
  77. data/spec/dummy/app/controllers/projects_controller.rb +3 -0
  78. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  79. data/spec/dummy/app/mailers/.gitkeep +0 -0
  80. data/spec/dummy/app/models/.gitkeep +0 -0
  81. data/spec/dummy/app/models/account.rb +3 -0
  82. data/spec/dummy/app/models/plan.rb +3 -0
  83. data/spec/dummy/app/models/project.rb +3 -0
  84. data/spec/dummy/app/models/user.rb +4 -0
  85. data/spec/dummy/app/views/homes/show.html.erb +1 -0
  86. data/spec/dummy/app/views/layouts/application.html.erb +24 -0
  87. data/spec/dummy/config.ru +4 -0
  88. data/spec/dummy/config/application.rb +48 -0
  89. data/spec/dummy/config/boot.rb +10 -0
  90. data/spec/dummy/config/database.yml +25 -0
  91. data/spec/dummy/config/environment.rb +5 -0
  92. data/spec/dummy/config/environments/development.rb +30 -0
  93. data/spec/dummy/config/environments/production.rb +60 -0
  94. data/spec/dummy/config/environments/test.rb +42 -0
  95. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  96. data/spec/dummy/config/initializers/clearance.rb +3 -0
  97. data/spec/dummy/config/initializers/inflections.rb +10 -0
  98. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  99. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  100. data/spec/dummy/config/initializers/session_store.rb +8 -0
  101. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  102. data/spec/dummy/config/locales/en.yml +5 -0
  103. data/spec/dummy/config/routes.rb +59 -0
  104. data/spec/dummy/db/migrate/20120201000751_create_diesel_clearance_users.rb +19 -0
  105. data/spec/dummy/db/migrate/20120201001546_create_saucy_tables.rb +122 -0
  106. data/spec/dummy/db/migrate/20120201001548_create_canceled_accounts.rb +14 -0
  107. data/spec/dummy/lib/assets/.gitkeep +0 -0
  108. data/spec/dummy/log/.gitkeep +0 -0
  109. data/spec/dummy/public/404.html +26 -0
  110. data/spec/dummy/public/422.html +26 -0
  111. data/spec/dummy/public/500.html +26 -0
  112. data/spec/dummy/public/favicon.ico +0 -0
  113. data/spec/dummy/script/rails +6 -0
  114. data/spec/mailers/billing_mailer_spec.rb +12 -2
  115. data/spec/models/canceled_account_spec.rb +8 -6
  116. data/spec/models/subscription_spec.rb +47 -53
  117. data/spec/spec_helper.rb +8 -11
  118. data/spec/support/braintree.rb +2 -4
  119. data/spec/support/factories.rb +1 -0
  120. metadata +447 -125
  121. data/db/migrate/20120206155222_add_subscription_token_to_canceled_accounts.rb +0 -5
  122. data/features/run_features.feature +0 -84
  123. data/lib/generators/saucy/features/templates/step_definitions/braintree_steps.rb +0 -25
  124. data/lib/generators/saucy/features/templates/support/braintree.rb +0 -5
  125. data/lib/generators/saucy/specs/specs_generator.rb +0 -20
  126. data/lib/generators/saucy/specs/templates/support/braintree.rb +0 -5
  127. data/lib/saucy/fake_braintree.rb +0 -134
  128. data/lib/saucy/routing_extensions.rb +0 -116
  129. data/spec/dummy/db/migrate/20120206155222_add_subscription_token_to_canceled_accounts.rb +0 -5
  130. data/spec/environment.rb +0 -98
  131. data/spec/route_extensions_spec.rb +0 -51
  132. data/spec/scaffold/config/database.yml +0 -6
  133. data/spec/scaffold/config/routes.rb +0 -5
  134. data/spec/scaffold/views/layouts/application.html.erb +0 -1
@@ -0,0 +1,5 @@
1
+ require 'fake_braintree'
2
+
3
+ Before do |s|
4
+ FakeBraintree.clear!
5
+ end
@@ -1,7 +1,25 @@
1
+ ENV["RAILS_ROOT"] = File.expand_path("../../../spec/dummy", __FILE__)
2
+ $LOAD_PATH << ENV["RAILS_ROOT"]
3
+
4
+ require 'rails/all'
5
+ require 'formtastic'
6
+ require 'jquery-rails'
7
+ require 'timecop'
8
+ require 'factory_girl'
9
+ require 'capybara'
1
10
  require 'aruba/cucumber'
11
+ require 'cucumber/rails'
2
12
 
3
13
  Before do
4
14
  @aruba_timeout_seconds = 140
5
15
  end
6
16
 
7
17
  PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), "..", ".."))
18
+
19
+ Capybara.save_and_open_page_path = 'tmp'
20
+ Capybara.javascript_driver = :selenium
21
+ Capybara.default_selector = :css
22
+
23
+ ActionController::Base.allow_rescue = false
24
+
25
+ DatabaseCleaner.strategy = :truncation
@@ -0,0 +1,2 @@
1
+ require 'factory_girl'
2
+ require "#{PROJECT_ROOT}/lib/generators/saucy/features/templates/factories"
@@ -0,0 +1,68 @@
1
+ module NavigationHelpers
2
+ # Maps a name to a path. Used by the
3
+ #
4
+ # When /^I go to (.+)$/ do |page_name|
5
+ #
6
+ # step definition in web_steps.rb
7
+ #
8
+ def path_to(page_name)
9
+ case page_name
10
+ when 'the admin page'
11
+ admin_path
12
+ when 'the list of accounts'
13
+ accounts_path
14
+ when 'the list of plans page'
15
+ plans_path
16
+ when /^the memberships page for the "([^"]+)" account$/
17
+ account = Account.find_by_name!($1)
18
+ account_memberships_path(account)
19
+ when /^the projects page for the "([^"]+)" account$/
20
+ account = Account.find_by_name!($1)
21
+ account_projects_path(account)
22
+ when /settings page for the "([^"]+)" account$/i
23
+ account = Account.find_by_name!($1)
24
+ edit_account_path(account)
25
+ when /settings page$/
26
+ edit_profile_path
27
+ when /dashboard page$/
28
+ accounts_path
29
+ when /sign up page for the "([^"]+)" plan$/i
30
+ plan = Plan.find_by_name!($1)
31
+ new_plan_account_path(plan)
32
+ when /^the billing page for the "([^"]+)" account$/
33
+ account = Account.find_by_name!($1)
34
+ account_billing_path(account)
35
+ when /^the upgrade plan page for the "([^"]+)" account$/
36
+ account = Account.find_by_name!($1)
37
+ edit_account_plan_path(account)
38
+ when /^the new project page for the newest account by "([^"]*)"$/
39
+ user = User.find_by_email!($1)
40
+ account = user.accounts.order("id desc").first
41
+ new_account_project_path(account)
42
+ when /^the "([^"]*)" project page$/
43
+ project = Project.find_by_name!($1)
44
+ account_project_path(project.account, project)
45
+ when /^the new project page for the "([^"]+)" account$/
46
+ account = Account.find_by_name!($1)
47
+ new_account_project_path(account)
48
+
49
+
50
+ # Here is an example that pulls values out of the Regexp:
51
+ #
52
+ # when /^(.*)'s profile page$/i
53
+ # user_profile_path(User.find_by_login($1))
54
+
55
+ else
56
+ begin
57
+ page_name =~ /^the (.*) page$/
58
+ path_components = $1.split(/\s+/)
59
+ self.send(path_components.push('path').join('_').to_sym)
60
+ rescue NoMethodError, ArgumentError
61
+ raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
62
+ "Now, go and add a mapping in #{__FILE__}"
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ World(NavigationHelpers)
@@ -0,0 +1,4 @@
1
+ Before("@generates-application") do
2
+ set_env "RAILS_ENV", nil
3
+ set_env "RAILS_ROOT", nil
4
+ end
@@ -0,0 +1,11 @@
1
+ module Selectors
2
+ def selector_for(string)
3
+ if string =~ /^"(.*)"$/
4
+ $1
5
+ else
6
+ raise "Invalid selector: #{string}"
7
+ end
8
+ end
9
+ end
10
+
11
+ World(Selectors)
@@ -10,9 +10,9 @@ Description:
10
10
  DESC
11
11
 
12
12
  def copy_feature_files
13
- directory "features", "features/saucy"
14
- directory "step_definitions", "features/step_definitions/saucy"
15
- directory "support", "features/support/saucy"
13
+ engine_directory "features"
14
+ engine_directory "features/step_definitions"
15
+ engine_directory "features/support"
16
16
  template "README", "features/saucy/README"
17
17
  template "README", "features/step_definitions/saucy/README"
18
18
  empty_directory "spec"
@@ -86,6 +86,10 @@ DESC
86
86
  File.open(path, "w") { |file| file.write(contents) }
87
87
  end
88
88
 
89
+ def engine_directory(prefix)
90
+ directory File.expand_path("../../../#{prefix}/engine"), "#{prefix}/saucy"
91
+ end
92
+
89
93
  end
90
94
  end
91
95
  end
@@ -37,79 +37,77 @@ module Saucy
37
37
  before_destroy :create_canceled_account
38
38
  end
39
39
 
40
- module InstanceMethods
41
- def to_param
42
- keyword
43
- end
40
+ def to_param
41
+ keyword
42
+ end
44
43
 
45
- def has_member?(user)
46
- memberships.exists?(:user_id => user.id)
47
- end
44
+ def has_member?(user)
45
+ memberships.exists?(:user_id => user.id)
46
+ end
48
47
 
49
- def users_by_name
50
- users.by_name
51
- end
48
+ def users_by_name
49
+ users.by_name
50
+ end
52
51
 
53
- def projects_by_name
54
- projects.by_name
55
- end
52
+ def projects_by_name
53
+ projects.by_name
54
+ end
56
55
 
57
- def projects_visible_to(user)
58
- projects.visible_to(user)
59
- end
56
+ def projects_visible_to(user)
57
+ projects.visible_to(user)
58
+ end
60
59
 
61
- def memberships_by_name
62
- memberships.by_name
63
- end
60
+ def memberships_by_name
61
+ memberships.by_name
62
+ end
64
63
 
65
- def expired?
66
- trial? && past_trial?
67
- end
64
+ def expired?
65
+ trial? && past_trial?
66
+ end
68
67
 
69
- def past_trial?
70
- trial_expires_at && trial_expires_at < Time.now
71
- end
68
+ def past_trial?
69
+ trial_expires_at && trial_expires_at < Time.now
70
+ end
72
71
 
73
- def admin_emails
74
- admins.map(&:email)
75
- end
72
+ def admin_emails
73
+ admins.map(&:email)
74
+ end
76
75
 
77
- def set_trial_expiration
78
- number_free_days = if coupon
79
- 30 * coupon.free_months
80
- else
81
- Saucy::Configuration.trial_length
82
- end
83
- self.trial_expires_at = number_free_days.days.from_now(created_at || Time.zone.now)
84
- end
76
+ def set_trial_expiration
77
+ number_free_days = if coupon
78
+ 30 * coupon.free_months
79
+ else
80
+ Saucy::Configuration.trial_length
81
+ end
82
+ self.trial_expires_at = number_free_days.days.from_now(created_at || Time.zone.now)
83
+ end
85
84
 
86
- def reset_trial_expiration(length_in_days = nil)
87
- new_length = length_in_days || Saucy::Configuration.trial_length
88
- new_trial_start_date = [trial_expires_at, Time.zone.now].max
89
- self.trial_expires_at = new_length.days.from_now(new_trial_start_date)
90
- self.notified_of_completed_trial = false
91
- self.notified_of_expiration = false
92
- end
85
+ def reset_trial_expiration(length_in_days = nil)
86
+ new_length = length_in_days || Saucy::Configuration.trial_length
87
+ new_trial_start_date = [trial_expires_at, Time.zone.now].max
88
+ self.trial_expires_at = new_length.days.from_now(new_trial_start_date)
89
+ self.notified_of_completed_trial = false
90
+ self.notified_of_expiration = false
91
+ end
93
92
 
94
- def record_new_activations
95
- if activated_changed? && activated?
96
- Saucy::Notifications.notify_observers("activated", :account => self)
97
- end
93
+ def record_new_activations
94
+ if activated_changed? && activated?
95
+ Saucy::Notifications.notify_observers("activated", :account => self)
98
96
  end
97
+ end
99
98
 
100
- def users_count
101
- users.count
102
- end
99
+ def users_count
100
+ users.count
101
+ end
103
102
 
104
- def projects_count
105
- projects.active.count
106
- end
103
+ def projects_count
104
+ projects.active.count
105
+ end
107
106
 
108
- private
107
+ private
109
108
 
110
- def create_canceled_account
111
- CanceledAccount.create(:account => self)
112
- end
109
+ def create_canceled_account
110
+ CanceledAccount.create(:account => self)
113
111
  end
114
112
 
115
113
  module ClassMethods
@@ -4,63 +4,60 @@ module Saucy
4
4
 
5
5
  included do
6
6
  helper_method :current_account, :current_project, :current_account?, :current_project?
7
- include InstanceMethods
8
7
  end
9
8
 
10
- module InstanceMethods
11
- protected
9
+ protected
12
10
 
13
- def current_account
14
- ::Account.find_by_keyword!(params[:account_id])
15
- end
11
+ def current_account
12
+ ::Account.find_by_keyword!(params[:account_id])
13
+ end
16
14
 
17
- def current_project
18
- current_account.projects.find_by_keyword!(params[:project_id])
19
- end
15
+ def current_project
16
+ current_account.projects.find_by_keyword!(params[:project_id])
17
+ end
20
18
 
21
- def current_project?
22
- params[:project_id].present?
23
- end
19
+ def current_project?
20
+ params[:project_id].present?
21
+ end
24
22
 
25
- def current_account?
26
- params[:account_id].present?
27
- end
23
+ def current_account?
24
+ params[:account_id].present?
25
+ end
28
26
 
29
- def authorize_admin
30
- unless current_user.admin_of?(current_account)
31
- deny_access("You must be an admin to access that page.")
32
- end
27
+ def authorize_admin
28
+ unless current_user.admin_of?(current_account)
29
+ deny_access("You must be an admin to access that page.")
33
30
  end
31
+ end
34
32
 
35
- def authorize_member
36
- unless current_user.member_of?(current_project)
37
- deny_access("You do not have permission for this project.")
38
- end
33
+ def authorize_member
34
+ unless current_user.member_of?(current_project)
35
+ deny_access("You do not have permission for this project.")
39
36
  end
37
+ end
40
38
 
41
- def ensure_active_account
42
- if current_account?
43
- if current_account.past_due?
44
- redirect_unusable_account account_billing_path(current_account),
45
- "past_due"
46
- end
47
- if current_account.expired?
48
- redirect_unusable_account edit_account_plan_path(current_account),
49
- "expired"
50
- end
39
+ def ensure_active_account
40
+ if current_account?
41
+ if current_account.past_due?
42
+ redirect_unusable_account account_billing_path(current_account),
43
+ "past_due"
44
+ end
45
+ if current_account.expired?
46
+ redirect_unusable_account edit_account_plan_path(current_account),
47
+ "expired"
51
48
  end
52
49
  end
50
+ end
53
51
 
54
- def redirect_unusable_account(path, failure)
55
- role = current_user.admin_of?(current_account) ? 'admin' : 'user'
56
- flash[:alert] = t("saucy.errors.#{failure}.#{role}")
57
- redirect_to path
58
- end
52
+ def redirect_unusable_account(path, failure)
53
+ role = current_user.admin_of?(current_account) ? 'admin' : 'user'
54
+ flash[:alert] = t("saucy.errors.#{failure}.#{role}")
55
+ redirect_to path
56
+ end
59
57
 
60
- def ensure_account_within_limit(limit_name)
61
- if !Limit.can_add_one?(limit_name, current_account)
62
- redirect_to edit_account_plan_path(current_account), :alert => t("saucy.errors.limited", :default => "You are at your limit of %{name} for your current plan.", :name => limit_name)
63
- end
58
+ def ensure_account_within_limit(limit_name)
59
+ if !Limit.can_add_one?(limit_name, current_account)
60
+ redirect_to edit_account_plan_path(current_account), :alert => t("saucy.errors.limited", :default => "You are at your limit of %{name} for your current plan.", :name => limit_name)
64
61
  end
65
62
  end
66
63
  end
@@ -29,26 +29,24 @@ module Saucy
29
29
  end
30
30
  end
31
31
 
32
- module InstanceMethods
33
- def free?
34
- price.zero?
35
- end
32
+ def free?
33
+ price.zero?
34
+ end
36
35
 
37
- def billed?
38
- !free?
39
- end
36
+ def billed?
37
+ !free?
38
+ end
40
39
 
41
- def can_add_more?(limit, amount)
42
- limits.numbered.named(limit).value > amount
43
- end
40
+ def can_add_more?(limit, amount)
41
+ limits.numbered.named(limit).value > amount
42
+ end
44
43
 
45
- def allows?(limit)
46
- limits.boolean.named(limit).allowed?
47
- end
44
+ def allows?(limit)
45
+ limits.boolean.named(limit).allowed?
46
+ end
48
47
 
49
- def limit(limit_name)
50
- limits.named(limit_name)
51
- end
48
+ def limit(limit_name)
49
+ limits.named(limit_name)
52
50
  end
53
51
  end
54
52
  end
@@ -65,60 +65,58 @@ module Saucy
65
65
  end
66
66
  end
67
67
 
68
- module InstanceMethods
69
- def to_param
70
- keyword
71
- end
68
+ def to_param
69
+ keyword
70
+ end
72
71
 
73
- def has_member?(user)
74
- permissions.
75
- joins(:membership).
76
- exists?(:memberships => { :user_id => user.id })
77
- end
72
+ def has_member?(user)
73
+ permissions.
74
+ joins(:membership).
75
+ exists?(:memberships => { :user_id => user.id })
76
+ end
78
77
 
79
- def assign_default_permissions
80
- account.memberships.where(:admin => true).each do |membership|
81
- self.permissions.build(:membership => membership)
82
- end
83
- self
78
+ def assign_default_permissions
79
+ account.memberships.where(:admin => true).each do |membership|
80
+ self.permissions.build(:membership => membership)
84
81
  end
82
+ self
83
+ end
85
84
 
86
- private
85
+ private
87
86
 
88
- def setup_memberships
89
- @new_user_ids ||= []
90
- @new_user_ids += admin_user_ids
91
- removed_user_ids = self.user_ids - @new_user_ids
92
- added_user_ids = @new_user_ids - self.user_ids
87
+ def setup_memberships
88
+ @new_user_ids ||= []
89
+ @new_user_ids += admin_user_ids
90
+ removed_user_ids = self.user_ids - @new_user_ids
91
+ added_user_ids = @new_user_ids - self.user_ids
93
92
 
94
- permissions.where(:user_id => removed_user_ids).destroy_all
95
- added_user_ids.each do |added_user_id|
96
- membership =
97
- account.memberships.where(:user_id => added_user_id).first
98
- permissions.create!(:membership => membership)
99
- end
93
+ permissions.where(:user_id => removed_user_ids).destroy_all
94
+ added_user_ids.each do |added_user_id|
95
+ membership =
96
+ account.memberships.where(:user_id => added_user_id).first
97
+ permissions.create!(:membership => membership)
100
98
  end
99
+ end
101
100
 
102
- def update_memberships
103
- setup_memberships if @new_user_ids
104
- end
101
+ def update_memberships
102
+ setup_memberships if @new_user_ids
103
+ end
105
104
 
106
- def admin_user_ids
107
- account.
108
- memberships.
109
- where(:admin => true).
110
- select(:user_id).
111
- map(&:user_id)
112
- end
105
+ def admin_user_ids
106
+ account.
107
+ memberships.
108
+ where(:admin => true).
109
+ select(:user_id).
110
+ map(&:user_id)
111
+ end
113
112
 
114
- def ensure_account_within_limit
115
- message = "You are at your limit of %{name} for your current plan."
116
- if archived_changed? && !archived? && !Limit.can_add_one?("projects", account)
117
- errors.add(:archived, I18n.t("saucy.errors.limited", :default => message, :name => 'projects'))
118
- end
119
- if account_id_changed? && !Limit.can_add_one?("projects", account)
120
- errors.add(:account_id, I18n.t("saucy.errors.limited", :default => message, :name => 'projects'))
121
- end
113
+ def ensure_account_within_limit
114
+ message = "You are at your limit of %{name} for your current plan."
115
+ if archived_changed? && !archived? && !Limit.can_add_one?("projects", account)
116
+ errors.add(:archived, I18n.t("saucy.errors.limited", :default => message, :name => 'projects'))
117
+ end
118
+ if account_id_changed? && !Limit.can_add_one?("projects", account)
119
+ errors.add(:account_id, I18n.t("saucy.errors.limited", :default => message, :name => 'projects'))
122
120
  end
123
121
  end
124
122
  end