Commit 7e85741bd4aca60edc23fa80e96814e026612590
Exists in
production
Merge branch 'staging' into production
Showing
31 changed files
with
232 additions
and
85 deletions
Show diff stats
Gemfile
@@ -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
1 | require 'noosfero/multi_tenancy' | 1 | require 'noosfero/multi_tenancy' |
2 | 2 | ||
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 |
@@ -107,12 +106,7 @@ class ApplicationController < ActionController::Base | @@ -107,12 +106,7 @@ class ApplicationController < ActionController::Base | ||
107 | protected | 106 | protected |
108 | 107 | ||
109 | def verified_request? | 108 | def verified_request? |
110 | - true | ||
111 | - #super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN']) | ||
112 | - end | ||
113 | - | ||
114 | - def setup_multitenancy | ||
115 | - Noosfero::MultiTenancy.setup!(request.host) | 109 | + super || form_authenticity_token == request.headers['X-XSRF-TOKEN'] |
116 | end | 110 | end |
117 | 111 | ||
118 | def boxes_editor? | 112 | def boxes_editor? |
@@ -137,12 +131,11 @@ class ApplicationController < ActionController::Base | @@ -137,12 +131,11 @@ class ApplicationController < ActionController::Base | ||
137 | @domain = Domain.find_by_name(request.host) | 131 | @domain = Domain.find_by_name(request.host) |
138 | if @domain.nil? | 132 | if @domain.nil? |
139 | @environment = Environment.default | 133 | @environment = Environment.default |
140 | - if @environment.nil? && Rails.env.development? | ||
141 | - # This should only happen in development ... | 134 | + # Avoid crashes on test and development setups |
135 | + if @environment.nil? && !Rails.env.production? | ||
142 | @environment = Environment.new | 136 | @environment = Environment.new |
143 | @environment.name = "Noosfero" | 137 | @environment.name = "Noosfero" |
144 | @environment.is_default = true | 138 | @environment.is_default = true |
145 | - @environment.save! | ||
146 | end | 139 | end |
147 | else | 140 | else |
148 | @environment = @domain.environment | 141 | @environment = @domain.environment |
app/controllers/my_profile/memberships_controller.rb
@@ -18,12 +18,14 @@ class MembershipsController < MyProfileController | @@ -18,12 +18,14 @@ class MembershipsController < MyProfileController | ||
18 | 18 | ||
19 | def new_community | 19 | def new_community |
20 | @community = Community.new(params[:community]) | 20 | @community = Community.new(params[:community]) |
21 | + custom_values = params[:profile_data][:custom_values] if (params[:profile_data] && params[:profile_data][:custom_values]) | ||
22 | + @community.custom_values = custom_values | ||
21 | @community.environment = environment | 23 | @community.environment = environment |
22 | @back_to = params[:back_to] || url_for(:action => 'index') | 24 | @back_to = params[:back_to] || url_for(:action => 'index') |
23 | if request.post? && @community.valid? | 25 | if request.post? && @community.valid? |
24 | begin | 26 | begin |
25 | # Community was created | 27 | # Community was created |
26 | - @community = Community.create_after_moderation(user, params[:community].merge({:environment => environment})) | 28 | + @community = Community.create_after_moderation(user, params[:community].merge({:environment => environment, :custom_values => custom_values})) |
27 | @community.reload | 29 | @community.reload |
28 | redirect_to :action => 'welcome', :community_id => @community.id, :back_to => @back_to | 30 | redirect_to :action => 'welcome', :community_id => @community.id, :back_to => @back_to |
29 | rescue ActiveRecord::RecordNotFound | 31 | rescue ActiveRecord::RecordNotFound |
app/controllers/public/account_controller.rb
@@ -6,7 +6,7 @@ class AccountController < ApplicationController | @@ -6,7 +6,7 @@ class AccountController < ApplicationController | ||
6 | before_filter :redirect_if_logged_in, :only => [:login, :signup] | 6 | before_filter :redirect_if_logged_in, :only => [:login, :signup] |
7 | before_filter :protect_from_bots, :only => :signup | 7 | before_filter :protect_from_bots, :only => :signup |
8 | 8 | ||
9 | - #protect_from_forgery except: [:login] | 9 | + protect_from_forgery except: [:login] |
10 | 10 | ||
11 | helper CustomFieldsHelper | 11 | helper CustomFieldsHelper |
12 | # say something nice, you goof! something sweet. | 12 | # say something nice, you goof! something sweet. |
app/models/community.rb
@@ -33,7 +33,7 @@ class Community < Organization | @@ -33,7 +33,7 @@ class Community < Organization | ||
33 | community = Community.new(attributes) | 33 | community = Community.new(attributes) |
34 | community.environment = environment | 34 | community.environment = environment |
35 | if community.environment.enabled?('admin_must_approve_new_communities') | 35 | if community.environment.enabled?('admin_must_approve_new_communities') |
36 | - CreateCommunity.create!(attributes.merge(:requestor => requestor, :environment => environment)) | 36 | + CreateCommunity.create!(attributes.merge(:requestor => requestor, :environment => environment).except(:custom_values)) |
37 | else | 37 | else |
38 | community.save! | 38 | community.save! |
39 | community.add_admin(requestor) | 39 | community.add_admin(requestor) |
app/models/session.rb
1 | class Session < ActiveRecord::SessionStore::Session | 1 | class Session < ActiveRecord::SessionStore::Session |
2 | 2 | ||
3 | - def self.find_by_session_id(session_id) | ||
4 | - where(session_id: session_id).first | 3 | + # removed and redefined on super class |
4 | + def self.find_by_session_id session_id | ||
5 | + super | ||
5 | end | 6 | end |
6 | 7 | ||
7 | belongs_to :user | 8 | belongs_to :user |
app/models/suggest_article.rb
@@ -23,6 +23,10 @@ class SuggestArticle < Task | @@ -23,6 +23,10 @@ class SuggestArticle < Task | ||
23 | requestor ? "#{requestor.name}" : "#{name} (#{email})" | 23 | requestor ? "#{requestor.name}" : "#{name} (#{email})" |
24 | end | 24 | end |
25 | 25 | ||
26 | + def author_name | ||
27 | + sender | ||
28 | + end | ||
29 | + | ||
26 | def article_object | 30 | def article_object |
27 | if @article_object.nil? | 31 | if @article_object.nil? |
28 | @article_object = article_type.new(article.merge(target.present? ? {:profile => target} : {}).except(:type)) | 32 | @article_object = article_type.new(article.merge(target.present? ? {:profile => target} : {}).except(:type)) |
@@ -41,7 +45,6 @@ class SuggestArticle < Task | @@ -41,7 +45,6 @@ class SuggestArticle < Task | ||
41 | return type if type < Article | 45 | return type if type < Article |
42 | end | 46 | end |
43 | TinyMceArticle | 47 | TinyMceArticle |
44 | - (article[:type] || 'TinyMceArticle').constantize | ||
45 | end | 48 | end |
46 | 49 | ||
47 | def perform | 50 | def perform |
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,37 @@ end | @@ -39,7 +39,37 @@ 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 | + link = find_link(link) | ||
47 | + href = link[:href] | ||
48 | + onclick = link[:onClick] | ||
49 | + | ||
50 | + warn "#{selenium_error.message}\n\n"\ | ||
51 | + "Trying to overcome this by:\n" | ||
52 | + | ||
53 | + onclick_return = true | ||
54 | + | ||
55 | + unless onclick.nil? | ||
56 | + warn "\t* Running onClick JS:\n"\ | ||
57 | + "\t\t'#{onclick}'\n" | ||
58 | + onclick_return = page.execute_script onclick | ||
59 | + end | ||
60 | + | ||
61 | + if onclick_return | ||
62 | + warn "\t* Redirecting you to the link's href:\n"\ | ||
63 | + "\t\t'#{href}'\n" | ||
64 | + | ||
65 | + visit href | ||
66 | + end | ||
67 | + | ||
68 | + warn "\nGood luck and be careful that this may produce hidden links to work on tests!\n" | ||
69 | + else | ||
70 | + raise selenium_error | ||
71 | + end | ||
72 | + end | ||
43 | end | 73 | end |
44 | end | 74 | end |
45 | 75 | ||
@@ -107,6 +137,7 @@ When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"(?: within "([^"]*)")?$/ do | @@ -107,6 +137,7 @@ When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"(?: within "([^"]*)")?$/ do | ||
107 | with_scope(selector) do | 137 | with_scope(selector) do |
108 | attach_file(field, path) | 138 | attach_file(field, path) |
109 | end | 139 | end |
140 | + sleep 1 | ||
110 | end | 141 | end |
111 | 142 | ||
112 | Then /^(?:|I )should see JSON:$/ do |expected_json| | 143 | Then /^(?:|I )should see JSON:$/ do |expected_json| |
@@ -260,6 +291,21 @@ Then /^display "([^\"]*)"$/ do |element| | @@ -260,6 +291,21 @@ Then /^display "([^\"]*)"$/ do |element| | ||
260 | evaluate_script("jQuery('#{element}').show() && false;") | 291 | evaluate_script("jQuery('#{element}').show() && false;") |
261 | end | 292 | end |
262 | 293 | ||
294 | +Then /^I fill in tinyMCE "(.*?)" with "(.*?)"$/ do |field, content| | ||
295 | + n = 0 | ||
296 | + begin | ||
297 | + execute_script("tinymce.editors['#{field}'].setContent('#{content}')") | ||
298 | + rescue Selenium::WebDriver::Error::JavascriptError | ||
299 | + n += 1 | ||
300 | + if n < 5 | ||
301 | + sleep 1 | ||
302 | + retry | ||
303 | + else | ||
304 | + raise | ||
305 | + end | ||
306 | + end | ||
307 | +end | ||
308 | + | ||
263 | Then /^there should be a div with class "([^"]*)"$/ do |klass| | 309 | Then /^there should be a div with class "([^"]*)"$/ do |klass| |
264 | should have_selector("div.#{klass}") | 310 | should have_selector("div.#{klass}") |
265 | end | 311 | end |
lib/acts_as_customizable.rb
@@ -90,7 +90,7 @@ module Customizable | @@ -90,7 +90,7 @@ module Customizable | ||
90 | custom_values.each_pair do |key, value| | 90 | custom_values.each_pair do |key, value| |
91 | custom_field = environment.custom_fields.detect{|cf|cf.name==key} | 91 | custom_field = environment.custom_fields.detect{|cf|cf.name==key} |
92 | next if custom_field.blank? | 92 | next if custom_field.blank? |
93 | - custom_field_value = self.custom_field_values.detect{|cv| cv.custom_field.name==key} | 93 | + custom_field_value = self.custom_field_values(true).detect{|cv| cv.custom_field.name==key} |
94 | 94 | ||
95 | if custom_field_value.nil? | 95 | if custom_field_value.nil? |
96 | custom_field_value = CustomFieldValue.new | 96 | custom_field_value = CustomFieldValue.new |
lib/authenticated_system.rb
@@ -23,17 +23,6 @@ module AuthenticatedSystem | @@ -23,17 +23,6 @@ module AuthenticatedSystem | ||
23 | def current_user | 23 | def current_user |
24 | @current_user ||= begin | 24 | @current_user ||= begin |
25 | id = session[:user] | 25 | id = session[:user] |
26 | - | ||
27 | - session_id = cookies[:_noosfero_session] | ||
28 | - if id.blank? && session_id.present? | ||
29 | - Session.connection.clear_query_cache | ||
30 | - session_obj = Session.where(session_id: session_id).first | ||
31 | - if session_obj.present? | ||
32 | - session = session_obj.data | ||
33 | - id = session_obj.user_id | ||
34 | - end | ||
35 | - end | ||
36 | - | ||
37 | user = User.where(id: id).first if id | 26 | user = User.where(id: id).first if id |
38 | user.session = session if user | 27 | user.session = session if user |
39 | User.current = user | 28 | User.current = user |
lib/feed_handler.rb
@@ -60,7 +60,7 @@ class FeedHandler | @@ -60,7 +60,7 @@ class FeedHandler | ||
60 | def process(container) | 60 | def process(container) |
61 | begin | 61 | begin |
62 | container.class.transaction do | 62 | container.class.transaction do |
63 | - if container.update_errors > FeedHandler.max_errors && container.fetched_at < (Time.now - FeedHandler.disabled_period) | 63 | + if failed_too_many_times(container) && enough_time_since_last_failure(container) |
64 | container.enabled = true | 64 | container.enabled = true |
65 | container.update_errors = 0 | 65 | container.update_errors = 0 |
66 | container.save | 66 | container.save |
@@ -110,4 +110,12 @@ class FeedHandler | @@ -110,4 +110,12 @@ class FeedHandler | ||
110 | url =~ URI.regexp('http') || url =~ URI.regexp('https') | 110 | url =~ URI.regexp('http') || url =~ URI.regexp('https') |
111 | end | 111 | end |
112 | 112 | ||
113 | + def failed_too_many_times(container) | ||
114 | + container.update_errors > FeedHandler.max_errors | ||
115 | + end | ||
116 | + | ||
117 | + def enough_time_since_last_failure(container) | ||
118 | + container.fetched_at.nil? || container.fetched_at < (Time.now - FeedHandler.disabled_period) | ||
119 | + end | ||
120 | + | ||
113 | end | 121 | 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 |
plugins/comment_paragraph/controllers/profile/comment_paragraph_plugin_profile_controller.rb
1 | require 'csv' | 1 | require 'csv' |
2 | -class CommentParagraphPluginProfileController < ProfileController | 2 | +class CommentParagraphPluginProfileController < CommentController |
3 | append_view_path File.join(File.dirname(__FILE__) + '/../../views') | 3 | append_view_path File.join(File.dirname(__FILE__) + '/../../views') |
4 | 4 | ||
5 | def view_comments | 5 | def view_comments |
@@ -12,6 +12,16 @@ class CommentParagraphPluginProfileController < ProfileController | @@ -12,6 +12,16 @@ class CommentParagraphPluginProfileController < ProfileController | ||
12 | render :partial => 'comment/comment.html.erb', :collection => @comments | 12 | render :partial => 'comment/comment.html.erb', :collection => @comments |
13 | end | 13 | end |
14 | 14 | ||
15 | + def comment_form | ||
16 | + @page = profile.articles.find(params[:article_id]) | ||
17 | + render :partial => 'comment/comment_form', :locals => { | ||
18 | + :comment => Comment.new, | ||
19 | + :display_link => true, | ||
20 | + :cancel_triggers_hide => true, | ||
21 | + :paragraph_uuid => params[:paragraph_uuid] | ||
22 | + } | ||
23 | + end | ||
24 | + | ||
15 | include CommentParagraphPlugin::CommentsReport | 25 | include CommentParagraphPlugin::CommentsReport |
16 | 26 | ||
17 | def export_comments | 27 | def export_comments |
plugins/comment_paragraph/lib/comment_paragraph_plugin/macros/allow_comment.rb
@@ -10,7 +10,8 @@ class CommentParagraphPlugin::AllowComment < Noosfero::Plugin::Macro | @@ -10,7 +10,8 @@ class CommentParagraphPlugin::AllowComment < Noosfero::Plugin::Macro | ||
10 | def parse(params, inner_html, source) | 10 | def parse(params, inner_html, source) |
11 | paragraph_uuid = params[:paragraph_uuid] | 11 | paragraph_uuid = params[:paragraph_uuid] |
12 | article = source | 12 | article = source |
13 | - count = article.paragraph_comments.without_spam.in_paragraph(paragraph_uuid).count | 13 | + @paragraph_comments_counts ||= article.paragraph_comments.without_spam.group(:paragraph_uuid).reorder(:paragraph_uuid).count |
14 | + count = @paragraph_comments_counts.fetch(paragraph_uuid, 0) | ||
14 | 15 | ||
15 | proc { | 16 | proc { |
16 | if controller.kind_of?(ContentViewerController) && article.comment_paragraph_plugin_activated? | 17 | if controller.kind_of?(ContentViewerController) && article.comment_paragraph_plugin_activated? |
plugins/comment_paragraph/lib/ext/article.rb
@@ -36,7 +36,7 @@ class Article | @@ -36,7 +36,7 @@ class Article | ||
36 | if body && (body_changed? || setting_changed?(:comment_paragraph_plugin_activate)) | 36 | if body && (body_changed? || setting_changed?(:comment_paragraph_plugin_activate)) |
37 | updated = body_changed? ? body_change[1] : body | 37 | updated = body_changed? ? body_change[1] : body |
38 | doc = Nokogiri::HTML(updated) | 38 | doc = Nokogiri::HTML(updated) |
39 | - doc.css('li, body > div, body > span, body > p').each do |paragraph| | 39 | + (doc.css('li') + doc.css('body > div, body > span, body > p')).each do |paragraph| |
40 | next if paragraph.css('[data-macro="comment_paragraph_plugin/allow_comment"]').present? || paragraph.content.blank? | 40 | next if paragraph.css('[data-macro="comment_paragraph_plugin/allow_comment"]').present? || paragraph.content.blank? |
41 | 41 | ||
42 | commentable = Nokogiri::XML::Node.new("span", doc) | 42 | commentable = Nokogiri::XML::Node.new("span", doc) |
plugins/comment_paragraph/public/comment_paragraph_macro.js
@@ -80,6 +80,12 @@ jQuery(document).ready(function($) { | @@ -80,6 +80,12 @@ jQuery(document).ready(function($) { | ||
80 | container.find('.display-comment-form').show(); | 80 | container.find('.display-comment-form').show(); |
81 | } | 81 | } |
82 | }); | 82 | }); |
83 | + var formDiv = container.find('.side-comment .post_comment_box'); | ||
84 | + if(formDiv.find('.page-comment-form').length==0) { | ||
85 | + $.ajax(formDiv.data('comment_paragraph_form_url')).done(function(data) { | ||
86 | + formDiv.append(data); | ||
87 | + }); | ||
88 | + } | ||
83 | }); | 89 | }); |
84 | 90 | ||
85 | 91 |
plugins/comment_paragraph/test/functional/comment_paragraph_plugin_profile_controller_test.rb
@@ -10,6 +10,9 @@ class CommentParagraphPluginProfileControllerTest < ActionController::TestCase | @@ -10,6 +10,9 @@ class CommentParagraphPluginProfileControllerTest < ActionController::TestCase | ||
10 | @profile = create_user('testuser').person | 10 | @profile = create_user('testuser').person |
11 | @article = profile.articles.build(:name => 'test') | 11 | @article = profile.articles.build(:name => 'test') |
12 | @article.save! | 12 | @article.save! |
13 | + @environment = Environment.default | ||
14 | + @environment.enabled_plugins = ['CommentParagraphPlugin'] | ||
15 | + @environment.save! | ||
13 | end | 16 | end |
14 | attr_reader :article, :profile | 17 | attr_reader :article, :profile |
15 | 18 | ||
@@ -39,6 +42,14 @@ class CommentParagraphPluginProfileControllerTest < ActionController::TestCase | @@ -39,6 +42,14 @@ class CommentParagraphPluginProfileControllerTest < ActionController::TestCase | ||
39 | assert_match /d comment/, @response.body | 42 | assert_match /d comment/, @response.body |
40 | end | 43 | end |
41 | 44 | ||
45 | + should 'load the comment form for a paragraph' do | ||
46 | + login_as('testuser') | ||
47 | + comment = fast_create(Comment, :source_id => article, :author_id => profile, :title => 'a comment', :body => 'lalala', :paragraph_uuid => 0) | ||
48 | + xhr :get, :comment_form, :profile => @profile.identifier, :article_id => article.id, :paragraph_uuid => 0 | ||
49 | + assert_select ".page-comment-form" | ||
50 | + assert_select "#comment_paragraph_uuid[value=?]", '0' | ||
51 | + end | ||
52 | + | ||
42 | should 'export comments as CSV' do | 53 | should 'export comments as CSV' do |
43 | comment1 = fast_create(Comment, :created_at => Time.now - 1.days, :source_id => article, :author_id => profile, :title => 'a comment', :body => 'a comment', :paragraph_uuid => nil) | 54 | comment1 = fast_create(Comment, :created_at => Time.now - 1.days, :source_id => article, :author_id => profile, :title => 'a comment', :body => 'a comment', :paragraph_uuid => nil) |
44 | comment2 = fast_create(Comment, :created_at => Time.now - 2.days, :source_id => article, :author_id => profile, :title => 'b comment', :body => 'b comment', :paragraph_uuid => nil) | 55 | comment2 = fast_create(Comment, :created_at => Time.now - 2.days, :source_id => article, :author_id => profile, :title => 'b comment', :body => 'b comment', :paragraph_uuid => nil) |
plugins/comment_paragraph/test/unit/allow_comment_test.rb
@@ -46,4 +46,13 @@ class AllowCommentTest < ActiveSupport::TestCase | @@ -46,4 +46,13 @@ class AllowCommentTest < ActiveSupport::TestCase | ||
46 | assert_equal 'inner', instance_eval(&content) | 46 | assert_equal 'inner', instance_eval(&content) |
47 | end | 47 | end |
48 | 48 | ||
49 | + should 'preload comment counts when parsing content' do | ||
50 | + 3.times { fast_create(Comment, :paragraph_uuid => '2', :source_id => article.id) } | ||
51 | + content = macro.parse({:paragraph_uuid => comment.paragraph_uuid}, article.body, article) | ||
52 | + paragraph_comments_counts = macro.instance_variable_get(:@paragraph_comments_counts) | ||
53 | + assert_equivalent ['1', '2'], paragraph_comments_counts.keys | ||
54 | + assert_equal 1, paragraph_comments_counts['1'] | ||
55 | + assert_equal 3, paragraph_comments_counts['2'] | ||
56 | + end | ||
57 | + | ||
49 | end | 58 | end |
plugins/comment_paragraph/views/comment_paragraph_plugin_profile/_comment_paragraph.html.erb
@@ -11,14 +11,14 @@ | @@ -11,14 +11,14 @@ | ||
11 | </div> | 11 | </div> |
12 | 12 | ||
13 | <% load_comments_url = url_for({:profile => profile_identifier, :controller => 'comment_paragraph_plugin_profile', :action => 'view_comments', :paragraph_uuid => paragraph_uuid, :article_id => article_id}) %> | 13 | <% load_comments_url = url_for({:profile => profile_identifier, :controller => 'comment_paragraph_plugin_profile', :action => 'view_comments', :paragraph_uuid => paragraph_uuid, :article_id => article_id}) %> |
14 | + <% load_comment_form_url = url_for({:profile => profile_identifier, :controller => 'comment_paragraph_plugin_profile', :action => 'comment_form', :paragraph_uuid => paragraph_uuid, :article_id => article_id}) %> | ||
14 | 15 | ||
15 | <div class="side-comment" data-comment_paragraph_url="<%= load_comments_url %>"> | 16 | <div class="side-comment" data-comment_paragraph_url="<%= load_comments_url %>"> |
16 | <div class="article-comments-list"> | 17 | <div class="article-comments-list"> |
17 | <div class="loading"></div> | 18 | <div class="loading"></div> |
18 | </div> | 19 | </div> |
19 | <div class ="article-comments-list-more"></div> | 20 | <div class ="article-comments-list-more"></div> |
20 | - <div class='post_comment_box closed'> | ||
21 | - <%= render :partial => 'comment/comment_form', :locals => {:comment => Comment.new, :display_link => true, :cancel_triggers_hide => true, :paragraph_uuid => paragraph_uuid}%> | 21 | + <div class='post_comment_box closed' data-comment_paragraph_form_url="<%= load_comment_form_url %>"> |
22 | </div> | 22 | </div> |
23 | </div> | 23 | </div> |
24 | </div> | 24 | </div> |
public/javascripts/application.js
@@ -568,12 +568,6 @@ function userDataCallback(data) { | @@ -568,12 +568,6 @@ function userDataCallback(data) { | ||
568 | // logged in | 568 | // logged in |
569 | jQuery('head').append('<meta content="authenticity_token" name="csrf-param" />'); | 569 | jQuery('head').append('<meta content="authenticity_token" name="csrf-param" />'); |
570 | jQuery('head').append('<meta content="'+jQuery.cookie("_noosfero_.XSRF-TOKEN")+'" name="csrf-token" />'); | 570 | jQuery('head').append('<meta content="'+jQuery.cookie("_noosfero_.XSRF-TOKEN")+'" name="csrf-token" />'); |
571 | - jQuery.ajaxSetup({ | ||
572 | - cache: false, | ||
573 | - headers: { | ||
574 | - 'X-XSRF-TOKEN': jQuery.cookie("_noosfero_.XSRF-TOKEN") | ||
575 | - } | ||
576 | - }); | ||
577 | } | 571 | } |
578 | if (data.notice) { | 572 | if (data.notice) { |
579 | display_notice(data.notice); | 573 | display_notice(data.notice); |
test/functional/account_controller_test.rb
@@ -108,6 +108,15 @@ class AccountControllerTest < ActionController::TestCase | @@ -108,6 +108,15 @@ class AccountControllerTest < ActionController::TestCase | ||
108 | end | 108 | end |
109 | end | 109 | end |
110 | 110 | ||
111 | + def test_shoud_save_with_custom_field_on_signup | ||
112 | + assert_difference 'User.count' do | ||
113 | + assert_difference 'CustomFieldValue.count' do | ||
114 | + CustomField.create!(:name => "zombies", :format=>"String", :default_value => "awrrr", :customized_type=>"Profile", :active => true, :required => true, :signup => true, :environment => Environment.default) | ||
115 | + new_user({},{"profile_data"=> {"custom_values"=>{"zombies"=>{"value"=>"BRAINSSS"}}}}) | ||
116 | + end | ||
117 | + end | ||
118 | + end | ||
119 | + | ||
111 | def test_should_logout | 120 | def test_should_logout |
112 | login_as :johndoe | 121 | login_as :johndoe |
113 | get :logout | 122 | get :logout |
test/functional/application_controller_test.rb
@@ -478,30 +478,6 @@ class ApplicationControllerTest < ActionController::TestCase | @@ -478,30 +478,6 @@ class ApplicationControllerTest < 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/functional/memberships_controller_test.rb
@@ -36,6 +36,17 @@ class MembershipsControllerTest < ActionController::TestCase | @@ -36,6 +36,17 @@ class MembershipsControllerTest < ActionController::TestCase | ||
36 | end | 36 | end |
37 | end | 37 | end |
38 | 38 | ||
39 | + should 'be able to create a new community with custom field' do | ||
40 | + assert_difference 'Community.count' do | ||
41 | + assert_difference 'CustomFieldValue.count' do | ||
42 | + CustomField.create!(:name => "zombies", :format=>"String", :default_value => "awrrr", :customized_type=>"Community", :active => true, :required => true, :signup => true, :environment => Environment.default) | ||
43 | + post :new_community, :profile => profile.identifier, :community => { :name => 'My shiny new community', :description => 'This is a community devoted to anything interesting we find in the internet '}, "profile_data"=>{"custom_values"=>{"zombies"=>{"value"=>"BRAINSSS"}}} | ||
44 | + assert_response :redirect | ||
45 | + assert Community.find_by_identifier('my-shiny-new-community').members.include?(profile), "Creator user should be added as member of the community just created" | ||
46 | + end | ||
47 | + end | ||
48 | + end | ||
49 | + | ||
39 | should 'link to new community creation in index' do | 50 | should 'link to new community creation in index' do |
40 | get :index, :profile => profile.identifier | 51 | get :index, :profile => profile.identifier |
41 | assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/memberships/new_community" } | 52 | assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/memberships/new_community" } |
test/functional/tasks_controller_test.rb
@@ -360,6 +360,19 @@ class TasksControllerTest < ActionController::TestCase | @@ -360,6 +360,19 @@ class TasksControllerTest < ActionController::TestCase | ||
360 | assert_select "#tasks_#{t.id}_task_name" | 360 | assert_select "#tasks_#{t.id}_task_name" |
361 | end | 361 | end |
362 | 362 | ||
363 | + should "not crash when article suggestion task fails" do | ||
364 | + TinyMceArticle.destroy_all | ||
365 | + c = fast_create(Community) | ||
366 | + c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id)) | ||
367 | + @controller.stubs(:profile).returns(c) | ||
368 | + t = SuggestArticle.create!(:article => {:name => 'test name', :abstract => 'test abstract', :body => 'test body'}, :name => 'some name', :email => 'test@localhost.com', :target => c) | ||
369 | + | ||
370 | + SuggestArticle.any_instance.stubs(:perform).raises('erro') | ||
371 | + assert_nothing_raised do | ||
372 | + post :close, :tasks => {t.id => { :task => {}, :decision => "finish"}} | ||
373 | + end | ||
374 | + end | ||
375 | + | ||
363 | should "append hidden tag with type value from article suggestion" do | 376 | should "append hidden tag with type value from article suggestion" do |
364 | Task.destroy_all | 377 | Task.destroy_all |
365 | c = fast_create(Community) | 378 | c = fast_create(Community) |
@@ -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 |
test/unit/feed_handler_test.rb
@@ -133,6 +133,14 @@ class FeedHandlerTest < ActiveSupport::TestCase | @@ -133,6 +133,14 @@ class FeedHandlerTest < ActiveSupport::TestCase | ||
133 | 133 | ||
134 | assert container.enabled, 'must reenable container after <disabled_period> (%s)' % container_class | 134 | assert container.enabled, 'must reenable container after <disabled_period> (%s)' % container_class |
135 | end | 135 | end |
136 | + | ||
137 | + should "handle a feed that was never fetched successfully (#{container_class})" do | ||
138 | + container = create(container_class) | ||
139 | + container.update_errors = FeedHandler.max_errors + 1 | ||
140 | + container.fetched_at = nil | ||
141 | + handler.expects(:actually_process_container).with(container) | ||
142 | + handler.process(container) | ||
143 | + end | ||
136 | end | 144 | end |
137 | 145 | ||
138 | should 'not crash even when finish fetch fails' do | 146 | should 'not crash even when finish fetch fails' do |
test/unit/suggest_article_test.rb
@@ -242,4 +242,9 @@ class SuggestArticleTest < ActiveSupport::TestCase | @@ -242,4 +242,9 @@ class SuggestArticleTest < ActiveSupport::TestCase | ||
242 | t.article_type == TinyMceArticle | 242 | t.article_type == TinyMceArticle |
243 | end | 243 | end |
244 | 244 | ||
245 | + should 'fallback to tinymce when type parameter is blank' do | ||
246 | + t = SuggestArticle.new | ||
247 | + t.article = {:name => 'name', :body => 'body', :type => ''} | ||
248 | + t.article_type == TinyMceArticle | ||
249 | + end | ||
245 | end | 250 | end |