Commit 528fc939ada3802df4ded58fb3b1c71f10a1da71

Authored by Victor Costa
2 parents fa1fe7cf 79d84c01

Merge branch 'fix_multitenancy' into staging

Conflicts:
	config/application.rb
@@ -81,7 +81,7 @@ group :cucumber do @@ -81,7 +81,7 @@ group :cucumber do
81 gem 'cucumber' 81 gem 'cucumber'
82 gem 'cucumber-rails', '~> 1.4.2', :require => false 82 gem 'cucumber-rails', '~> 1.4.2', :require => false
83 gem 'database_cleaner', '~> 1.3' 83 gem 'database_cleaner', '~> 1.3'
84 - gem 'selenium-webdriver' 84 + gem 'selenium-webdriver', '>= 2.50'
85 end 85 end
86 86
87 # Requires custom dependencies 87 # Requires custom dependencies
app/controllers/application_controller.rb
@@ -3,7 +3,6 @@ require 'noosfero/multi_tenancy' @@ -3,7 +3,6 @@ require 'noosfero/multi_tenancy'
3 class ApplicationController < ActionController::Base 3 class ApplicationController < ActionController::Base
4 #protect_from_forgery 4 #protect_from_forgery
5 5
6 - before_filter :setup_multitenancy  
7 before_filter :detect_stuff_by_domain 6 before_filter :detect_stuff_by_domain
8 before_filter :init_noosfero_plugins 7 before_filter :init_noosfero_plugins
9 before_filter :allow_cross_domain_access 8 before_filter :allow_cross_domain_access
@@ -111,10 +110,6 @@ class ApplicationController &lt; ActionController::Base @@ -111,10 +110,6 @@ class ApplicationController &lt; ActionController::Base
111 #super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN']) 110 #super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN'])
112 end 111 end
113 112
114 - def setup_multitenancy  
115 - Noosfero::MultiTenancy.setup!(request.host)  
116 - end  
117 -  
118 def boxes_editor? 113 def boxes_editor?
119 false 114 false
120 end 115 end
@@ -137,12 +132,11 @@ class ApplicationController &lt; ActionController::Base @@ -137,12 +132,11 @@ class ApplicationController &lt; ActionController::Base
137 @domain = Domain.find_by_name(request.host) 132 @domain = Domain.find_by_name(request.host)
138 if @domain.nil? 133 if @domain.nil?
139 @environment = Environment.default 134 @environment = Environment.default
140 - if @environment.nil? && Rails.env.development?  
141 - # This should only happen in development ... 135 + # Avoid crashes on test and development setups
  136 + if @environment.nil? && !Rails.env.production?
142 @environment = Environment.new 137 @environment = Environment.new
143 @environment.name = "Noosfero" 138 @environment.name = "Noosfero"
144 @environment.is_default = true 139 @environment.is_default = true
145 - @environment.save!  
146 end 140 end
147 else 141 else
148 @environment = @domain.environment 142 @environment = @domain.environment
config/application.rb
@@ -15,6 +15,9 @@ module Noosfero @@ -15,6 +15,9 @@ module Noosfero
15 15
16 require 'noosfero/plugin' 16 require 'noosfero/plugin'
17 17
  18 + require 'noosfero/multi_tenancy'
  19 + config.middleware.use Noosfero::MultiTenancy::Middleware
  20 +
18 # Adds custom attributes to the Set of allowed html attributes for the #sanitize helper 21 # Adds custom attributes to the Set of allowed html attributes for the #sanitize helper
19 config.action_view.sanitized_allowed_attributes = 'align', 'border', 'alt', 'vspace', 'hspace', 'width', 'heigth', 'value', 'type', 'data', 'style', 'target', 'codebase', 'archive', 'classid', 'code', 'flashvars', 'scrolling', 'frameborder', 'controls', 'autoplay', 'colspan', 'rowspan', 'usemap', 'shape', 'coords' 22 config.action_view.sanitized_allowed_attributes = 'align', 'border', 'alt', 'vspace', 'hspace', 'width', 'heigth', 'value', 'type', 'data', 'style', 'target', 'codebase', 'archive', 'classid', 'code', 'flashvars', 'scrolling', 'frameborder', 'controls', 'autoplay', 'colspan', 'rowspan', 'usemap', 'shape', 'coords'
20 23
features/edit_article.feature
@@ -90,7 +90,7 @@ Feature: edit article @@ -90,7 +90,7 @@ Feature: edit article
90 And I fill in "Title" with "My Folder" 90 And I fill in "Title" with "My Folder"
91 And I choose "article_published_false" 91 And I choose "article_published_false"
92 And I uncheck "article_show_to_followers" 92 And I uncheck "article_show_to_followers"
93 - Then I should see "Fill in the search field to add the exception users to see this content" 93 + Then I should see "Allow only community members entered below to view this content"
94 94
95 @selenium 95 @selenium
96 Scenario: allowed user should see the content of a folder 96 Scenario: allowed user should see the content of a folder
features/forum.feature
@@ -79,7 +79,7 @@ Feature: forum @@ -79,7 +79,7 @@ Feature: forum
79 | joaosilva | Forum One | 79 | joaosilva | Forum One |
80 And I go to /joaosilva/forum-one 80 And I go to /joaosilva/forum-one
81 When I follow "Configure forum" 81 When I follow "Configure forum"
82 - And I fill in "Description" with "My description" 82 + And I fill in tinyMCE "article_body" with "My description"
83 And I check "Has terms of use:" 83 And I check "Has terms of use:"
84 And I press "Save" 84 And I press "Save"
85 Then I should see "Forum One" 85 Then I should see "Forum One"
@@ -95,7 +95,7 @@ Feature: forum @@ -95,7 +95,7 @@ Feature: forum
95 | mariasilva | Maria Silva | 95 | mariasilva | Maria Silva |
96 And I go to /joaosilva/forum-one 96 And I go to /joaosilva/forum-one
97 When I follow "Configure forum" 97 When I follow "Configure forum"
98 - And I fill in "Description" with "My description" 98 + And I fill in tinyMCE "article_body" with "My description"
99 And I check "Has terms of use:" 99 And I check "Has terms of use:"
100 And I press "Save" 100 And I press "Save"
101 When I follow "New discussion topic" 101 When I follow "New discussion topic"
@@ -118,7 +118,7 @@ Feature: forum @@ -118,7 +118,7 @@ Feature: forum
118 | mariasilva | Maria Silva | 118 | mariasilva | Maria Silva |
119 And I go to /joaosilva/forum-one 119 And I go to /joaosilva/forum-one
120 When I follow "Configure forum" 120 When I follow "Configure forum"
121 - And I fill in "Description" with "My description" 121 + And I fill in tinyMCE "article_body" with "My description"
122 And I check "Has terms of use:" 122 And I check "Has terms of use:"
123 And I press "Save" 123 And I press "Save"
124 When I follow "Logout" 124 When I follow "Logout"
@@ -135,7 +135,7 @@ Feature: forum @@ -135,7 +135,7 @@ Feature: forum
135 | joaosilva | Forum One | 135 | joaosilva | Forum One |
136 And I go to /joaosilva/forum-one 136 And I go to /joaosilva/forum-one
137 When I follow "Configure forum" 137 When I follow "Configure forum"
138 - And I fill in "Description" with "My description" 138 + And I fill in tinyMCE "article_body" with "My description"
139 And I check "Has terms of use:" 139 And I check "Has terms of use:"
140 And I press "Save" 140 And I press "Save"
141 When I follow "Logout" 141 When I follow "Logout"
features/media_panel_upload_files.feature
@@ -94,20 +94,17 @@ Feature: uploads items on media panel @@ -94,20 +94,17 @@ Feature: uploads items on media panel
94 94
95 @selenium 95 @selenium
96 Scenario: select type when create new folder 96 Scenario: select type when create new folder
97 - When I follow "Show/Hide"  
98 - And I follow "New folder"  
99 - And I choose "Folder" within "#new-folder-dialog"  
100 - And I fill in "Name" with "Main new folder" within "#new-folder-dialog"  
101 - And I press "Create" 97 + Given I follow "Show/Hide"
  98 + And I follow "New folder"
  99 + And I choose "Folder" within "#new-folder-dialog"
  100 + And I fill in "Name" with "Main new folder" within "#new-folder-dialog"
  101 + When I press "Create"
102 Then I should see "joaosilva/Gallery/Main new folder" within "#parent_id" 102 Then I should see "joaosilva/Gallery/Main new folder" within "#parent_id"
103 - When I follow "New folder"  
104 - And I choose "Gallery" within "#new-folder-dialog"  
105 - And I fill in "Name" with "Gallery new folder" within "#new-folder-dialog"  
106 - And I press "Create"  
107 - And I go to joaosilva's cms  
108 - And I follow "Gallery"  
109 - Then I should see "Folder" within "tr[title='Main new folder'] td.article-mime"  
110 - And I should see "Gallery" within "tr[title='Gallery new folder'] td.article-mime" 103 + Given I follow "New folder"
  104 + And I choose "Gallery" within "#new-folder-dialog"
  105 + And I fill in "Name" with "Gallery new folder" within "#new-folder-dialog"
  106 + When I press "Create"
  107 + Then I should see "joaosilva/Gallery/Gallery new folder" within "#parent_id"
111 108
112 @selenium 109 @selenium
113 Scenario: hide and show upload list 110 Scenario: hide and show upload list
features/step_definitions/web_steps.rb
@@ -39,7 +39,22 @@ end @@ -39,7 +39,22 @@ end
39 39
40 When /^(?:|I )follow "([^"]*)"(?: within "([^"]*)")?$/ do |link, selector| 40 When /^(?:|I )follow "([^"]*)"(?: within "([^"]*)")?$/ do |link, selector|
41 with_scope(selector) do 41 with_scope(selector) do
42 - click_link(link, :match => :prefer_exact) 42 + begin
  43 + click_link(link, :match => :prefer_exact)
  44 + rescue Selenium::WebDriver::Error::UnknownError => selenium_error
  45 + if selenium_error.message.start_with? 'Element is not clickable at point'
  46 + href = find_link(link)[:href]
  47 +
  48 + warn "#{selenium_error.message}\n\n"\
  49 + "Trying to overcome this by redirecting you to the link's href:\n"\
  50 + "\t'#{href}'\n\n"\
  51 + "Good luck and be careful that this may produce hidden links to work on tests!\n"
  52 +
  53 + visit href
  54 + else
  55 + raise selenium_error
  56 + end
  57 + end
43 end 58 end
44 end 59 end
45 60
@@ -107,6 +122,7 @@ When /^(?:|I )attach the file &quot;([^&quot;]*)&quot; to &quot;([^&quot;]*)&quot;(?: within &quot;([^&quot;]*)&quot;)?$/ do @@ -107,6 +122,7 @@ When /^(?:|I )attach the file &quot;([^&quot;]*)&quot; to &quot;([^&quot;]*)&quot;(?: within &quot;([^&quot;]*)&quot;)?$/ do
107 with_scope(selector) do 122 with_scope(selector) do
108 attach_file(field, path) 123 attach_file(field, path)
109 end 124 end
  125 + sleep 1
110 end 126 end
111 127
112 Then /^(?:|I )should see JSON:$/ do |expected_json| 128 Then /^(?:|I )should see JSON:$/ do |expected_json|
@@ -260,6 +276,10 @@ Then /^display &quot;([^\&quot;]*)&quot;$/ do |element| @@ -260,6 +276,10 @@ Then /^display &quot;([^\&quot;]*)&quot;$/ do |element|
260 evaluate_script("jQuery('#{element}').show() && false;") 276 evaluate_script("jQuery('#{element}').show() && false;")
261 end 277 end
262 278
  279 +Then /^I fill in tinyMCE "(.*?)" with "(.*?)"$/ do |field, content|
  280 + execute_script("$(tinymce.editors['#{field}'].setContent('#{content}'))")
  281 +end
  282 +
263 Then /^there should be a div with class "([^"]*)"$/ do |klass| 283 Then /^there should be a div with class "([^"]*)"$/ do |klass|
264 should have_selector("div.#{klass}") 284 should have_selector("div.#{klass}")
265 end 285 end
lib/noosfero/multi_tenancy.rb
@@ -22,6 +22,18 @@ module Noosfero @@ -22,6 +22,18 @@ module Noosfero
22 end 22 end
23 end 23 end
24 24
  25 + class Middleware
  26 + def initialize(app)
  27 + @app = app
  28 + end
  29 +
  30 + def call(env)
  31 + request = Rack::Request.new(env)
  32 + Noosfero::MultiTenancy.setup!(request.host)
  33 + @app.call(env)
  34 + end
  35 + end
  36 +
25 private 37 private
26 38
27 def self.load_map 39 def self.load_map
test/functional/application_controller_test.rb
@@ -478,30 +478,6 @@ class ApplicationControllerTest &lt; ActionController::TestCase @@ -478,30 +478,6 @@ class ApplicationControllerTest &lt; ActionController::TestCase
478 assert_response :forbidden 478 assert_response :forbidden
479 end 479 end
480 480
481 - if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'  
482 -  
483 - should 'change postgresql schema' do  
484 - uses_host 'schema1.com'  
485 - Noosfero::MultiTenancy.expects(:on?).returns(true)  
486 - Noosfero::MultiTenancy.expects(:mapping).returns({ 'schema1.com' => 'schema1' }).at_least_once  
487 - exception = assert_raise(ActiveRecord::StatementInvalid) { get :index }  
488 -  
489 - # we have switched to a new database schema; depending on the PostgreSQL  
490 - # version, we will receive either an error message because the schema  
491 - # does not exist, or an error saying that whatever table we need can't be  
492 - # found.  
493 - assert_match /(SET search_path TO schema1|PG::UndefinedTable)/, exception.message  
494 - end  
495 -  
496 - should 'not change postgresql schema if multitenancy is off' do  
497 - uses_host 'schema1.com'  
498 - Noosfero::MultiTenancy.stubs(:on?).returns(false)  
499 - Noosfero::MultiTenancy.stubs(:mapping).returns({ 'schema1.com' => 'schema1' })  
500 - assert_nothing_raised(ActiveRecord::StatementInvalid) { get :index }  
501 - end  
502 -  
503 - end  
504 -  
505 should 'register search_term occurrence on find_by_contents' do 481 should 'register search_term occurrence on find_by_contents' do
506 controller = ApplicationController.new 482 controller = ApplicationController.new
507 controller.stubs(:environment).returns(Environment.default) 483 controller.stubs(:environment).returns(Environment.default)
test/integration/multi_tenancy_test.rb 0 → 100644
@@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
  1 +require_relative "../test_helper"
  2 +
  3 +class MultiTenancyTest < ActionDispatch::IntegrationTest
  4 +
  5 + should 'change postgresql schema' do
  6 + host! 'schema1.com'
  7 + Noosfero::MultiTenancy.expects(:on?).at_least_once.returns(true)
  8 + Noosfero::MultiTenancy.expects(:mapping).returns({ 'schema1.com' => 'schema1' }).at_least_once
  9 + exception = assert_raise(ActiveRecord::StatementInvalid) { get '/' }
  10 +
  11 + # we have switched to a new database schema; depending on the PostgreSQL
  12 + # version, we will receive either an error message because the schema
  13 + # does not exist, or an error saying that whatever table we need can't be
  14 + # found.
  15 + assert_match /(SET search_path TO schema1|PG::UndefinedTable)/, exception.message
  16 + end
  17 +
  18 + should 'not change postgresql schema if multitenancy is off' do
  19 + host! 'schema1.com'
  20 + Noosfero::MultiTenancy.stubs(:on?).returns(false)
  21 + Noosfero::MultiTenancy.stubs(:mapping).returns({ 'schema1.com' => 'schema1' })
  22 + assert_nothing_raised(ActiveRecord::StatementInvalid) { get '/' }
  23 + end
  24 +
  25 + should 'find session from the correct database schema' do
  26 + Noosfero::MultiTenancy.expects(:on?).at_least_once.returns(true)
  27 + Noosfero::MultiTenancy.expects(:mapping).returns({ 'schema2.com' => 'public', 'schema1.com' => 'schema1' }).at_least_once
  28 +
  29 + user = create_user
  30 + session_obj = create(Session, user_id: user.id, session_id: 'some_id', data: {})
  31 + person_identifier = user.person.identifier
  32 +
  33 + Noosfero::MultiTenancy.setup!('schema1.com')
  34 + host! 'schema2.com'
  35 + cookies[:_noosfero_session] = session_obj.session_id
  36 + assert_nothing_raised { get "/myprofile/#{person_identifier}" }
  37 + assert_equal 'public', ActiveRecord::Base.connection.schema_search_path
  38 + end
  39 +
  40 +end