kaui 0.7.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -2
  4. data/Gemfile.lock +59 -38
  5. data/README.md +12 -9
  6. data/Rakefile +9 -0
  7. data/{lib/generators/kaui/install/templates/app/assets/javascripts/kaui/all.js → app/assets/javascripts/application.js} +2 -5
  8. data/{lib/generators/kaui/install/templates/app/assets/stylesheets/kaui/all.css → app/assets/stylesheets/application.css} +0 -4
  9. data/app/assets/stylesheets/bootstrap_and_overrides.css +7 -0
  10. data/app/controllers/kaui/admin_allowed_users_controller.rb +48 -0
  11. data/app/controllers/kaui/admin_tenants_controller.rb +97 -0
  12. data/app/controllers/kaui/engine_controller.rb +28 -31
  13. data/app/controllers/kaui/engine_controller_util.rb +33 -0
  14. data/app/controllers/kaui/login_proxy_controller.rb +11 -0
  15. data/app/controllers/kaui/sessions_controller.rb +12 -0
  16. data/app/controllers/kaui/tenants_controller.rb +60 -0
  17. data/app/models/kaui/ability.rb +20 -3
  18. data/app/models/kaui/admin_tenant.rb +10 -0
  19. data/app/models/kaui/allowed_user.rb +8 -0
  20. data/app/models/kaui/allowed_user_tenant.rb +6 -0
  21. data/app/models/kaui/killbill_authenticatable.rb +5 -18
  22. data/app/models/kaui/tenant.rb +13 -0
  23. data/app/models/kaui/user.rb +14 -16
  24. data/app/views/kaui/admin_allowed_users/index.html.erb +23 -0
  25. data/app/views/kaui/admin_allowed_users/new.html.erb +22 -0
  26. data/app/views/kaui/admin_allowed_users/show.html.erb +53 -0
  27. data/app/views/kaui/admin_tenants/index.html.erb +25 -0
  28. data/app/views/kaui/admin_tenants/new.html.erb +32 -0
  29. data/app/views/kaui/admin_tenants/show.html.erb +68 -0
  30. data/app/views/kaui/invoices/show.html.erb +1 -1
  31. data/app/views/kaui/tenants/index.html.erb +17 -0
  32. data/config/initializers/killbill_authenticatable.rb +3 -5
  33. data/config/locales/en.bootstrap.yml +18 -0
  34. data/config/routes.rb +27 -1
  35. data/config/symmetric-encryption.yml +135 -0
  36. data/db/ddl.sql +33 -2
  37. data/db/migrate/20130812155313_devise_create_kaui_users.rb +1 -3
  38. data/db/migrate/20150109214021_create_kaui_tenants.rb +12 -0
  39. data/db/migrate/20150112232813_create_kaui_allowed_users.rb +19 -0
  40. data/kaui.gemspec +5 -3
  41. data/lib/kaui.rb +49 -1
  42. data/lib/kaui/version.rb +1 -1
  43. data/test/dummy/config/application.rb +3 -0
  44. data/test/dummy/config/database.yml +9 -0
  45. data/test/dummy/config/environments/development.rb +2 -2
  46. data/test/dummy/config/initializers/killbill_client.rb +2 -0
  47. data/test/dummy/config/symmetric-encryption.yml +135 -0
  48. data/test/dummy/db/migrate/{20130819152643_devise_create_kaui_users.kaui.rb → 20150116052157_devise_create_kaui_users.kaui.rb} +1 -3
  49. data/test/dummy/db/migrate/20150116052158_create_kaui_tenants.kaui.rb +13 -0
  50. data/test/dummy/db/migrate/20150116052159_create_kaui_allowed_users.kaui.rb +20 -0
  51. data/test/dummy/db/schema.rb +29 -3
  52. data/test/functional/kaui/admin_allowed_users_controller_test.rb +30 -0
  53. data/test/functional/kaui/admin_tenants_controller_test.rb +35 -0
  54. data/test/functional/kaui/functional_test_helper.rb +2 -50
  55. data/test/functional/kaui/functional_test_helper_nosetup.rb +53 -0
  56. data/test/functional/kaui/invoices_controller_test.rb +22 -0
  57. data/test/functional/kaui/tenants_controller_test.rb +60 -0
  58. data/test/integration/kaui/integration_test_helper.rb +2 -0
  59. data/test/integration/kaui/navigation_test.rb +1 -2
  60. data/test/killbill_test_helper.rb +46 -4
  61. data/test/test_helper.rb +1 -0
  62. data/test/unit/helpers/kaui/admin_allowed_users_helper_test.rb +6 -0
  63. data/test/unit/helpers/kaui/admin_tenants_helper_test.rb +6 -0
  64. data/test/unit/helpers/kaui/tenants_helper_test.rb +6 -0
  65. data/test/unit/kaui/allowed_user_test.rb +34 -0
  66. data/test/unit/kaui/tenant_test.rb +19 -0
  67. data/vendor/assets/javascripts/jquery.dataTables.min.js +155 -0
  68. metadata +86 -21
  69. data/app/assets/javascripts/kaui/analytics.js +0 -71
  70. data/app/assets/stylesheets/kaui/analytics.css +0 -30
  71. data/test/dummy/app/assets/javascripts/application.js +0 -21
  72. data/test/dummy/app/assets/stylesheets/application.css +0 -15
  73. data/test/dummy/app/views/layouts/application.html.erb +0 -48
  74. data/vendor/assets/javascripts/js/bootstrap-datepicker.cd46d38.js +0 -1211
  75. data/vendor/assets/javascripts/js/bootstrap.v2.2.1.min.js +0 -6
  76. data/vendor/assets/javascripts/js/jquery.dataTables.v1.9.3.min.js +0 -156
@@ -1,18 +1,16 @@
1
1
  class Kaui::EngineController < ApplicationController
2
- before_filter :authenticate_user!
2
+
3
+ include Kaui::EngineControllerUtil
4
+
5
+ before_filter :authenticate_user!, :check_for_redirect_to_tenant_screen
3
6
 
4
7
  layout :get_layout
5
8
 
6
9
  # Common options for the Kill Bill client
7
10
  def options_for_klient(options = {})
8
- {
9
- # TODO Kaui doesn't support multi-tenancy yet
10
- :api_key => KillBillClient.api_key,
11
- :api_secret => KillBillClient.api_secret,
12
- :username => current_user.kb_username || KillBillClient.username,
13
- :password => current_user.password || KillBillClient.password,
14
- :session_id => current_user.kb_session_id
15
- }.merge(options)
11
+ user_tenant_options = Kaui.current_tenant_user_options(current_user, session)
12
+ user_tenant_options.merge(options)
13
+ user_tenant_options
16
14
  end
17
15
 
18
16
  # Used for auditing purposes
@@ -20,38 +18,37 @@ class Kaui::EngineController < ApplicationController
20
18
  super
21
19
  end
22
20
 
21
+
23
22
  def current_ability
24
23
  # Redefined here to namespace Ability in the correct module
25
24
  @current_ability ||= Kaui::Ability.new(current_user)
26
25
  end
27
26
 
28
- protected
29
-
30
- def as_string(e)
31
- if e.is_a?(KillBillClient::API::ResponseError)
32
- "Error #{e.response.code}: #{as_string_from_response(e.response.body)}"
33
- else
34
- e.message
27
+ def check_for_redirect_to_tenant_screen
28
+ if !Kaui.is_user_assigned_valid_tenant?(current_user, session)
29
+ flash[:error] = "No tenants configured for users AND KillBillClient.api_key, KillBillClient.api_secret have not been set"
30
+ session[:kb_tenant_id] = nil
31
+ redirect_to Kaui.tenant_home_path.call and return
35
32
  end
36
33
  end
37
34
 
38
- def as_string_from_response(response)
39
- error_message = response
40
- begin
41
- # BillingExceptionJson?
42
- error_message = JSON.parse response
43
- rescue => e
44
- end
45
35
 
46
- if error_message.respond_to? :[] and error_message['message'].present?
47
- # Likely BillingExceptionJson
48
- error_message = error_message['message']
36
+ private
37
+
38
+ def current_tenant_user
39
+ user = current_user
40
+ kb_tenant_id = session[:kb_tenant_id]
41
+ user_tenant = Kaui::Tenant.find_by_kb_tenant_id(kb_tenant_id) if kb_tenant_id
42
+ result = {
43
+ :username => user.kb_username,
44
+ :password => user.password,
45
+ :session_id => user.kb_session_id,
46
+ }
47
+ if user_tenant
48
+ result[:api_key] = user_tenant.api_key
49
+ result[:api_secret] = user_tenant.api_secret
49
50
  end
50
- # Limit the error size to avoid ActionDispatch::Cookies::CookieOverflow
51
- error_message[0..1000]
51
+ result
52
52
  end
53
53
 
54
- def get_layout
55
- layout ||= Kaui.config[:layout]
56
- end
57
54
  end
@@ -0,0 +1,33 @@
1
+ module Kaui::EngineControllerUtil
2
+
3
+ protected
4
+
5
+ def get_layout
6
+ layout ||= Kaui.config[:layout]
7
+ end
8
+
9
+ def as_string(e)
10
+ if e.is_a?(KillBillClient::API::ResponseError)
11
+ "Error #{e.response.code}: #{as_string_from_response(e.response.body)}"
12
+ else
13
+ e.message
14
+ end
15
+ end
16
+
17
+ def as_string_from_response(response)
18
+ error_message = response
19
+ begin
20
+ # BillingExceptionJson?
21
+ error_message = JSON.parse response
22
+ rescue => e
23
+ end
24
+
25
+ if error_message.respond_to? :[] and error_message['message'].present?
26
+ # Likely BillingExceptionJson
27
+ error_message = error_message['message']
28
+ end
29
+ # Limit the error size to avoid ActionDispatch::Cookies::CookieOverflow
30
+ error_message[0..1000]
31
+ end
32
+
33
+ end
@@ -0,0 +1,11 @@
1
+ module Kaui
2
+ class LoginProxyController < Kaui::EngineController
3
+
4
+ def check_login
5
+ #
6
+ # Redirect to where we come from after going through all the Kaui filters ensuring correct authentication and kb_tenant_id
7
+ #
8
+ redirect_to params['path']
9
+ end
10
+ end
11
+ end
@@ -2,5 +2,17 @@ module Kaui
2
2
  # Subclassed to specify the correct layout
3
3
  class SessionsController < Devise::SessionsController
4
4
  layout Kaui.config[:layout]
5
+
6
+ skip_before_filter :check_for_redirect_to_tenant_screen
7
+
8
+ protected
9
+
10
+ # Override after_sign_in_path_for to not have to rely on the default 'root' config which we want to keep on home#index
11
+ def after_sign_in_path_for(resource)
12
+ # Clear the tenant_id from the cookie to not rely on old cookie data
13
+ session[:kb_tenant_id] = nil
14
+ Kaui.tenant_home_path.call
15
+ end
16
+
5
17
  end
6
18
  end
@@ -0,0 +1,60 @@
1
+ module Kaui
2
+ class TenantsController < Kaui::EngineController
3
+
4
+ skip_before_filter :check_for_redirect_to_tenant_screen
5
+
6
+ def index
7
+ begin
8
+
9
+ # Retrieve current user and extract allowed list of tenants
10
+ user = current_user
11
+ allowed_user = Kaui::AllowedUser.find_by_kb_username(user.kb_username)
12
+ @tenants = (allowed_user.kaui_tenants if allowed_user) || []
13
+
14
+ #
15
+ # If there is nothing we check for override with KillBillClient.api_key/KillBillClient.api_secret
16
+ # If there is only one, we skip the tenant screen since the choice is obvious
17
+ # If not, we allow user to chose what he wants
18
+ #
19
+ case @tenants.size
20
+ when 0
21
+ # If KillBillClient.api_key and KillBillClient.api_secret are not set, the client library will throw
22
+ # an KillBillClient::API::Unauthorized exception which will end up in the rescue below
23
+ tenant = KillBillClient::Model::Tenant.find_by_api_key(KillBillClient.api_key, {
24
+ :session_id => user.kb_session_id
25
+ })
26
+ kb_tenant_id = tenant.tenant_id if tenant.present?
27
+ select_tenant_for_tenant_id(kb_tenant_id)
28
+ when 1
29
+ # If there is only one tenant defined we skip the screen and set the tenant for the user
30
+ select_tenant_for_tenant_id(@tenants[0].kb_tenant_id)
31
+ else
32
+ # Jump to default view allowing to chose which tenant to pick
33
+ respond_to do |format|
34
+ format.html # index.html.erb
35
+ format.json { render :json => @tenants }
36
+ end
37
+ end
38
+ rescue => e
39
+ flash[:error] = "Error while retrieving tenants: No tenants configured for users AND KillBillClient.api_key, KillBillClient.api_secret have not been set"
40
+ @tenants = []
41
+ # We then display the view with NO tenants and the flash error so user understands he does not have any configured tenants available
42
+ end
43
+
44
+ end
45
+
46
+ def select_tenant
47
+ kb_tenant_id = params[:kb_tenant_id]
48
+ select_tenant_for_tenant_id(kb_tenant_id)
49
+ end
50
+
51
+ private
52
+
53
+ def select_tenant_for_tenant_id(kb_tenant_id)
54
+ # Set kb_tenant_id in the session
55
+ session[:kb_tenant_id] = kb_tenant_id
56
+ redirect_to Kaui.home_path.call
57
+ end
58
+
59
+ end
60
+ end
@@ -7,19 +7,36 @@ module Kaui
7
7
  user.permissions.each do |permission|
8
8
  # permission is something like invoice:item_adjust or payment:refund
9
9
  # We rely on a naming convention where the left part refers to a Kaui model
10
- model, action = permission.split(':')
10
+ model, action = permission_to_model_action(permission)
11
11
  if model == '*' and action == '*'
12
12
  # All permissions!
13
13
  can :manage, :all
14
14
  elsif model == '*' and action != '*'
15
15
  # TODO
16
16
  elsif action == '*'
17
- can :all, ('Kaui::' + model.capitalize).constantize rescue nil
17
+ # TODO Not sure the :all is really working (but we don't use it)
18
+ can :all, ('Kaui::' + model.camelize).constantize rescue nil
18
19
  else
19
- can action.to_sym, ('Kaui::' + model.capitalize).constantize rescue nil
20
+ can action.to_sym, ('Kaui::' + model.camelize).constantize rescue nil
20
21
  end
21
22
  end
22
23
  rescue KillBillClient::API::Unauthorized => e
23
24
  end
25
+
26
+ def permission_to_model_action(permission)
27
+ #
28
+ # Permissions are defined in Kill Kill apis (https://github.com/killbill/killbill-api/blob/master/src/main/java/org/killbill/billing/security/Permission.java)
29
+ # and they look something like 'invoice:item_adjust' or 'payment:refund', where the first part is the Kill Bill module and the second the action.
30
+ #
31
+ # For most of those the Kill Bill module maps to the Kaui model, but for a few, the naming convention breaks, so in order to keep the API clean, we do the fix up
32
+ # in KAUI itself:
33
+ #
34
+ to_be_model, action = permission.split(':')
35
+ # Currently the only actions implemented for overdue and catalog (upload_config) are those implemented at the tenant level:
36
+ if to_be_model == 'tenant' || 'overdue' || 'catalog'
37
+ to_be_model = 'admin_tenant'
38
+ end
39
+ [to_be_model, action]
40
+ end
24
41
  end
25
42
  end
@@ -0,0 +1,10 @@
1
+ class Kaui::AdminTenant < KillBillClient::Model::Tenant
2
+
3
+
4
+ class << self
5
+ def upload_catalog(catalog_xml, user = nil, reason = nil, comment = nil, options = {})
6
+ KillBillClient::Model::Catalog.upload_tenant_catalog(catalog_xml, user, reason, comment, options)
7
+ end
8
+ end
9
+
10
+ end
@@ -0,0 +1,8 @@
1
+ module Kaui
2
+ class AllowedUser < ActiveRecord::Base
3
+ attr_accessible :kb_username, :description
4
+
5
+ has_many :kaui_allowed_user_tenants, :class_name => 'Kaui::AllowedUserTenant', :foreign_key => 'kaui_allowed_user_id'
6
+ has_many :kaui_tenants, :through => :kaui_allowed_user_tenants, :source => :kaui_tenant, :uniq => true
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ module Kaui
2
+ class AllowedUserTenant < ActiveRecord::Base
3
+ belongs_to :kaui_allowed_user, :class_name => 'Kaui::AllowedUser', :foreign_key => 'kaui_allowed_user_id'
4
+ belongs_to :kaui_tenant, :class_name => 'Kaui::Tenant', :foreign_key => 'kaui_tenant_id'
5
+ end
6
+ end
@@ -5,10 +5,10 @@ module Devise
5
5
  module KillbillAuthenticatable
6
6
  extend ActiveSupport::Concern
7
7
 
8
- def valid_killbill_password?(kb_username, kb_password, api_key, api_secret)
8
+ def valid_killbill_password?(kb_username, kb_password)
9
9
  # Simply try to look-up the permissions for that user - this will
10
10
  # Take care of the auth part
11
- response = Kaui::User.find_permissions(kb_username, kb_password, api_key, api_secret)
11
+ response = Kaui::User.find_permissions(kb_username, kb_password)
12
12
  # Auth was successful, update the session id
13
13
  self.kb_session_id = response.session_id
14
14
  true
@@ -24,22 +24,9 @@ module Devise
24
24
 
25
25
  # Invoked by the KillbillAuthenticatable strategy to lookup the user
26
26
  # before attempting authentication
27
- def find_for_killbill_authentication(kb_username, kb_password, api_key, api_secret)
28
- kb_tenant_id = nil
29
-
30
- # Only in the Multi-Tenancy usecase
31
- if api_key.present?
32
- tenant = KillBillClient::Model::Tenant.find_by_api_key api_key, {
33
- :username => kb_username,
34
- :password => kb_password,
35
- :api_key => api_key,
36
- :api_secret => api_secret
37
- }
38
- kb_tenant_id = tenant.tenant_id if tenant.present?
39
- end
40
-
41
- find_for_authentication(:kb_tenant_id => kb_tenant_id, :kb_username => kb_username) ||
42
- new(:kb_tenant_id => kb_tenant_id, :kb_username => kb_username)
27
+ def find_for_killbill_authentication(kb_username)
28
+ find_for_authentication(:kb_username => kb_username) ||
29
+ new(:kb_username => kb_username)
43
30
  rescue KillBillClient::API::Unauthorized => e
44
31
  # Multi-Tenancy was enabled, but the tenant_id couldn't be retrieved because of bad credentials
45
32
  nil
@@ -0,0 +1,13 @@
1
+ require 'symmetric-encryption'
2
+
3
+ module Kaui
4
+ class Tenant < ActiveRecord::Base
5
+
6
+ attr_accessible :name, :api_key, :api_secret, :kb_tenant_id
7
+ attr_encrypted :api_secret
8
+
9
+ has_many :kaui_allowed_user_tenants, :class_name => 'Kaui::AllowedUserTenant', :foreign_key => 'kaui_tenant_id'
10
+ has_many :kaui_allowed_users, :through => :kaui_allowed_user_tenants, :source => :kaui_allowed_user
11
+
12
+ end
13
+ end
@@ -7,33 +7,31 @@ module Kaui
7
7
  # Managed by Devise
8
8
  attr_accessor :password
9
9
 
10
- attr_accessible :kb_tenant_id, :kb_username, :kb_session_id, :password
10
+ attr_accessible :kb_username, :kb_session_id, :password
11
11
 
12
12
  # Called by Devise to perform authentication
13
13
  # Throws KillBillClient::API::Unauthorized on failure
14
- def self.find_permissions(kb_username, kb_password, api_key=KillBillClient.api_key, api_secret=KillBillClient.api_secret)
14
+ def self.find_permissions(kb_username, kb_password)
15
15
  do_find_permissions :username => kb_username,
16
- :password => kb_password,
17
- :api_key => api_key,
18
- :api_secret => api_secret
16
+ :password => kb_password
19
17
  end
20
18
 
21
19
  # Called by CanCan to perform authorization
22
20
  # Throws KillBillClient::API::Unauthorized on failure
23
- def permissions(api_key=KillBillClient.api_key, api_secret=KillBillClient.api_secret)
24
- User.do_find_permissions :session_id => kb_session_id,
25
- :api_key => api_key,
26
- :api_secret => api_secret
21
+ def permissions()
22
+ User.do_find_permissions :session_id => kb_session_id
27
23
  end
28
24
 
29
25
  # Verify the Kill Bill session hasn't timed-out
30
- def authenticated_with_killbill?(api_key=KillBillClient.api_key, api_secret=KillBillClient.api_secret)
31
- subject = KillBillClient::Model::Security.find_subject :session_id => kb_session_id,
32
- :api_key => api_key,
33
- :api_secret => api_secret
34
- subject.is_authenticated
35
- rescue KillBillClient::API::Unauthorized => e
36
- false
26
+ def authenticated_with_killbill?()
27
+
28
+ begin
29
+ subject = KillBillClient::Model::Security.find_subject :session_id => kb_session_id
30
+ result = subject.is_authenticated
31
+ return result
32
+ rescue KillBillClient::API::Unauthorized => e
33
+ false
34
+ end
37
35
  end
38
36
 
39
37
  private
@@ -0,0 +1,23 @@
1
+ <% if can? :view, Kaui::AdminTenant %>
2
+ <% unless @allowed_users.empty? %>
3
+ <table id="allowed-users-table" class="table table-condensed">
4
+ <thead>
5
+ <tr>
6
+ <th>Name</th>
7
+ <th>Description</th>
8
+ </tr>
9
+ </thead>
10
+ <tbody>
11
+ <% @allowed_users.each do |u | %>
12
+ <tr>
13
+ <td><%= link_to u.kb_username, admin_allowed_user_path(u.id) %></td>
14
+ <td><%= u.description %></td>
15
+ </tr>
16
+ <% end %>
17
+ </tbody>
18
+ </table>
19
+ <% end %>
20
+ <% end %>
21
+ <% if can? :create, Kaui::AdminTenant %>
22
+ <h3><%= link_to 'Add a new Allowed User', new_admin_allowed_user_path %></h3>
23
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <% if can? :create, Kaui::AdminTenant %>
2
+ <%= form_for @allowed_user, url: admin_allowed_users_path, :html => {:class => 'form-horizontal'} do |f| %>
3
+ <fieldset>
4
+ <div class="control-group">
5
+ <%= f.label :kb_username, 'Name', :class => 'control-label' %>
6
+ <div class="controls">
7
+ <%= f.text_field :kb_username, :class => 'input-small', :required => true %>
8
+ </div>
9
+ </div>
10
+ <div class="control-group">
11
+ <%= f.label :description, 'Description', :class => 'control-label' %>
12
+ <div class="controls">
13
+ <%= f.text_field :description, :class => 'input-small', :required => false %>
14
+ </div>
15
+ </div>
16
+ <div class="form-actions">
17
+ <%= button_tag 'Configure a new Allowed User', :class => 'btn btn-primary' %>
18
+ </div>
19
+ </fieldset>
20
+ <% end %>
21
+ <% end %>
22
+
@@ -0,0 +1,53 @@
1
+ <% if can? :view, Kaui::AdminTenant %>
2
+ <dl class="dl-horizontal">
3
+ <dt>Name:</dt>
4
+ <dd><%= @allowed_user.kb_username %>&nbsp;</dd>
5
+ <dt>Tenant ID:</dt>
6
+ <dd><%= @allowed_user.description %>&nbsp;</dd>
7
+ </dl>
8
+
9
+ <% unless @allowed_user.kaui_tenants.empty? %>
10
+ <h3>Configured tenants:</h3>
11
+ <table id="allowed-user-tenants-table" class="table table-condensed">
12
+ <thead>
13
+ <tr>
14
+ <th>Name</th>
15
+ <th>Tenant Id</th>
16
+ <th>Api Key</th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ <% @allowed_user.kaui_tenants.each do |t| %>
21
+ <tr>
22
+ <td><%= link_to t.name, admin_tenant_path(t.id) %></td>
23
+ <td><%= t.kb_tenant_id %></td>
24
+ <td><%= t.api_key %></td>
25
+ </tr>
26
+ <% end %>
27
+ </tbody>
28
+ </table>
29
+ <% end %>
30
+ <% end %>
31
+
32
+ <% if can? :create, Kaui::AdminTenant %>
33
+ <%= form_for(@allowed_user, :url => {:action => :add_tenant}, :html => {:method => :post, :class => "form-horizontal"}) do |f| %>
34
+
35
+ <fieldset>
36
+ <%= f.hidden_field(:id) %>
37
+ <div class="control-group">
38
+ <%= label_tag :tenant_name, "Available Tenants:", :class => "control-label" %>
39
+ <div class="controls">
40
+ <%= select_tag :tenant_id, options_for_select(@tenants.map { |t| [t.name, t.id] }) %>
41
+ </div>
42
+ </div>
43
+ <div class="form-actions">
44
+ <%= f.submit 'Chose Tenant', :class => 'btn btn-primary' %>
45
+ <%= link_to 'Back', :back, :class => 'btn' %>
46
+ </div>
47
+ </fieldset>
48
+ <% end %>
49
+ <% end %>
50
+
51
+ <div class="form-actions">
52
+ <%= link_to 'Back', :back, :class => 'btn' %>
53
+ </div>