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 | 3 | helper TagsHelper |
4 | 4 | include SearchHelper |
5 | 5 | include ActionView::Helpers::NumberHelper |
6 | + include SanitizeParams | |
6 | 7 | |
8 | + | |
9 | + before_filter :sanitize_params | |
7 | 10 | before_filter :redirect_asset_param, :except => [:assets, :suggestions] |
8 | 11 | before_filter :load_category, :except => :suggestions |
9 | 12 | before_filter :load_search_assets, :except => :suggestions | ... | ... |
app/helpers/blog_helper.rb
... | ... | @@ -17,28 +17,28 @@ module BlogHelper |
17 | 17 | _('Configure blog') |
18 | 18 | end |
19 | 19 | |
20 | - def list_posts(articles, format = 'full', paginate = true) | |
20 | + def list_posts(articles, conf = { format: 'full', paginate: true }) | |
21 | 21 | pagination = will_paginate(articles, { |
22 | 22 | :param_name => 'npage', |
23 | 23 | :previous_label => _('« Newer posts'), |
24 | 24 | :next_label => _('Older posts »'), |
25 | 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 | 27 | content = [] |
28 | 28 | artic_len = articles.length |
29 | 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 | 31 | position = (i%2 == 0) ? 'odd-post' : 'even-post' |
32 | 32 | css_add << 'first' if i == 0 |
33 | 33 | css_add << 'last' if i == (artic_len-1) |
34 | 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 | 43 | content.join("\n<hr class='sep-posts'/>\n") + (pagination or '') |
44 | 44 | end |
... | ... | @@ -46,7 +46,16 @@ module BlogHelper |
46 | 46 | def display_post(article, format = 'full') |
47 | 47 | no_comments = (format == 'full') ? false : true |
48 | 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 | 59 | title + html |
51 | 60 | end |
52 | 61 | ... | ... |
app/models/article.rb
... | ... | @@ -784,7 +784,9 @@ class Article < ActiveRecord::Base |
784 | 784 | end |
785 | 785 | |
786 | 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 | 790 | img.nil? ? '' : img['src'] |
789 | 791 | end |
790 | 792 | ... | ... |
app/models/blog.rb
... | ... | @@ -76,7 +76,7 @@ class Blog < Folder |
76 | 76 | end |
77 | 77 | |
78 | 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 | 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 | 64 | <%= labelled_check_box(_('Remove cover image'),'remove_image',true,false)%> |
65 | 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 | 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 | 18 | format = inside_block.visualization_format |
19 | 19 | paginate = false |
20 | 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 | 26 | </div> | ... | ... |
app/views/features/manage_fields.html.erb
1 | 1 | <h1><%= _('Manage fields displayed for profiles') %></h1> |
2 | 2 | |
3 | +<%= javascript_include_tag "manage-fields.js" %> | |
4 | + | |
3 | 5 | <% tabs = [] %> |
4 | 6 | <% tabs << {:title => _("Person's fields"), :id => 'person-fields', |
5 | 7 | :content => (render :partial => 'manage_person_fields')} %> |
... | ... | @@ -11,5 +13,3 @@ |
11 | 13 | <% end %> |
12 | 14 | |
13 | 15 | <%= render_tabs(tabs) %> |
14 | - | |
15 | -<%= javascript_include_tag "manage-fields.js" %> | ... | ... |
lib/noosfero/api/entities.rb
... | ... | @@ -53,9 +53,11 @@ module Noosfero |
53 | 53 | expose :image, :using => Image |
54 | 54 | end |
55 | 55 | |
56 | - class ArticleChild < Entity | |
56 | + class ArticleBase < Entity | |
57 | 57 | root 'articles', 'article' |
58 | - expose :id, :body, :abstract | |
58 | + expose :id | |
59 | + expose :body | |
60 | + expose :abstract | |
59 | 61 | expose :created_at, :format_with => :timestamp |
60 | 62 | expose :title, :documentation => {:type => "String", :desc => "Title of the article"} |
61 | 63 | expose :created_by, :as => :author, :using => Profile |
... | ... | @@ -64,18 +66,10 @@ module Noosfero |
64 | 66 | expose :image, :using => Image |
65 | 67 | end |
66 | 68 | |
67 | - class Article < Entity | |
69 | + class Article < ArticleBase | |
68 | 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 | 73 | end |
80 | 74 | |
81 | 75 | class Comment < Entity | ... | ... |
lib/noosfero/api/v1/articles.rb
... | ... | @@ -71,7 +71,7 @@ module Noosfero |
71 | 71 | if !article.save |
72 | 72 | render_api_errors!(article.errors.full_messages) |
73 | 73 | end |
74 | - present article, :with => Entities::Article | |
74 | + present article, :with => Entities::Article, :fields => params[:fields] | |
75 | 75 | end |
76 | 76 | |
77 | 77 | |
... | ... | @@ -110,7 +110,7 @@ module Noosfero |
110 | 110 | if !article.save |
111 | 111 | render_api_errors!(article.errors.full_messages) |
112 | 112 | end |
113 | - present article, :with => Entities::Article | |
113 | + present article, :with => Entities::Article, :fields => params[:fields] | |
114 | 114 | end |
115 | 115 | |
116 | 116 | end |
... | ... | @@ -149,7 +149,7 @@ module Noosfero |
149 | 149 | if !article.save |
150 | 150 | render_api_errors!(article.errors.full_messages) |
151 | 151 | end |
152 | - present article, :with => Entities::Article | |
152 | + present article, :with => Entities::Article, :fields => params[:fields] | |
153 | 153 | end |
154 | 154 | |
155 | 155 | end |
... | ... | @@ -188,7 +188,7 @@ module Noosfero |
188 | 188 | if !article.save |
189 | 189 | render_api_errors!(article.errors.full_messages) |
190 | 190 | end |
191 | - present article, :with => Entities::Article | |
191 | + present article, :with => Entities::Article, :fields => params[:fields] | |
192 | 192 | end |
193 | 193 | |
194 | 194 | end | ... | ... |
... | ... | @@ -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 | 2 | |
3 | 3 | class Profile |
4 | 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 | 10 | end | ... | ... |
plugins/google_analytics/lib/google_analytics_plugin.rb
... | ... | @@ -19,12 +19,15 @@ class GoogleAnalyticsPlugin < Noosfero::Plugin |
19 | 19 | |
20 | 20 | def head_ending |
21 | 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 | 23 | end |
24 | 24 | end |
25 | 25 | |
26 | 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 | 31 | end |
29 | 32 | |
30 | 33 | end | ... | ... |
plugins/google_analytics/test/functional/profile_editor_controller_test.rb
0 → 100644
... | ... | @@ -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 | 27 | assert_equal 'content', @plugin.head_ending |
28 | 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 | 30 | should 'extends Profile with attr google_analytics_profile_id' do |
36 | 31 | assert_respond_to Profile.new, :google_analytics_profile_id |
37 | 32 | end | ... | ... |
plugins/google_analytics/views/profile-editor-extras.html.erb
0 → 100644
... | ... | @@ -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 | -<% 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 @@ |
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 | -<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 | 11 | ) |
12 | 12 | @mail.subject = params[:subject] unless params[:subject].blank? |
13 | 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 | 16 | if request.xhr? |
16 | 17 | render :text => _('Message sent') |
17 | 18 | else | ... | ... |
plugins/send_email/lib/send_email_plugin.rb
... | ... | @@ -16,9 +16,9 @@ class SendEmailPlugin < Noosfero::Plugin |
16 | 16 | |
17 | 17 | def parse_content(html, source) |
18 | 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 | 20 | else |
21 | - html.gsub!(/\{sendemail\}/, '/plugin/send_email/deliver') | |
21 | + html.gsub!(/({|%7[Bb])sendemail(}|%7[Dd])/, '/plugin/send_email/deliver') | |
22 | 22 | end |
23 | 23 | [html, source] |
24 | 24 | end | ... | ... |
plugins/send_email/lib/send_email_plugin/mail.rb
... | ... | @@ -10,12 +10,11 @@ class SendEmailPlugin::Mail |
10 | 10 | validate :recipients_format |
11 | 11 | |
12 | 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 | 18 | end |
20 | 19 | |
21 | 20 | def recipients_format |
... | ... | @@ -36,7 +35,7 @@ class SendEmailPlugin::Mail |
36 | 35 | end |
37 | 36 | |
38 | 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 | 39 | @params = value |
41 | 40 | end |
42 | 41 | ... | ... |
plugins/send_email/lib/send_email_plugin/sender.rb
... | ... | @@ -7,9 +7,9 @@ class SendEmailPlugin::Sender < Noosfero::Plugin::MailerBase |
7 | 7 | @params = mail.params |
8 | 8 | |
9 | 9 | mail( |
10 | + content_type: 'text/plain', | |
10 | 11 | to: mail.to, |
11 | 12 | from: mail.from, |
12 | - body: mail.params, | |
13 | 13 | subject: "[#{mail.environment.name}] #{mail.subject}" |
14 | 14 | ) |
15 | 15 | end | ... | ... |
plugins/send_email/test/functional/send_email_plugin_base_controller_test.rb
... | ... | @@ -54,6 +54,13 @@ def run_common_tests |
54 | 54 | post :deliver, @extra_args.merge(:to => 'john@example.com', :message => 'Hi john', :subject => 'Hello john') |
55 | 55 | assert_equal '[Colivre.net] Hello john', ActionMailer::Base.deliveries.first.subject |
56 | 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 | 64 | end |
58 | 65 | |
59 | 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 | 15 | end |
16 | 16 | |
17 | 17 | should 'be able to deliver mail' do |
18 | + @mail.expects(:params).returns({}) | |
18 | 19 | response = SendEmailPlugin::Sender.send_message("http://localhost/contact", 'http//profile', @mail) |
19 | 20 | assert_equal 'noreply@localhost', response.from.join |
20 | 21 | assert_equal "[Noosfero] #{@mail.subject}", response.subject |
21 | 22 | end |
22 | 23 | |
23 | 24 | should 'deliver mail to john@example.com' do |
25 | + @mail.expects(:params).returns({}) | |
24 | 26 | response = SendEmailPlugin::Sender.send_message("http://localhost/contact", 'http//profile', @mail) |
25 | 27 | assert_equal ['john@example.com'], response.to |
26 | 28 | end | ... | ... |
plugins/send_email/test/unit/send_email_plugin_test.rb
... | ... | @@ -26,4 +26,12 @@ class SendEmailPluginTest < ActiveSupport::TestCase |
26 | 26 | assert_match /profile\/#{@plugin.context.profile.identifier}\/plugin\/send_email\/deliver/, @plugin.parse_content("expand this macro {sendemail}", nil).first |
27 | 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 | 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 | 2 | |
3 | 3 | <table class='sendemail-plugin-message-sent'> |
4 | 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 | 6 | </table> |
7 | 7 | |
8 | 8 | <p><%= button :back, c_('Back'), :back %></p> | ... | ... |
public/javascripts/manage-fields.js
... | ... | @@ -57,7 +57,7 @@ jQuery(document).ready(function(){ |
57 | 57 | } |
58 | 58 | |
59 | 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 | 74 | |
75 | 75 | jQuery("input[type='checkbox']").click(function (){ |
76 | 76 | var checkbox = jQuery(this).attr("id").split("_") |
77 | - verify_checked(checkbox.first()) | |
77 | + verify_checked(checkbox[0]) | |
78 | 78 | |
79 | 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 | 1502 | #content .title { |
1503 | 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 | 1513 | .metadata, .blog-post .metadata { |
1506 | 1514 | display: block; |
1507 | 1515 | text-align: center; | ... | ... |
script/production
... | ... | @@ -55,7 +55,7 @@ do_restart() { |
55 | 55 | environments_loop start |
56 | 56 | |
57 | 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 | 61 | stop_via_pid_file() { |
... | ... | @@ -85,7 +85,9 @@ environments_loop() { |
85 | 85 | } |
86 | 86 | |
87 | 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 | 93 | case "$ACTION" in | ... | ... |
test/functional/content_viewer_controller_test.rb
... | ... | @@ -780,6 +780,20 @@ class ContentViewerControllerTest < ActionController::TestCase |
780 | 780 | assert_no_tag :tag => 'div', :attributes => { :class => 'short-post'}, :content => /Anything/ |
781 | 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 | 797 | should 'display link to edit blog for allowed' do |
784 | 798 | blog = fast_create(Blog, :profile_id => profile.id, :path => 'blog') |
785 | 799 | login_as(profile.identifier) | ... | ... |
test/functional/search_controller_test.rb
... | ... | @@ -769,6 +769,22 @@ class SearchControllerTest < ActionController::TestCase |
769 | 769 | assert_equivalent [t1,t2,c1,c2,c3,c4] , assigns(:searches)[:communities][:results] |
770 | 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 | 788 | protected |
773 | 789 | |
774 | 790 | def create_event(profile, options) | ... | ... |
test/unit/article_test.rb
... | ... | @@ -1715,6 +1715,18 @@ class ArticleTest < ActiveSupport::TestCase |
1715 | 1715 | assert_equal 'bar.png', a.first_image |
1716 | 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 | 1730 | should 'not get first image from anywhere' do |
1719 | 1731 | a = fast_create(Article, :body => '<p>Foo</p><p>Bar</p>') |
1720 | 1732 | assert_equal '', a.first_image | ... | ... |
test/unit/blog_helper_test.rb
... | ... | @@ -20,30 +20,36 @@ class BlogHelperTest < ActionView::TestCase |
20 | 20 | def _(s); s; end |
21 | 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 | 53 | end |
48 | 54 | |
49 | 55 | ... | ... |