Commit dc0f987c9dbaa6c21eb65c0e937339eda03553d2
Exists in
theme-brasil-digital-from-staging
and in
9 other branches
Merge branch 'stable' of gitlab.com:participa/noosfero into stable
Showing
37 changed files
with
263 additions
and
107 deletions
Show diff stats
app/controllers/public/search_controller.rb
@@ -3,7 +3,10 @@ class SearchController < PublicController | @@ -3,7 +3,10 @@ class SearchController < PublicController | ||
3 | helper TagsHelper | 3 | helper TagsHelper |
4 | include SearchHelper | 4 | include SearchHelper |
5 | include ActionView::Helpers::NumberHelper | 5 | include ActionView::Helpers::NumberHelper |
6 | + include SanitizeParams | ||
6 | 7 | ||
8 | + | ||
9 | + before_filter :sanitize_params | ||
7 | before_filter :redirect_asset_param, :except => [:assets, :suggestions] | 10 | before_filter :redirect_asset_param, :except => [:assets, :suggestions] |
8 | before_filter :load_category, :except => :suggestions | 11 | before_filter :load_category, :except => :suggestions |
9 | before_filter :load_search_assets, :except => :suggestions | 12 | before_filter :load_search_assets, :except => :suggestions |
app/helpers/blog_helper.rb
@@ -17,28 +17,28 @@ module BlogHelper | @@ -17,28 +17,28 @@ module BlogHelper | ||
17 | _('Configure blog') | 17 | _('Configure blog') |
18 | end | 18 | end |
19 | 19 | ||
20 | - def list_posts(articles, format = 'full', paginate = true) | 20 | + def list_posts(articles, conf = { format: 'full', paginate: true }) |
21 | pagination = will_paginate(articles, { | 21 | pagination = will_paginate(articles, { |
22 | :param_name => 'npage', | 22 | :param_name => 'npage', |
23 | :previous_label => _('« Newer posts'), | 23 | :previous_label => _('« Newer posts'), |
24 | :next_label => _('Older posts »'), | 24 | :next_label => _('Older posts »'), |
25 | :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"} | 25 | :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"} |
26 | - }) if articles.present? && paginate | 26 | + }) if articles.present? && conf[:paginate] |
27 | content = [] | 27 | content = [] |
28 | artic_len = articles.length | 28 | artic_len = articles.length |
29 | articles.each_with_index{ |art,i| | 29 | articles.each_with_index{ |art,i| |
30 | - css_add = [ 'position-'+(i+1).to_s() ] | 30 | + css_add = [ 'blog-post', 'position-'+(i+1).to_s() ] |
31 | position = (i%2 == 0) ? 'odd-post' : 'even-post' | 31 | position = (i%2 == 0) ? 'odd-post' : 'even-post' |
32 | css_add << 'first' if i == 0 | 32 | css_add << 'first' if i == 0 |
33 | css_add << 'last' if i == (artic_len-1) | 33 | css_add << 'last' if i == (artic_len-1) |
34 | css_add << 'not-published' if !art.published? | 34 | css_add << 'not-published' if !art.published? |
35 | - css_add << position + '-inner' | ||
36 | - content << content_tag('div', | ||
37 | - content_tag('div', | ||
38 | - display_post(art, format).html_safe + '<br style="clear:both"/>'.html_safe, | ||
39 | - :class => 'blog-post ' + css_add.join(' '), | ||
40 | - :id => "post-#{art.id}"), :class => position | ||
41 | - ) | 35 | + css_add << position |
36 | + content << (content_tag 'div', id: "post-#{art.id}", class: css_add do | ||
37 | + content_tag 'div', class: position + '-inner blog-post-inner' do | ||
38 | + display_post(art, conf[:format]).html_safe + | ||
39 | + '<br style="clear:both"/>'.html_safe | ||
40 | + end | ||
41 | + end) | ||
42 | } | 42 | } |
43 | content.join("\n<hr class='sep-posts'/>\n") + (pagination or '') | 43 | content.join("\n<hr class='sep-posts'/>\n") + (pagination or '') |
44 | end | 44 | end |
@@ -46,7 +46,16 @@ module BlogHelper | @@ -46,7 +46,16 @@ module BlogHelper | ||
46 | def display_post(article, format = 'full') | 46 | def display_post(article, format = 'full') |
47 | no_comments = (format == 'full') ? false : true | 47 | no_comments = (format == 'full') ? false : true |
48 | title = article_title(article, :no_comments => no_comments) | 48 | title = article_title(article, :no_comments => no_comments) |
49 | - html = send("display_#{format}_format", FilePresenter.for(article)).html_safe | 49 | + method = "display_#{format.split('+')[0]}_format" |
50 | + html = send(method, FilePresenter.for(article)).html_safe | ||
51 | + if format.split('+')[1] == 'pic' | ||
52 | + img = article.first_image | ||
53 | + if img.blank? | ||
54 | + '<div class="post-pic empty"></div>' | ||
55 | + else | ||
56 | + '<div class="post-pic" style="background-image:url('+img+')"></div>' | ||
57 | + end | ||
58 | + end.to_s + | ||
50 | title + html | 59 | title + html |
51 | end | 60 | end |
52 | 61 |
app/models/article.rb
@@ -784,7 +784,9 @@ class Article < ActiveRecord::Base | @@ -784,7 +784,9 @@ class Article < ActiveRecord::Base | ||
784 | end | 784 | end |
785 | 785 | ||
786 | def first_image | 786 | def first_image |
787 | - img = Nokogiri::HTML.fragment(self.lead.to_s).css('img[src]').first || Nokogiri::HTML.fragment(self.body.to_s).search('img').first | 787 | + img = ( image.present? && { 'src' => image.public_filename } ) || |
788 | + Nokogiri::HTML.fragment(self.lead.to_s).css('img[src]').first || | ||
789 | + Nokogiri::HTML.fragment(self.body.to_s).search('img').first | ||
788 | img.nil? ? '' : img['src'] | 790 | img.nil? ? '' : img['src'] |
789 | end | 791 | end |
790 | 792 |
app/models/blog.rb
@@ -76,7 +76,7 @@ class Blog < Folder | @@ -76,7 +76,7 @@ class Blog < Folder | ||
76 | end | 76 | end |
77 | 77 | ||
78 | settings_items :visualization_format, :type => :string, :default => 'full' | 78 | settings_items :visualization_format, :type => :string, :default => 'full' |
79 | - validates_inclusion_of :visualization_format, :in => [ 'full', 'short' ], :if => :visualization_format | 79 | + validates_inclusion_of :visualization_format, :in => [ 'full', 'short', 'short+pic' ], :if => :visualization_format |
80 | 80 | ||
81 | settings_items :display_posts_in_current_language, :type => :boolean, :default => false | 81 | settings_items :display_posts_in_current_language, :type => :boolean, :default => false |
82 | 82 |
app/views/cms/_blog.html.erb
@@ -64,7 +64,11 @@ | @@ -64,7 +64,11 @@ | ||
64 | <%= labelled_check_box(_('Remove cover image'),'remove_image',true,false)%> | 64 | <%= labelled_check_box(_('Remove cover image'),'remove_image',true,false)%> |
65 | <% end %> | 65 | <% end %> |
66 | 66 | ||
67 | -<%= labelled_form_field(_('How to display posts:'), f.select(:visualization_format, [ [ _('Full post'), 'full'], [ _('First paragraph'), 'short'] ])) %> | 67 | +<%= labelled_form_field(_('How to display posts:'), f.select(:visualization_format, [ |
68 | + [ _('Full post'), 'full'], | ||
69 | + [ _('First paragraph'), 'short'], | ||
70 | + [ _('First paragraph, with post picture'), 'short+pic'] | ||
71 | +])) %> | ||
68 | 72 | ||
69 | <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, Blog.posts_per_page_options)) %> | 73 | <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, Blog.posts_per_page_options)) %> |
70 | 74 |
app/views/content_viewer/blog_page.html.erb
@@ -18,6 +18,9 @@ | @@ -18,6 +18,9 @@ | ||
18 | format = inside_block.visualization_format | 18 | format = inside_block.visualization_format |
19 | paginate = false | 19 | paginate = false |
20 | end | 20 | end |
21 | - (blog.empty? ? content_tag('em', _('(no posts)')) : list_posts(posts, format, paginate)) | 21 | + (blog.empty? ? |
22 | + content_tag('em', _('(no posts)')) : | ||
23 | + list_posts(posts, format: format, paginate: paginate) | ||
24 | + ) | ||
22 | %> | 25 | %> |
23 | </div> | 26 | </div> |
app/views/features/manage_fields.html.erb
1 | <h1><%= _('Manage fields displayed for profiles') %></h1> | 1 | <h1><%= _('Manage fields displayed for profiles') %></h1> |
2 | 2 | ||
3 | +<%= javascript_include_tag "manage-fields.js" %> | ||
4 | + | ||
3 | <% tabs = [] %> | 5 | <% tabs = [] %> |
4 | <% tabs << {:title => _("Person's fields"), :id => 'person-fields', | 6 | <% tabs << {:title => _("Person's fields"), :id => 'person-fields', |
5 | :content => (render :partial => 'manage_person_fields')} %> | 7 | :content => (render :partial => 'manage_person_fields')} %> |
@@ -11,5 +13,3 @@ | @@ -11,5 +13,3 @@ | ||
11 | <% end %> | 13 | <% end %> |
12 | 14 | ||
13 | <%= render_tabs(tabs) %> | 15 | <%= render_tabs(tabs) %> |
14 | - | ||
15 | -<%= javascript_include_tag "manage-fields.js" %> |
lib/noosfero/api/entities.rb
@@ -53,9 +53,11 @@ module Noosfero | @@ -53,9 +53,11 @@ module Noosfero | ||
53 | expose :image, :using => Image | 53 | expose :image, :using => Image |
54 | end | 54 | end |
55 | 55 | ||
56 | - class ArticleChild < Entity | 56 | + class ArticleBase < Entity |
57 | root 'articles', 'article' | 57 | root 'articles', 'article' |
58 | - expose :id, :body, :abstract | 58 | + expose :id |
59 | + expose :body | ||
60 | + expose :abstract | ||
59 | expose :created_at, :format_with => :timestamp | 61 | expose :created_at, :format_with => :timestamp |
60 | expose :title, :documentation => {:type => "String", :desc => "Title of the article"} | 62 | expose :title, :documentation => {:type => "String", :desc => "Title of the article"} |
61 | expose :created_by, :as => :author, :using => Profile | 63 | expose :created_by, :as => :author, :using => Profile |
@@ -64,18 +66,10 @@ module Noosfero | @@ -64,18 +66,10 @@ module Noosfero | ||
64 | expose :image, :using => Image | 66 | expose :image, :using => Image |
65 | end | 67 | end |
66 | 68 | ||
67 | - class Article < Entity | 69 | + class Article < ArticleBase |
68 | root 'articles', 'article' | 70 | root 'articles', 'article' |
69 | - expose :id, :body, :abstract | ||
70 | - expose :created_at, :format_with => :timestamp | ||
71 | - expose :title, :documentation => {:type => "String", :desc => "Title of the article"} | ||
72 | - expose :created_by, :as => :author, :using => Profile | ||
73 | - expose :profile, :using => Profile | ||
74 | - expose :categories, :using => Category | ||
75 | - # FIXME: create a method that overrides expose and include conditions for return attributes | ||
76 | - expose :parent, :using => Article | ||
77 | - expose :children, :using => ArticleChild | ||
78 | - expose :image, :using => Image | 71 | + expose :parent, :using => ArticleBase |
72 | + expose :children, :using => ArticleBase | ||
79 | end | 73 | end |
80 | 74 | ||
81 | class Comment < Entity | 75 | class Comment < Entity |
lib/noosfero/api/v1/articles.rb
@@ -71,7 +71,7 @@ module Noosfero | @@ -71,7 +71,7 @@ module Noosfero | ||
71 | if !article.save | 71 | if !article.save |
72 | render_api_errors!(article.errors.full_messages) | 72 | render_api_errors!(article.errors.full_messages) |
73 | end | 73 | end |
74 | - present article, :with => Entities::Article | 74 | + present article, :with => Entities::Article, :fields => params[:fields] |
75 | end | 75 | end |
76 | 76 | ||
77 | 77 | ||
@@ -110,7 +110,7 @@ module Noosfero | @@ -110,7 +110,7 @@ module Noosfero | ||
110 | if !article.save | 110 | if !article.save |
111 | render_api_errors!(article.errors.full_messages) | 111 | render_api_errors!(article.errors.full_messages) |
112 | end | 112 | end |
113 | - present article, :with => Entities::Article | 113 | + present article, :with => Entities::Article, :fields => params[:fields] |
114 | end | 114 | end |
115 | 115 | ||
116 | end | 116 | end |
@@ -149,7 +149,7 @@ module Noosfero | @@ -149,7 +149,7 @@ module Noosfero | ||
149 | if !article.save | 149 | if !article.save |
150 | render_api_errors!(article.errors.full_messages) | 150 | render_api_errors!(article.errors.full_messages) |
151 | end | 151 | end |
152 | - present article, :with => Entities::Article | 152 | + present article, :with => Entities::Article, :fields => params[:fields] |
153 | end | 153 | end |
154 | 154 | ||
155 | end | 155 | end |
@@ -188,7 +188,7 @@ module Noosfero | @@ -188,7 +188,7 @@ module Noosfero | ||
188 | if !article.save | 188 | if !article.save |
189 | render_api_errors!(article.errors.full_messages) | 189 | render_api_errors!(article.errors.full_messages) |
190 | end | 190 | end |
191 | - present article, :with => Entities::Article | 191 | + present article, :with => Entities::Article, :fields => params[:fields] |
192 | end | 192 | end |
193 | 193 | ||
194 | end | 194 | end |
@@ -0,0 +1,34 @@ | @@ -0,0 +1,34 @@ | ||
1 | +module SanitizeParams | ||
2 | + | ||
3 | + protected | ||
4 | + | ||
5 | + # Check each request parameter for | ||
6 | + # improper HTML or Script tags | ||
7 | + def sanitize_params | ||
8 | + request.params.each { |k, v| | ||
9 | + if v.is_a?(String) | ||
10 | + params[k] = sanitize_param v | ||
11 | + elsif v.is_a?(Array) | ||
12 | + params[k] = sanitize_array v | ||
13 | + end | ||
14 | + } | ||
15 | + end | ||
16 | + | ||
17 | + # If the parameter was an array, | ||
18 | + # try to sanitize each element in the array | ||
19 | + def sanitize_array(array) | ||
20 | + array.map! { |e| | ||
21 | + if e.is_a?(String) | ||
22 | + sanitize_param e | ||
23 | + end | ||
24 | + } | ||
25 | + return array | ||
26 | + end | ||
27 | + | ||
28 | + # Santitize a single value | ||
29 | + def sanitize_param(value) | ||
30 | + allowed_tags = %w(a acronym b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p) | ||
31 | + ActionController::Base.helpers.sanitize(value, tags: allowed_tags, attributes: %w(href title)) | ||
32 | + end | ||
33 | + | ||
34 | +end |
plugins/google_analytics/lib/ext/profile.rb
@@ -2,4 +2,9 @@ require_dependency 'profile' | @@ -2,4 +2,9 @@ require_dependency 'profile' | ||
2 | 2 | ||
3 | class Profile | 3 | class Profile |
4 | settings_items :google_analytics_profile_id | 4 | settings_items :google_analytics_profile_id |
5 | + attr_accessible :google_analytics_profile_id | ||
6 | + | ||
7 | + descendants.each do |descendant| | ||
8 | + descendant.attr_accessible :google_analytics_profile_id | ||
9 | + end | ||
5 | end | 10 | end |
plugins/google_analytics/lib/google_analytics_plugin.rb
@@ -19,12 +19,15 @@ class GoogleAnalyticsPlugin < Noosfero::Plugin | @@ -19,12 +19,15 @@ class GoogleAnalyticsPlugin < Noosfero::Plugin | ||
19 | 19 | ||
20 | def head_ending | 20 | def head_ending |
21 | unless profile_id.blank? | 21 | unless profile_id.blank? |
22 | - expanded_template('tracking-code.rhtml',{:profile_id => profile_id}) | 22 | + expanded_template('tracking-code.html.erb',{:profile_id => profile_id}) |
23 | end | 23 | end |
24 | end | 24 | end |
25 | 25 | ||
26 | def profile_editor_extras | 26 | def profile_editor_extras |
27 | - expanded_template('profile-editor-extras.rhtml',{:profile_id => profile_id}) | 27 | + analytics_id = profile_id |
28 | + lambda { | ||
29 | + render :file => 'profile-editor-extras', :locals => { :profile_id => analytics_id } | ||
30 | + } | ||
28 | end | 31 | end |
29 | 32 | ||
30 | end | 33 | end |
plugins/google_analytics/test/functional/profile_editor_controller_test.rb
0 → 100644
@@ -0,0 +1,31 @@ | @@ -0,0 +1,31 @@ | ||
1 | +require 'test_helper' | ||
2 | +require 'profile_editor_controller' | ||
3 | + | ||
4 | +# Re-raise errors caught by the controller. | ||
5 | +class ProfileEditorController; def rescue_action(e) raise e end; end | ||
6 | + | ||
7 | +class ProfileEditorControllerTest < ActionController::TestCase | ||
8 | + | ||
9 | + def setup | ||
10 | + @controller = ProfileEditorController.new | ||
11 | + @request = ActionController::TestRequest.new | ||
12 | + @response = ActionController::TestResponse.new | ||
13 | + @profile = create_user('default_user').person | ||
14 | + login_as(@profile.identifier) | ||
15 | + Environment.default.enable_plugin(GoogleAnalyticsPlugin.name) | ||
16 | + end | ||
17 | + | ||
18 | + attr_accessor :profile | ||
19 | + | ||
20 | + should 'add extra fields to profile editor info and settings' do | ||
21 | + get :edit, :profile => profile.identifier | ||
22 | + assert_tag_in_string @response.body, :tag => 'label', :content => /Google Analytics/, :attributes => { :for => 'profile_data_google_analytics_profile_id' } | ||
23 | + assert_tag_in_string @response.body, :tag => 'input', :attributes => { :id => 'profile_data_google_analytics_profile_id' } | ||
24 | + end | ||
25 | + | ||
26 | + should 'save code filled in on field' do | ||
27 | + post :edit, :profile => profile.identifier, :profile_data => {:google_analytics_profile_id => 12345678} | ||
28 | + assert_equal '12345678', Person.find(profile.id).google_analytics_profile_id | ||
29 | + end | ||
30 | + | ||
31 | +end |
plugins/google_analytics/test/unit/google_analytics_plugin_test.rb
@@ -27,11 +27,6 @@ class GoogleAnalyticsPluginTest < ActiveSupport::TestCase | @@ -27,11 +27,6 @@ class GoogleAnalyticsPluginTest < ActiveSupport::TestCase | ||
27 | assert_equal 'content', @plugin.head_ending | 27 | assert_equal 'content', @plugin.head_ending |
28 | end | 28 | end |
29 | 29 | ||
30 | - should 'add extra fields to profile editor info and settings' do | ||
31 | - assert_tag_in_string @plugin.profile_editor_extras, | ||
32 | - :tag => 'input', :attributes => {:id => 'profile_data_google_analytics_profile_id', :value => 10} | ||
33 | - end | ||
34 | - | ||
35 | should 'extends Profile with attr google_analytics_profile_id' do | 30 | should 'extends Profile with attr google_analytics_profile_id' do |
36 | assert_respond_to Profile.new, :google_analytics_profile_id | 31 | assert_respond_to Profile.new, :google_analytics_profile_id |
37 | end | 32 | end |
plugins/google_analytics/views/profile-editor-extras.html.erb
0 → 100644
@@ -0,0 +1,3 @@ | @@ -0,0 +1,3 @@ | ||
1 | +<h2><%= c_('Statistics') %></h2> | ||
2 | +<%= labelled_form_field(_('Google Analytics Profile ID'), text_field(:profile_data, :google_analytics_profile_id, :value => profile_id)) %> | ||
3 | +<%= link_to(_('See how to configure statistics for your profile'), '/doc/plugins/google_analytics', :target => '_blank') %> |
plugins/google_analytics/views/profile-editor-extras.rhtml
@@ -1,5 +0,0 @@ | @@ -1,5 +0,0 @@ | ||
1 | -<% extend ApplicationHelper %> | ||
2 | - | ||
3 | -<h2><%= c_('Statistics') %></h2> | ||
4 | -<%= labelled_form_field(_('Google Analytics Profile ID'), text_field(:profile_data, :google_analytics_profile_id, :value => profile_id)) %> | ||
5 | -<%= link_to(_('See how to configure statistics for your profile'), '/doc/plugins/google_analytics', :target => '_blank') %> |
@@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
1 | +<script> | ||
2 | + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | ||
3 | + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | ||
4 | + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | ||
5 | + })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); | ||
6 | + | ||
7 | + ga('create', '<%= escape_javascript locals[:profile_id] %>', 'auto'); | ||
8 | + ga('send', 'pageview'); | ||
9 | +</script> |
plugins/google_analytics/views/tracking-code.rhtml
@@ -1,10 +0,0 @@ | @@ -1,10 +0,0 @@ | ||
1 | -<script type="text/javascript"> | ||
2 | - var _gaq = _gaq || []; | ||
3 | - _gaq.push(['_setAccount', '<%= escape_javascript locals[:profile_id] %>']); | ||
4 | - _gaq.push(['_trackPageview']); | ||
5 | - (function() { | ||
6 | - var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; | ||
7 | - ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | ||
8 | - var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); | ||
9 | - })(); | ||
10 | -</script> |
plugins/proposals_discussion
plugins/send_email/controllers/send_email_plugin_base_controller.rb
@@ -11,7 +11,8 @@ module SendEmailPluginBaseController | @@ -11,7 +11,8 @@ module SendEmailPluginBaseController | ||
11 | ) | 11 | ) |
12 | @mail.subject = params[:subject] unless params[:subject].blank? | 12 | @mail.subject = params[:subject] unless params[:subject].blank? |
13 | if @mail.valid? | 13 | if @mail.valid? |
14 | - SendEmailPlugin::Sender.send_message(request.referer, @context_url, @mail).deliver | 14 | + @referer = request.referer |
15 | + SendEmailPlugin::Sender.send_message(@referer, @context_url, @mail).deliver | ||
15 | if request.xhr? | 16 | if request.xhr? |
16 | render :text => _('Message sent') | 17 | render :text => _('Message sent') |
17 | else | 18 | else |
plugins/send_email/lib/send_email_plugin.rb
@@ -16,9 +16,9 @@ class SendEmailPlugin < Noosfero::Plugin | @@ -16,9 +16,9 @@ class SendEmailPlugin < Noosfero::Plugin | ||
16 | 16 | ||
17 | def parse_content(html, source) | 17 | def parse_content(html, source) |
18 | if context.profile | 18 | if context.profile |
19 | - html.gsub!(/\{sendemail\}/, "/profile/#{context.profile.identifier}/plugin/send_email/deliver") | 19 | + html.gsub!(/({|%7[Bb])sendemail(}|%7[Dd])/, "/profile/#{context.profile.identifier}/plugin/send_email/deliver") |
20 | else | 20 | else |
21 | - html.gsub!(/\{sendemail\}/, '/plugin/send_email/deliver') | 21 | + html.gsub!(/({|%7[Bb])sendemail(}|%7[Dd])/, '/plugin/send_email/deliver') |
22 | end | 22 | end |
23 | [html, source] | 23 | [html, source] |
24 | end | 24 | end |
plugins/send_email/lib/send_email_plugin/mail.rb
@@ -10,12 +10,11 @@ class SendEmailPlugin::Mail | @@ -10,12 +10,11 @@ class SendEmailPlugin::Mail | ||
10 | validate :recipients_format | 10 | validate :recipients_format |
11 | 11 | ||
12 | def initialize(attributes = {:subject => 'New mail'}) | 12 | def initialize(attributes = {:subject => 'New mail'}) |
13 | - @environment = attributes[:environment] | ||
14 | - @from = attributes[:from] | ||
15 | - @to = attributes[:to] | ||
16 | - @subject = attributes[:subject] | ||
17 | - @message = attributes[:message] | ||
18 | - @params = attributes[:params] | 13 | + if attributes |
14 | + attributes.each do |attr,value| | ||
15 | + self.send("#{attr}=", value) | ||
16 | + end | ||
17 | + end | ||
19 | end | 18 | end |
20 | 19 | ||
21 | def recipients_format | 20 | def recipients_format |
@@ -36,7 +35,7 @@ class SendEmailPlugin::Mail | @@ -36,7 +35,7 @@ class SendEmailPlugin::Mail | ||
36 | end | 35 | end |
37 | 36 | ||
38 | def params=(value = {}) | 37 | def params=(value = {}) |
39 | - [:action, :controller, :to, :message, :subject, :from].each{|k| value.delete(k)} | 38 | + [:profile, :action, :controller, :to, :message, :subject, :from, :commit].each{|k| value.delete(k)} |
40 | @params = value | 39 | @params = value |
41 | end | 40 | end |
42 | 41 |
plugins/send_email/lib/send_email_plugin/sender.rb
@@ -7,9 +7,9 @@ class SendEmailPlugin::Sender < Noosfero::Plugin::MailerBase | @@ -7,9 +7,9 @@ class SendEmailPlugin::Sender < Noosfero::Plugin::MailerBase | ||
7 | @params = mail.params | 7 | @params = mail.params |
8 | 8 | ||
9 | mail( | 9 | mail( |
10 | + content_type: 'text/plain', | ||
10 | to: mail.to, | 11 | to: mail.to, |
11 | from: mail.from, | 12 | from: mail.from, |
12 | - body: mail.params, | ||
13 | subject: "[#{mail.environment.name}] #{mail.subject}" | 13 | subject: "[#{mail.environment.name}] #{mail.subject}" |
14 | ) | 14 | ) |
15 | end | 15 | end |
plugins/send_email/test/functional/send_email_plugin_base_controller_test.rb
@@ -54,6 +54,13 @@ def run_common_tests | @@ -54,6 +54,13 @@ def run_common_tests | ||
54 | post :deliver, @extra_args.merge(:to => 'john@example.com', :message => 'Hi john', :subject => 'Hello john') | 54 | post :deliver, @extra_args.merge(:to => 'john@example.com', :message => 'Hi john', :subject => 'Hello john') |
55 | assert_equal '[Colivre.net] Hello john', ActionMailer::Base.deliveries.first.subject | 55 | assert_equal '[Colivre.net] Hello john', ActionMailer::Base.deliveries.first.subject |
56 | end | 56 | end |
57 | + | ||
58 | + should 'deliver mail with message from view' do | ||
59 | + Environment.any_instance.stubs(:send_email_plugin_allow_to).returns('john@example.com') | ||
60 | + post :deliver, @extra_args.merge(:to => 'john@example.com', :message => 'Hi john', :subject => 'Hello john') | ||
61 | + assert_match /Contact from/, ActionMailer::Base.deliveries.first.body.to_s | ||
62 | + end | ||
63 | + | ||
57 | end | 64 | end |
58 | 65 | ||
59 | class SendEmailPluginProfileControllerTest < ActionController::TestCase | 66 | class SendEmailPluginProfileControllerTest < ActionController::TestCase |
plugins/send_email/test/unit/send_email_plugin_sender_test.rb
@@ -15,12 +15,14 @@ class SendEmailPluginSenderTest < ActiveSupport::TestCase | @@ -15,12 +15,14 @@ class SendEmailPluginSenderTest < ActiveSupport::TestCase | ||
15 | end | 15 | end |
16 | 16 | ||
17 | should 'be able to deliver mail' do | 17 | should 'be able to deliver mail' do |
18 | + @mail.expects(:params).returns({}) | ||
18 | response = SendEmailPlugin::Sender.send_message("http://localhost/contact", 'http//profile', @mail) | 19 | response = SendEmailPlugin::Sender.send_message("http://localhost/contact", 'http//profile', @mail) |
19 | assert_equal 'noreply@localhost', response.from.join | 20 | assert_equal 'noreply@localhost', response.from.join |
20 | assert_equal "[Noosfero] #{@mail.subject}", response.subject | 21 | assert_equal "[Noosfero] #{@mail.subject}", response.subject |
21 | end | 22 | end |
22 | 23 | ||
23 | should 'deliver mail to john@example.com' do | 24 | should 'deliver mail to john@example.com' do |
25 | + @mail.expects(:params).returns({}) | ||
24 | response = SendEmailPlugin::Sender.send_message("http://localhost/contact", 'http//profile', @mail) | 26 | response = SendEmailPlugin::Sender.send_message("http://localhost/contact", 'http//profile', @mail) |
25 | assert_equal ['john@example.com'], response.to | 27 | assert_equal ['john@example.com'], response.to |
26 | end | 28 | end |
plugins/send_email/test/unit/send_email_plugin_test.rb
@@ -26,4 +26,12 @@ class SendEmailPluginTest < ActiveSupport::TestCase | @@ -26,4 +26,12 @@ class SendEmailPluginTest < ActiveSupport::TestCase | ||
26 | assert_match /profile\/#{@plugin.context.profile.identifier}\/plugin\/send_email\/deliver/, @plugin.parse_content("expand this macro {sendemail}", nil).first | 26 | assert_match /profile\/#{@plugin.context.profile.identifier}\/plugin\/send_email\/deliver/, @plugin.parse_content("expand this macro {sendemail}", nil).first |
27 | end | 27 | end |
28 | 28 | ||
29 | + should 'expand macro used on form on profile context' do | ||
30 | + profile = fast_create(Community) | ||
31 | + @plugin.context.stubs(:profile).returns(profile) | ||
32 | + article = RawHTMLArticle.create!(:name => 'Raw HTML', :body => "<form action='{sendemail}'></form>", :profile => profile) | ||
33 | + | ||
34 | + assert_match /profile\/#{profile.identifier}\/plugin\/send_email\/deliver/, @plugin.parse_content(article.to_html, nil).first | ||
35 | + end | ||
36 | + | ||
29 | end | 37 | end |
plugins/send_email/views/send_email_plugin/sender/message.html.erb
plugins/send_email/views/send_email_plugin/sender/send_message.html.erb
0 → 100644
plugins/send_email/views/send_email_plugin/success.html.erb
@@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
2 | 2 | ||
3 | <table class='sendemail-plugin-message-sent'> | 3 | <table class='sendemail-plugin-message-sent'> |
4 | <tr><td class='label'><strong><%= c_('Subject') %>:</strong></td><td class='value'><em><%=h @mail.subject %></em></td></tr> | 4 | <tr><td class='label'><strong><%= c_('Subject') %>:</strong></td><td class='value'><em><%=h @mail.subject %></em></td></tr> |
5 | - <tr><td class='label'><strong><%= c_('Message') %>:</strong></td><td class='value'><pre><%=h render :file => 'send_email_plugin/sender/message' %></pre></td></tr> | 5 | + <tr><td class='label'><strong><%= c_('Message') %>:</strong></td><td class='value'><pre><%=h render :file => 'send_email_plugin/sender/send_message' %></pre></td></tr> |
6 | </table> | 6 | </table> |
7 | 7 | ||
8 | <p><%= button :back, c_('Back'), :back %></p> | 8 | <p><%= button :back, c_('Back'), :back %></p> |
public/javascripts/manage-fields.js
@@ -57,7 +57,7 @@ jQuery(document).ready(function(){ | @@ -57,7 +57,7 @@ jQuery(document).ready(function(){ | ||
57 | } | 57 | } |
58 | 58 | ||
59 | var checkbox = jQuery(checkboxes[i+3]).attr("id").split("_") | 59 | var checkbox = jQuery(checkboxes[i+3]).attr("id").split("_") |
60 | - jQuery("#" + checkbox.first() + "_" + checkbox.last()).attr("checked", allchecked) | 60 | + jQuery("#" + checkbox[0] + "_" + checkbox[checkbox.length-1]).attr("checked", allchecked) |
61 | } | 61 | } |
62 | } | 62 | } |
63 | 63 | ||
@@ -74,10 +74,10 @@ jQuery(document).ready(function(){ | @@ -74,10 +74,10 @@ jQuery(document).ready(function(){ | ||
74 | 74 | ||
75 | jQuery("input[type='checkbox']").click(function (){ | 75 | jQuery("input[type='checkbox']").click(function (){ |
76 | var checkbox = jQuery(this).attr("id").split("_") | 76 | var checkbox = jQuery(this).attr("id").split("_") |
77 | - verify_checked(checkbox.first()) | 77 | + verify_checked(checkbox[0]) |
78 | 78 | ||
79 | if(this.checked == false) { | 79 | if(this.checked == false) { |
80 | - jQuery("#" + checkbox.first() + "_" + checkbox.last()).attr("checked", false) | 80 | + jQuery("#" + checkbox[0] + "_" + checkbox[checkbox.length-1]).attr("checked", false) |
81 | } | 81 | } |
82 | }) | 82 | }) |
83 | }) | 83 | }) |
public/proposal-app
public/stylesheets/application.css
@@ -1502,6 +1502,14 @@ a.comment-picture { | @@ -1502,6 +1502,14 @@ a.comment-picture { | ||
1502 | #content .title { | 1502 | #content .title { |
1503 | margin-bottom: 2px; | 1503 | margin-bottom: 2px; |
1504 | } | 1504 | } |
1505 | +.blog-post .post-pic { | ||
1506 | + background-position: 50% 40%; | ||
1507 | + background-size: cover; | ||
1508 | + height: 150px; | ||
1509 | +} | ||
1510 | +.blog-post .post-pic.empty { | ||
1511 | + display: none; | ||
1512 | +} | ||
1505 | .metadata, .blog-post .metadata { | 1513 | .metadata, .blog-post .metadata { |
1506 | display: block; | 1514 | display: block; |
1507 | text-align: center; | 1515 | text-align: center; |
script/production
@@ -55,7 +55,7 @@ do_restart() { | @@ -55,7 +55,7 @@ do_restart() { | ||
55 | environments_loop start | 55 | environments_loop start |
56 | 56 | ||
57 | clear_cache | 57 | clear_cache |
58 | - ruby -S bundle exec thin -C config/thin.yml restart --onebyone | 58 | + RUBY_GC_MALLOC_LIMIT=250000000 RUBY_HEAP_MIN_SLOTS=800000 RUBY_FREE_MIN=32768 ruby -S bundle exec thin -C config/thin.yml restart --onebyone |
59 | } | 59 | } |
60 | 60 | ||
61 | stop_via_pid_file() { | 61 | stop_via_pid_file() { |
@@ -85,7 +85,9 @@ environments_loop() { | @@ -85,7 +85,9 @@ environments_loop() { | ||
85 | } | 85 | } |
86 | 86 | ||
87 | do_running() { | 87 | do_running() { |
88 | - pgrep -u noosfero -f 'thin server' > /dev/null | 88 | + pids=$(sed "s/.*/& /" tmp/pids/thin.*.pid | tr -d '\n' 2>/dev/null || true) |
89 | + # passes if any of $pids exist, fails otherwise | ||
90 | + kill -0 $pids > /dev/null 2>&1 | ||
89 | } | 91 | } |
90 | 92 | ||
91 | case "$ACTION" in | 93 | case "$ACTION" in |
test/functional/content_viewer_controller_test.rb
@@ -780,6 +780,20 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -780,6 +780,20 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
780 | assert_no_tag :tag => 'div', :attributes => { :class => 'short-post'}, :content => /Anything/ | 780 | assert_no_tag :tag => 'div', :attributes => { :class => 'short-post'}, :content => /Anything/ |
781 | end | 781 | end |
782 | 782 | ||
783 | + should 'show only first paragraph with picture of posts if visualization_format is short+pic' do | ||
784 | + login_as(profile.identifier) | ||
785 | + | ||
786 | + blog = Blog.create!(:name => 'A blog test', :profile => profile, :visualization_format => 'short+pic') | ||
787 | + | ||
788 | + blog.posts << TinyMceArticle.create!(:name => 'first post', :parent => blog, :profile => profile, :body => '<p>Content to be displayed.</p> <img src="pic.jpg">') | ||
789 | + | ||
790 | + get :view_page, :profile => profile.identifier, :page => blog.path | ||
791 | + | ||
792 | + assert_select '.blog-post .post-pic' do |el| | ||
793 | + assert_match /background-image:url\(pic.jpg\)/, el.to_s | ||
794 | + end | ||
795 | + end | ||
796 | + | ||
783 | should 'display link to edit blog for allowed' do | 797 | should 'display link to edit blog for allowed' do |
784 | blog = fast_create(Blog, :profile_id => profile.id, :path => 'blog') | 798 | blog = fast_create(Blog, :profile_id => profile.id, :path => 'blog') |
785 | login_as(profile.identifier) | 799 | login_as(profile.identifier) |
test/functional/search_controller_test.rb
@@ -769,6 +769,22 @@ class SearchControllerTest < ActionController::TestCase | @@ -769,6 +769,22 @@ class SearchControllerTest < ActionController::TestCase | ||
769 | assert_equivalent [t1,t2,c1,c2,c3,c4] , assigns(:searches)[:communities][:results] | 769 | assert_equivalent [t1,t2,c1,c2,c3,c4] , assigns(:searches)[:communities][:results] |
770 | end | 770 | end |
771 | 771 | ||
772 | + should 'not allow query injection' do | ||
773 | + injection = '<iMg SrC=x OnErRoR=document.documentElement.innerHTML=1>SearchParam' | ||
774 | + get :tag, :tag => injection | ||
775 | + tag = assigns(:tag) | ||
776 | + assert !tag.upcase.include?('IMG') && tag.include?('SearchParam') | ||
777 | + end | ||
778 | + | ||
779 | + should 'not allow query injection array' do | ||
780 | + injection = ['<iMg SrC=x OnErRoR=document.documentElement.innerHTML=1>', '<script>document.innerHTML = \'x\'</script>'] | ||
781 | + get :tag, :tag => injection | ||
782 | + tag = assigns(:tag) | ||
783 | + tag.each { |t| | ||
784 | + assert !t.upcase.include?('IMG') && !t.upcase.include?('SCRIPT') | ||
785 | + } | ||
786 | + end | ||
787 | + | ||
772 | protected | 788 | protected |
773 | 789 | ||
774 | def create_event(profile, options) | 790 | def create_event(profile, options) |
test/unit/article_test.rb
@@ -1715,6 +1715,18 @@ class ArticleTest < ActiveSupport::TestCase | @@ -1715,6 +1715,18 @@ class ArticleTest < ActiveSupport::TestCase | ||
1715 | assert_equal 'bar.png', a.first_image | 1715 | assert_equal 'bar.png', a.first_image |
1716 | end | 1716 | end |
1717 | 1717 | ||
1718 | + should 'get first image from having_image' do | ||
1719 | + a = fast_create(Article, | ||
1720 | + :body => '<p>Foo</p><p><img src="bar.png" /></p>', | ||
1721 | + :abstract => '<p>Lead</p><p><img src="lead.png" /></p>' | ||
1722 | + ) | ||
1723 | + img = {} | ||
1724 | + img.expects(:present?).returns true | ||
1725 | + img.expects(:public_filename).returns 'pic.jpg' | ||
1726 | + a.expects(:image).at_least_once.returns img | ||
1727 | + assert_equal 'pic.jpg', a.first_image | ||
1728 | + end | ||
1729 | + | ||
1718 | should 'not get first image from anywhere' do | 1730 | should 'not get first image from anywhere' do |
1719 | a = fast_create(Article, :body => '<p>Foo</p><p>Bar</p>') | 1731 | a = fast_create(Article, :body => '<p>Foo</p><p>Bar</p>') |
1720 | assert_equal '', a.first_image | 1732 | assert_equal '', a.first_image |
test/unit/blog_helper_test.rb
@@ -20,30 +20,36 @@ class BlogHelperTest < ActionView::TestCase | @@ -20,30 +20,36 @@ class BlogHelperTest < ActionView::TestCase | ||
20 | def _(s); s; end | 20 | def _(s); s; end |
21 | def h(s); s; end | 21 | def h(s); s; end |
22 | 22 | ||
23 | - should 'list published posts with class blog-post' do | ||
24 | - blog.children << published_post = create(TextileArticle, :name => 'Post', :profile => profile, :parent => blog, :published => true) | ||
25 | - | ||
26 | - expects(:display_post).with(anything, anything).returns('POST') | ||
27 | - expects(:content_tag).with('div', "POST<br style=\"clear:both\"/>", :class => 'blog-post position-1 first last odd-post-inner', :id => "post-#{published_post.id}").returns('POST') | ||
28 | - expects(:content_tag).with('div', 'POST', {:class => 'odd-post'}).returns('RESULT') | ||
29 | - | ||
30 | - assert_equal 'RESULT', list_posts(blog.posts) | ||
31 | - end | ||
32 | - | ||
33 | - should 'list even/odd posts with a different class' do | ||
34 | - blog.children << older_post = create(TextileArticle, :name => 'First post', :profile => profile, :parent => blog, :published => true) | ||
35 | - | ||
36 | - blog.children << newer_post = create(TextileArticle, :name => 'Second post', :profile => profile, :parent => blog, :published => true) | ||
37 | - | ||
38 | - expects(:display_post).with(anything, anything).returns('POST').times(2) | ||
39 | - | ||
40 | - expects(:content_tag).with('div', "POST<br style=\"clear:both\"/>", :class => 'blog-post position-1 first odd-post-inner', :id => "post-#{newer_post.id}").returns('POST 1') | ||
41 | - expects(:content_tag).with('div', "POST 1", :class => 'odd-post').returns('ODD-POST') | ||
42 | - | ||
43 | - expects(:content_tag).with('div', "POST<br style=\"clear:both\"/>", :class => 'blog-post position-2 last even-post-inner', :id => "post-#{older_post.id}").returns('POST 2') | ||
44 | - expects(:content_tag).with('div', "POST 2", :class => 'even-post').returns('EVEN-POST') | ||
45 | - | ||
46 | - assert_equal "ODD-POST\n<hr class='sep-posts'/>\nEVEN-POST", list_posts(blog.posts) | 23 | + should 'list blog posts with identifiers and classes' do |
24 | + blog.children << older_post = create(TextileArticle, :name => 'First post', | ||
25 | + :profile => profile, :parent => blog, :published => true) | ||
26 | + blog.children << some_post = create(TextileArticle, :name => 'Some post', | ||
27 | + :profile => profile, :parent => blog, :published => true) | ||
28 | + blog.children << hidden_post = create(TextileArticle, :name => 'Hidden post', | ||
29 | + :profile => profile, :parent => blog, :published => false) | ||
30 | + blog.children << newer_post = create(TextileArticle, :name => 'Last post', | ||
31 | + :profile => profile, :parent => blog, :published => true) | ||
32 | + | ||
33 | + def content_tag(tag, content_or_options_with_block = nil, options = nil, &block) | ||
34 | + if block_given? | ||
35 | + options = content_or_options_with_block | ||
36 | + content = block.call | ||
37 | + else | ||
38 | + content = content_or_options_with_block | ||
39 | + end | ||
40 | + options ||= {} | ||
41 | + "<#{tag}#{options.map{|k,v| " #{k}=\"#{[v].flatten.join(' ')}\""}.join}>#{content}</#{tag}>" | ||
42 | + end | ||
43 | + | ||
44 | + html = HTML::Document.new(list_posts(blog.posts)).root | ||
45 | + assert_select html, "div#post-#{newer_post.id}.blog-post.position-1.first.odd-post" + | ||
46 | + " > div.odd-post-inner.blog-post-inner > .title", 'Last post' | ||
47 | + assert_select html, "div#post-#{hidden_post.id}.blog-post.position-2.not-published.even-post" + | ||
48 | + " > div.even-post-inner.blog-post-inner > .title", 'Hidden post' | ||
49 | + assert_select html, "div#post-#{some_post.id}.blog-post.position-3.odd-post" + | ||
50 | + " > div.odd-post-inner.blog-post-inner > .title", 'Some post' | ||
51 | + assert_select html, "div#post-#{older_post.id}.blog-post.position-4.last.even-post" + | ||
52 | + " > div.even-post-inner.blog-post-inner > .title", 'First post' | ||
47 | end | 53 | end |
48 | 54 | ||
49 | 55 |