Commit 6c7a6cc3279057c7cdf972ff9a328f61de31e58b

Authored by Victor Costa
2 parents 3ebc0a24 88d13891

Merge branch 'suggest_article_refactor' into api

Showing 54 changed files with 446 additions and 208 deletions   Show diff stats
app/controllers/my_profile/cms_controller.rb
@@ -350,7 +350,8 @@ class CmsController < MyProfileController @@ -350,7 +350,8 @@ class CmsController < MyProfileController
350 @task.ip_address = request.remote_ip 350 @task.ip_address = request.remote_ip
351 @task.user_agent = request.user_agent 351 @task.user_agent = request.user_agent
352 @task.referrer = request.referrer 352 @task.referrer = request.referrer
353 - if verify_recaptcha(:model => @task, :message => _('Please type the words correctly')) && @task.save 353 + @task.requestor = current_person if logged_in?
  354 + if (logged_in? || verify_recaptcha(:model => @task, :message => _('Please type the words correctly'))) && @task.save
354 session[:notice] = _('Thanks for your suggestion. The community administrators were notified.') 355 session[:notice] = _('Thanks for your suggestion. The community administrators were notified.')
355 redirect_to @back_to 356 redirect_to @back_to
356 end 357 end
app/controllers/public/events_controller.rb
@@ -5,7 +5,11 @@ class EventsController < PublicController @@ -5,7 +5,11 @@ class EventsController < PublicController
5 5
6 def events 6 def events
7 @events = [] 7 @events = []
8 - @date = build_date(params[:year], params[:month], params[:day]) 8 + begin
  9 + @date = build_date params[:year], params[:month], params[:day]
  10 + rescue ArgumentError # invalid date
  11 + return render_not_found
  12 + end
9 13
10 if !params[:year] && !params[:month] && !params[:day] 14 if !params[:year] && !params[:month] && !params[:day]
11 @events = profile.events.next_events_from_month(@date).paginate(:per_page => per_page, :page => params[:page]) 15 @events = profile.events.next_events_from_month(@date).paginate(:per_page => per_page, :page => params[:page])
app/controllers/public/search_controller.rb
@@ -62,7 +62,7 @@ class SearchController < PublicController @@ -62,7 +62,7 @@ class SearchController < PublicController
62 end 62 end
63 63
64 def articles 64 def articles
65 - @scope = @environment.articles.public.paginate(paginate_options) 65 + @scope = @environment.articles.public
66 full_text_search 66 full_text_search
67 end 67 end
68 68
@@ -76,7 +76,7 @@ class SearchController < PublicController @@ -76,7 +76,7 @@ class SearchController < PublicController
76 end 76 end
77 77
78 def products 78 def products
79 - @scope = @environment.products.paginate(paginate_options) 79 + @scope = @environment.products
80 full_text_search 80 full_text_search
81 end 81 end
82 82
@@ -244,7 +244,7 @@ class SearchController < PublicController @@ -244,7 +244,7 @@ class SearchController < PublicController
244 def visible_profiles(klass, *extra_relations) 244 def visible_profiles(klass, *extra_relations)
245 relations = [:image, :domains, :environment, :preferred_domain] 245 relations = [:image, :domains, :environment, :preferred_domain]
246 relations += extra_relations 246 relations += extra_relations
247 - @environment.send(klass.name.underscore.pluralize).visible.includes(relations).paginate(paginate_options) 247 + @environment.send(klass.name.underscore.pluralize).visible.includes(relations)
248 end 248 end
249 249
250 def per_page 250 def per_page
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/helpers/boxes_helper.rb
@@ -251,8 +251,8 @@ module BoxesHelper @@ -251,8 +251,8 @@ module BoxesHelper
251 content_tag('h2', _('Embed block code')) + 251 content_tag('h2', _('Embed block code')) +
252 content_tag('div', _('Below, you''ll see a field containing embed code for the block. Just copy the code and paste it into your website or blogging software.'), :style => 'margin-bottom: 1em;') + 252 content_tag('div', _('Below, you''ll see a field containing embed code for the block. Just copy the code and paste it into your website or blogging software.'), :style => 'margin-bottom: 1em;') +
253 content_tag('textarea', embed_code, :style => 'margin-bottom: 1em; width:100%; height:40%;', :readonly => 'readonly') + 253 content_tag('textarea', embed_code, :style => 'margin-bottom: 1em; width:100%; height:40%;', :readonly => 'readonly') +
254 - thickbox_close_button(_('Close')), :style => 'display: none;', :id => "embed-code-box-#{block.id}")  
255 - buttons << thickbox_inline_popup_icon(:embed, _('Embed code'), {}, "embed-code-box-#{block.id}") << html 254 + modal_close_button(_('Close')), :style => 'display: none;', :id => "embed-code-box-#{block.id}")
  255 + buttons << modal_inline_icon(:embed, _('Embed code'), {}, "#embed-code-box-#{block.id}") << html
256 end 256 end
257 257
258 content_tag('div', buttons.join("\n") + tag('br', :style => 'clear: left'), :class => 'button-bar') 258 content_tag('div', buttons.join("\n") + tag('br', :style => 'clear: left'), :class => 'button-bar')
app/helpers/tinymce_helper.rb
@@ -17,6 +17,7 @@ module TinymceHelper @@ -17,6 +17,7 @@ module TinymceHelper
17 searchreplace wordcount visualblocks visualchars code fullscreen 17 searchreplace wordcount visualblocks visualchars code fullscreen
18 insertdatetime media nonbreaking save table contextmenu directionality 18 insertdatetime media nonbreaking save table contextmenu directionality
19 emoticons template paste textcolor colorpicker textpattern], 19 emoticons template paste textcolor colorpicker textpattern],
  20 + :image_advtab => true,
20 :language => tinymce_language 21 :language => tinymce_language
21 22
22 options[:toolbar1] = "insertfile undo redo | copy paste | bold italic underline | styleselect fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image" 23 options[:toolbar1] = "insertfile undo redo | copy paste | bold italic underline | styleselect fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
app/models/article.rb
@@ -5,7 +5,7 @@ class Article &lt; ActiveRecord::Base @@ -5,7 +5,7 @@ class Article &lt; ActiveRecord::Base
5 :allow_members_to_edit, :translation_of_id, :language, 5 :allow_members_to_edit, :translation_of_id, :language,
6 :license_id, :parent_id, :display_posts_in_current_language, 6 :license_id, :parent_id, :display_posts_in_current_language,
7 :category_ids, :posts_per_page, :moderate_comments, 7 :category_ids, :posts_per_page, :moderate_comments,
8 - :accept_comments, :feed, :published, :source, 8 + :accept_comments, :feed, :published, :source, :source_name,
9 :highlighted, :notify_comments, :display_hits, :slug, 9 :highlighted, :notify_comments, :display_hits, :slug,
10 :external_feed_builder, :display_versions, :external_link, 10 :external_feed_builder, :display_versions, :external_link,
11 :image_builder, :show_to_followers 11 :image_builder, :show_to_followers
@@ -784,7 +784,9 @@ class Article &lt; ActiveRecord::Base @@ -784,7 +784,9 @@ class Article &lt; 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 &lt; Folder @@ -76,7 +76,7 @@ class Blog &lt; 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/models/suggest_article.rb
1 class SuggestArticle < Task 1 class SuggestArticle < Task
2 2
3 - validates_presence_of :target_id, :article_name, :email, :name, :article_body 3 + validates_presence_of :target_id
  4 + validates_presence_of :email, :name, :if => Proc.new { |task| task.requestor.blank? }
  5 + validates_associated :article_object
4 6
5 settings_items :email, :type => String 7 settings_items :email, :type => String
6 settings_items :name, :type => String 8 settings_items :name, :type => String
7 - settings_items :article_name, :type => String  
8 - settings_items :article_body, :type => String  
9 - settings_items :article_abstract, :type => String  
10 - settings_items :article_parent_id, :type => String  
11 - settings_items :source, :type => String  
12 - settings_items :source_name, :type => String  
13 - settings_items :highlighted, :type => :boolean, :default => false  
14 settings_items :ip_address, :type => String 9 settings_items :ip_address, :type => String
15 settings_items :user_agent, :type => String 10 settings_items :user_agent, :type => String
16 settings_items :referrer, :type => String 11 settings_items :referrer, :type => String
  12 + settings_items :article, :type => Hash, :default => {}
17 13
18 after_create :schedule_spam_checking 14 after_create :schedule_spam_checking
19 15
@@ -24,34 +20,45 @@ class SuggestArticle &lt; Task @@ -24,34 +20,45 @@ class SuggestArticle &lt; Task
24 include Noosfero::Plugin::HotSpot 20 include Noosfero::Plugin::HotSpot
25 21
26 def sender 22 def sender
27 - "#{name} (#{email})" 23 + requestor ? "#{requestor.name}" : "#{name} (#{email})"
  24 + end
  25 +
  26 + def article_object
  27 + if @article_object.nil?
  28 + @article_object = article_type.new(article.merge({:profile => target}))
  29 + if requestor.present?
  30 + @article_object.author = requestor
  31 + else
  32 + @article_object.author_name = name
  33 + end
  34 + end
  35 + @article_object
  36 + end
  37 +
  38 + def article_type
  39 + (article[:type] || 'TinyMceArticle').constantize
28 end 40 end
29 41
30 def perform 42 def perform
31 - task = TinyMceArticle.new  
32 - task.profile = target  
33 - task.name = article_name  
34 - task.author_name = name  
35 - task.body = article_body  
36 - task.abstract = article_abstract  
37 - task.parent_id = article_parent_id  
38 - task.source = source  
39 - task.source_name = source_name  
40 - task.highlighted = highlighted  
41 - task.save! 43 + article_object.save!
42 end 44 end
43 45
44 def title 46 def title
45 _("Article suggestion") 47 _("Article suggestion")
46 end 48 end
47 49
  50 + def article_name
  51 + article[:name]
  52 + end
  53 +
48 def subject 54 def subject
49 article_name 55 article_name
50 end 56 end
51 57
52 def information 58 def information
53 - { :message => _('%{sender} suggested the publication of the article: %{subject}.'),  
54 - :variables => {:sender => sender} } 59 + variables = requestor.blank? ? {:requestor => sender} : {}
  60 + { :message => _('%{requestor} suggested the publication of the article: %{subject}.'),
  61 + :variables => variables }
55 end 62 end
56 63
57 def accept_details 64 def accept_details
@@ -63,8 +70,8 @@ class SuggestArticle &lt; Task @@ -63,8 +70,8 @@ class SuggestArticle &lt; Task
63 end 70 end
64 71
65 def target_notification_description 72 def target_notification_description
66 - _('%{sender} suggested the publication of the article: %{article}.') %  
67 - {:sender => sender, :article => article_name} 73 + _('%{requestor} suggested the publication of the article: %{article}.') %
  74 + {:requestor => sender, :article => article_name}
68 end 75 end
69 76
70 def target_notification_message 77 def target_notification_message
app/models/user.rb
@@ -46,7 +46,7 @@ class User &lt; ActiveRecord::Base @@ -46,7 +46,7 @@ class User &lt; ActiveRecord::Base
46 p = Person.new 46 p = Person.new
47 47
48 p.attributes = user.person_data 48 p.attributes = user.person_data
49 - p.identifier = user.login 49 + p.identifier = user.login if p.identifier.blank?
50 p.user = user 50 p.user = user
51 p.environment = user.environment 51 p.environment = user.environment
52 p.name ||= user.name || user.login 52 p.name ||= user.name || user.login
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/cms/suggest_an_article.html.erb
@@ -6,21 +6,22 @@ @@ -6,21 +6,22 @@
6 6
7 <%= labelled_form_for 'task' do |f| %> 7 <%= labelled_form_for 'task' do |f| %>
8 8
9 - <%= required labelled_form_field(_('Title'), text_field(:task, 'article_name', :size => 50)) %> 9 + <%= required labelled_form_field(_('Title'), text_field('task[article]', 'name', :size => 50)) %>
10 10
11 - <%= labelled_form_field(_('Source'), text_field(:task, 'source_name')) %> 11 + <%= labelled_form_field(_('Source'), text_field('task[article]', 'source_name')) %>
12 12
13 - <%= labelled_form_field(_('Source URL'), text_field(:task, 'source')) %> 13 + <%= labelled_form_field(_('Source URL'), text_field('task[article]', 'source')) %>
14 14
15 - <%= required labelled_form_field(_('Your name'), text_field(:task, 'name')) %>  
16 -  
17 - <%= required labelled_form_field(_('Email'), text_field(:task, 'email')) %> 15 + <% unless logged_in? %>
  16 + <%= required labelled_form_field(_('Your name'), text_field(:task, 'name')) %>
  17 + <%= required labelled_form_field(_('Email'), text_field(:task, 'email')) %>
  18 + <% end %>
18 19
19 - <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :object => :task, :abstract_method => 'article_abstract', :body_method => 'article_body'} %> 20 + <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :object => 'task[article]'} %>
20 21
21 <%= hidden_field_tag('back_to', @back_to) %> 22 <%= hidden_field_tag('back_to', @back_to) %>
22 23
23 - <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) %> 24 + <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) unless logged_in? %>
24 25
25 <% button_bar do %> 26 <% button_bar do %>
26 <%= submit_button :save, _('Save') %> 27 <%= submit_button :save, _('Save') %>
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/profile/report_abuse.html.erb
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 $('#report-abuse-submit-button').css('cursor', 'progress'); 24 $('#report-abuse-submit-button').css('cursor', 'progress');
25 $.ajax({ 25 $.ajax({
26 type: 'POST', 26 type: 'POST',
27 - url: <%= url_for({:controller => 'profile', :action => 'register_report', :profile => profile.identifier}) %>, 27 + url: <%= url_for({:controller => 'profile', :action => 'register_report', :profile => profile.identifier}).to_json %>,
28 data: $(form).serialize(), 28 data: $(form).serialize(),
29 dataType: 'json', 29 dataType: 'json',
30 success: function(data, status, ajax){ 30 success: function(data, status, ajax){
app/views/profile_editor/edit.html.erb
1 <h1><%= _('Profile settings for %s') % profile.name %></h1> 1 <h1><%= _('Profile settings for %s') % profile.name %></h1>
2 2
3 -<%= javascript_include_tag 'deactivate_profile' %>  
4 <%= error_messages_for :profile_data %> 3 <%= error_messages_for :profile_data %>
5 4
6 <%= labelled_form_for :profile_data, :html => { :id => 'profile-data', :multipart => true } do |f| %> 5 <%= labelled_form_for :profile_data, :html => { :id => 'profile-data', :multipart => true } do |f| %>
app/views/search/search.js.erb
1 -jQuery('#search-content').html('<%= escape_javascript(render :partial => "search_content") %>'); 1 +jQuery('#search-content').replaceWith('<%= escape_javascript(render "search_content") %>');
  2 +
app/views/spam/_suggest_article.html.erb
@@ -7,13 +7,13 @@ @@ -7,13 +7,13 @@
7 <ul class="suggest-article-details" style="display: none"> 7 <ul class="suggest-article-details" style="display: none">
8 <li><strong><%=_('Sent by')%></strong>: <%=task.name%> </li> 8 <li><strong><%=_('Sent by')%></strong>: <%=task.name%> </li>
9 <li><strong><%=_('Email')%></strong>: <%=task.email%> </li> 9 <li><strong><%=_('Email')%></strong>: <%=task.email%> </li>
10 - <li><strong><%=_('Source')%></strong>: <%=task.source_name%> </li>  
11 - <li><strong><%=_('Source URL')%></strong>: <%=task.source%> </li>  
12 - <li><strong><%=_('Folder')%></strong>: <%=(a = Article.find_by_id(task.article_parent_id))?a.name : '<em>' + s_('Folder|none') + '</em>'%> </li>  
13 - <li><strong><%=_('Lead')%></strong>: <%=task.article_abstract.blank? ? '<em>' + s_('Abstract|empty') + '</em>' : task.article_abstract%> </li> 10 + <li><strong><%=_('Source')%></strong>: <%=task.article_object.source_name%> </li>
  11 + <li><strong><%=_('Source URL')%></strong>: <%=task.article_object.source%> </li>
  12 + <li><strong><%=_('Folder')%></strong>: <%=(a = Article.find_by_id(task.article_object.parent_id))?a.name : '<em>' + s_('Folder|none') + '</em>'%> </li>
  13 + <li><strong><%=_('Lead')%></strong>: <%=task.article_object.abstract.blank? ? '<em>' + s_('Abstract|empty') + '</em>' : task.article_object.abstract%> </li>
14 <li><strong><%=_('Body')%></strong>: 14 <li><strong><%=_('Body')%></strong>:
15 <div class='suggest-article-body'> 15 <div class='suggest-article-body'>
16 - <%= task.article_body %> 16 + <%= task.article_object.body %>
17 </div> 17 </div>
18 </li> 18 </li>
19 </ul> 19 </ul>
app/views/tasks/_suggest_article_accept_details.html.erb
1 <%= render :file => 'shared/tiny_mce' %> 1 <%= render :file => 'shared/tiny_mce' %>
2 2
3 -<%= labelled_form_field(_("Sent by: "), f.text_field(:name)) %>  
4 -<p><%= label_tag(_("Email: %s") % task.email) %> </p>  
5 -<%= required labelled_form_field(_('Title'), f.text_field(:article_name, :size => 50)) %>  
6 -<%= labelled_form_field(_('Source'), f.text_field(:source_name)) %>  
7 -<%= labelled_form_field(_("Source URL"), f.text_field(:source)) %> 3 +<% unless task.requestor %>
  4 + <%= labelled_form_field(_("Sent by: "), f.text_field(:name)) %>
  5 + <p><%= label_tag(_("Email: %s") % task.email) %> </p>
  6 +<% end %>
8 7
9 -<%= select_profile_folder(_('Select the folder where the article must be published'), "tasks[#{task.id}][task][article_parent_id]", task.target) %>  
10 -<%= labelled_form_field(_('Highlight this article'), f.check_box(:highlighted)) %> 8 +<%= f.fields_for 'article', OpenStruct.new(task.article) do |a| %>
  9 + <%= required labelled_form_field(_('Title'), a.text_field(:name, :size => 50)) %>
  10 + <%= labelled_form_field(_('Source'), a.text_field(:source_name)) %>
  11 + <%= labelled_form_field(_("Source URL"), a.text_field(:source)) %>
11 12
12 -<%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :f => f, :abstract_method => 'article_abstract', :body_method => 'article_body', :lead_id => task.id} %> 13 + <%= select_profile_folder(_('Select the folder where the article must be published'), "tasks[#{task.id}][task][article][parent_id]", task.target) %>
  14 + <%= labelled_form_field(_('Highlight this article'), a.check_box(:highlighted)) %>
  15 +
  16 + <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :f => a, :lead_id => task.id} %>
  17 +<% end %>
config/initializers/newrelic.rb
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -# Load newrelic agent if its config file is defined.  
2 -require 'newrelic_rpm' if File.exist?(File.dirname(__FILE__) + '/../newrelic.yml')  
db/migrate/20140724134601_fix_yaml_encoding.rb
@@ -18,9 +18,8 @@ class FixYamlEncoding &lt; ActiveRecord::Migration @@ -18,9 +18,8 @@ class FixYamlEncoding &lt; ActiveRecord::Migration
18 private 18 private
19 19
20 def self.fix_encoding(model, param) 20 def self.fix_encoding(model, param)
21 - result = model.all  
22 - puts "Fixing #{result.count} rows of #{model} (#{param})"  
23 - result.each do |r| 21 + puts "Fixing #{model.count} rows of #{model} (#{param})"
  22 + model.find_each do |r|
24 begin 23 begin
25 yaml = r.send(param) 24 yaml = r.send(param)
26 # if deserialization failed then a string is returned 25 # if deserialization failed then a string is returned
debian/changelog
  1 +noosfero (1.1~rc4) wheezy; urgency=medium
  2 +
  3 + * Fourth release candidate for Noosfero 1.1
  4 +
  5 + -- Antonio Terceiro <terceiro@debian.org> Wed, 01 Apr 2015 12:22:36 -0300
  6 +
1 noosfero (1.1~rc2) wheezy; urgency=low 7 noosfero (1.1~rc2) wheezy; urgency=low
2 8
3 * Second release candidate for Noosfero 1.1 9 * Second release candidate for Noosfero 1.1
debian/noosfero.install
@@ -25,6 +25,7 @@ etc/init.d/noosfero etc/init.d @@ -25,6 +25,7 @@ etc/init.d/noosfero etc/init.d
25 etc/logrotate.d/noosfero etc/logrotate.d 25 etc/logrotate.d/noosfero etc/logrotate.d
26 etc/noosfero/varnish-accept-language.vcl etc/noosfero 26 etc/noosfero/varnish-accept-language.vcl etc/noosfero
27 etc/noosfero/varnish-noosfero.vcl etc/noosfero 27 etc/noosfero/varnish-noosfero.vcl etc/noosfero
  28 +etc/awstats-noosfero.conf etc/noosfero
28 lib usr/share/noosfero 29 lib usr/share/noosfero
29 locale usr/share/noosfero 30 locale usr/share/noosfero
30 plugins usr/share/noosfero 31 plugins usr/share/noosfero
features/edit_article.feature
@@ -250,6 +250,7 @@ Feature: edit article @@ -250,6 +250,7 @@ Feature: edit article
250 Scenario: add a translation to an article 250 Scenario: add a translation to an article
251 Given I am on joaosilva's sitemap 251 Given I am on joaosilva's sitemap
252 And I follow "Save the whales" 252 And I follow "Save the whales"
  253 + And the following languages "en es" are available on environment
253 Then I should not see "Add translation" 254 Then I should not see "Add translation"
254 And I follow "Edit" 255 And I follow "Edit"
255 And I select "English" from "Language" 256 And I select "English" from "Language"
@@ -267,6 +268,7 @@ Feature: edit article @@ -267,6 +268,7 @@ Feature: edit article
267 | owner | name | language | 268 | owner | name | language |
268 | joaosilva | Article in English | en | 269 | joaosilva | Article in English | en |
269 And I am on joaosilva's sitemap 270 And I am on joaosilva's sitemap
  271 + And the following languages "en pt" are available on environment
270 When I follow "Article in English" 272 When I follow "Article in English"
271 And I follow "Add translation" 273 And I follow "Add translation"
272 And I fill in "Title" with "Article in Portuguese" 274 And I fill in "Title" with "Article in Portuguese"
features/login.feature
@@ -207,18 +207,3 @@ Feature: login @@ -207,18 +207,3 @@ Feature: login
207 | Password | 123456 | 207 | Password | 123456 |
208 When I press "Log in" 208 When I press "Log in"
209 Then I should be on joaosilva's control panel 209 Then I should be on joaosilva's control panel
210 -  
211 - Scenario: join community on login  
212 - Given the following users  
213 - | login | name |  
214 - | mariasilva | Maria Silva |  
215 - And the following communities  
216 - | name | identifier | owner |  
217 - | Free Software | freesoftware | mariasilva |  
218 - And I am on /freesoftware  
219 - When I follow "Join"  
220 - And I fill in the following:  
221 - | Username / Email | joaosilva |  
222 - | Password | 123456 |  
223 - And I press "Log in"  
224 - Then "Joao Silva" should be a member of "Free Software"  
features/step_definitions/internationalization_steps.rb
@@ -22,6 +22,10 @@ Given /^Noosfero is configured to use (.+) as default$/ do |lang| @@ -22,6 +22,10 @@ Given /^Noosfero is configured to use (.+) as default$/ do |lang|
22 Noosfero.default_locale = language_to_code(lang) 22 Noosfero.default_locale = language_to_code(lang)
23 end 23 end
24 24
  25 +Given /^the following languages "([^"]*)" are available on environment$/ do |languages|
  26 + Environment.default.update_attribute(:languages, languages.split)
  27 +end
  28 +
25 After do 29 After do
26 # reset everything back to normal 30 # reset everything back to normal
27 Noosfero.default_locale = nil 31 Noosfero.default_locale = nil
lib/noosfero/plugin.rb
@@ -8,6 +8,10 @@ class Noosfero::Plugin @@ -8,6 +8,10 @@ class Noosfero::Plugin
8 self.context = context 8 self.context = context
9 end 9 end
10 10
  11 + def environment
  12 + context.environment if self.context
  13 + end
  14 +
11 class << self 15 class << self
12 16
13 attr_writer :should_load 17 attr_writer :should_load
@@ -35,6 +39,7 @@ class Noosfero::Plugin @@ -35,6 +39,7 @@ class Noosfero::Plugin
35 # filters must be loaded after all extensions 39 # filters must be loaded after all extensions
36 klasses.each do |plugin| 40 klasses.each do |plugin|
37 load_plugin_filters plugin 41 load_plugin_filters plugin
  42 + load_plugin_hotspots plugin
38 end 43 end
39 end 44 end
40 45
@@ -108,6 +113,23 @@ class Noosfero::Plugin @@ -108,6 +113,23 @@ class Noosfero::Plugin
108 end 113 end
109 end 114 end
110 115
  116 + # This is a generic method to extend the hotspots list with plugins
  117 + # hotspots. This allows plugins to extend other plugins.
  118 + # To use this, the plugin must define its hotspots inside a module Hotspots.
  119 + # Its also needed to include Noosfero::Plugin::HotSpot module
  120 + # in order to dispatch plugins methods.
  121 + #
  122 + # Checkout FooPlugin for usage example.
  123 + def load_plugin_hotspots(plugin)
  124 + ActionDispatch::Reloader.to_prepare do
  125 + begin
  126 + module_name = "#{plugin.name}::Hotspots"
  127 + Noosfero::Plugin.send(:include, module_name.constantize)
  128 + rescue NameError
  129 + end
  130 + end
  131 + end
  132 +
111 def add_controller_filters(controller_class, plugin, filters) 133 def add_controller_filters(controller_class, plugin, filters)
112 unless filters.is_a?(Array) 134 unless filters.is_a?(Array)
113 filters = [filters] 135 filters = [filters]
lib/noosfero/version.rb
1 module Noosfero 1 module Noosfero
2 PROJECT = 'noosfero' 2 PROJECT = 'noosfero'
3 - VERSION = '1.1~rc2' 3 + VERSION = '1.1~rc4'
4 end 4 end
5 5
6 root = File.expand_path(File.dirname(__FILE__) + '/../..') 6 root = File.expand_path(File.dirname(__FILE__) + '/../..')
lib/tasks/plugins_tests.rake
@@ -4,7 +4,6 @@ $broken_plugins = %w[ @@ -4,7 +4,6 @@ $broken_plugins = %w[
4 comment_classification 4 comment_classification
5 ldap 5 ldap
6 solr 6 solr
7 - stoa  
8 ] 7 ]
9 8
10 @all_plugins = Dir.glob('plugins/*').map { |f| File.basename(f) } - ['template'] 9 @all_plugins = Dir.glob('plugins/*').map { |f| File.basename(f) } - ['template']
plugins/context_content/lib/context_content_plugin/context_content_block.rb
@@ -58,7 +58,7 @@ class ContextContentPlugin::ContextContentBlock &lt; Block @@ -58,7 +58,7 @@ class ContextContentPlugin::ContextContentBlock &lt; Block
58 def contents(page, p=1) 58 def contents(page, p=1)
59 return @children unless @children.blank? 59 return @children unless @children.blank?
60 if page 60 if page
61 - @children = page.children.with_types(types).paginate(:per_page => limit, :page => p) 61 + @children = page.children.with_types(types).order(:name).paginate(:per_page => limit, :page => p)
62 (@children.blank? && show_parent_content) ? contents(page.parent, p) : @children 62 (@children.blank? && show_parent_content) ? contents(page.parent, p) : @children
63 else 63 else
64 nil 64 nil
plugins/context_content/test/unit/context_content_block_test.rb
@@ -51,18 +51,18 @@ class ContextContentBlockTest &lt; ActiveSupport::TestCase @@ -51,18 +51,18 @@ class ContextContentBlockTest &lt; ActiveSupport::TestCase
51 should 'show contents for next page' do 51 should 'show contents for next page' do
52 @block.limit = 2 52 @block.limit = 2
53 folder = fast_create(Folder) 53 folder = fast_create(Folder)
54 - article1 = fast_create(TinyMceArticle, :parent_id => folder.id)  
55 - article2 = fast_create(TinyMceArticle, :parent_id => folder.id)  
56 - article3 = fast_create(TinyMceArticle, :parent_id => folder.id) 54 + article1 = fast_create(TinyMceArticle, :name => 'article 1', :parent_id => folder.id)
  55 + article2 = fast_create(TinyMceArticle, :name => 'article 2', :parent_id => folder.id)
  56 + article3 = fast_create(TinyMceArticle, :name => 'article 3', :parent_id => folder.id)
57 assert_equal [article3], @block.contents(folder, 2) 57 assert_equal [article3], @block.contents(folder, 2)
58 end 58 end
59 59
60 should 'show parent contents for next page' do 60 should 'show parent contents for next page' do
61 @block.limit = 2 61 @block.limit = 2
62 folder = fast_create(Folder) 62 folder = fast_create(Folder)
63 - article1 = fast_create(TinyMceArticle, :parent_id => folder.id)  
64 - article2 = fast_create(TinyMceArticle, :parent_id => folder.id)  
65 - article3 = fast_create(TinyMceArticle, :parent_id => folder.id) 63 + article1 = fast_create(TinyMceArticle, :name => 'article 1', :parent_id => folder.id)
  64 + article2 = fast_create(TinyMceArticle, :name => 'article 2', :parent_id => folder.id)
  65 + article3 = fast_create(TinyMceArticle, :name => 'article 3', :parent_id => folder.id)
66 assert_equal [article3], @block.contents(article1, 2) 66 assert_equal [article3], @block.contents(article1, 2)
67 end 67 end
68 68
plugins/foo/lib/foo_plugin.rb
1 class FooPlugin < Noosfero::Plugin 1 class FooPlugin < Noosfero::Plugin
  2 + include Noosfero::Plugin::HotSpot
2 3
3 def self.plugin_name 4 def self.plugin_name
4 "Foo" 5 "Foo"
@@ -8,12 +9,29 @@ class FooPlugin &lt; Noosfero::Plugin @@ -8,12 +9,29 @@ class FooPlugin &lt; Noosfero::Plugin
8 _("A sample plugin to test autoload craziness.") 9 _("A sample plugin to test autoload craziness.")
9 end 10 end
10 11
  12 + module Hotspots
  13 + # -> Custom foo plugin hotspot
  14 + # do something to extend the FooPlugin behaviour
  15 + # receive params a, b and c
  16 + # returns = boolean or something else
  17 + def foo_plugin_my_hotspot(a, b, c)
  18 + end
  19 +
  20 + # -> Custom title for foo profiles tab
  21 + # returns = a string with a custom title
  22 + def foo_plugin_tab_title
  23 + end
  24 + end
  25 +
11 def control_panel_buttons 26 def control_panel_buttons
12 {:title => 'Foo plugin button', :icon => '', :url => ''} 27 {:title => 'Foo plugin button', :icon => '', :url => ''}
13 end 28 end
14 29
15 def profile_tabs 30 def profile_tabs
16 - {:title => 'Foo plugin tab', :id => 'foo_plugin', :content => lambda {'Foo plugin random content'} } 31 + title = plugins.dispatch_first(:foo_plugin_tab_title)
  32 + title = 'Foo plugin tab' unless title
  33 +
  34 + {:title => title, :id => 'foo_plugin', :content => lambda {'Foo plugin random content'} }
17 end 35 end
18 36
19 end 37 end
plugins/foo/test/unit/foo_plugin_test.rb
@@ -4,7 +4,25 @@ class FooPluginTest &lt; ActiveSupport::TestCase @@ -4,7 +4,25 @@ class FooPluginTest &lt; ActiveSupport::TestCase
4 def test_foo 4 def test_foo
5 FooPlugin::Bar.create! 5 FooPlugin::Bar.create!
6 end 6 end
  7 +
7 def test_monkey_patch 8 def test_monkey_patch
8 Profile.new.bar 9 Profile.new.bar
9 end 10 end
  11 +
  12 + should "respond to new hotspots" do
  13 + plugin = FooPlugin.new
  14 +
  15 + assert plugin.respond_to?(:foo_plugin_my_hotspot)
  16 + assert plugin.respond_to?(:foo_plugin_tab_title)
  17 + end
  18 +
  19 + should "other plugin respond to new hotspots" do
  20 + class TestPlugin < Noosfero::Plugin
  21 + end
  22 +
  23 + plugin = TestPlugin.new
  24 +
  25 + assert plugin.respond_to?(:foo_plugin_my_hotspot)
  26 + assert plugin.respond_to?(:foo_plugin_tab_title)
  27 + end
10 end 28 end
plugins/ldap/lib/ldap_authentication.rb
@@ -77,18 +77,20 @@ class LdapAuthentication @@ -77,18 +77,20 @@ class LdapAuthentication
77 end 77 end
78 78
79 def get_user_attributes_from_ldap_entry(entry) 79 def get_user_attributes_from_ldap_entry(entry)
80 - {  
81 - :dn => entry.dn,  
82 - :fullname => LdapAuthentication.get_attr(entry, self.attr_fullname),  
83 - :mail => LdapAuthentication.get_attr(entry, self.attr_mail),  
84 - } 80 + attributes = entry.instance_values["myhash"]
  81 +
  82 + attributes[:dn] = entry.dn
  83 + attributes[:fullname] = LdapAuthentication.get_attr(entry, self.attr_fullname)
  84 + attributes[:mail] = LdapAuthentication.get_attr(entry, self.attr_mail)
  85 +
  86 + attributes
85 end 87 end
86 88
87 # Return the attributes needed for the LDAP search. It will only 89 # Return the attributes needed for the LDAP search. It will only
88 # include the user attributes if on-the-fly registration is enabled 90 # include the user attributes if on-the-fly registration is enabled
89 def search_attributes 91 def search_attributes
90 if onthefly_register? 92 if onthefly_register?
91 - ['dn', self.attr_fullname, self.attr_mail] 93 + nil
92 else 94 else
93 ['dn'] 95 ['dn']
94 end 96 end
@@ -111,6 +113,7 @@ class LdapAuthentication @@ -111,6 +113,7 @@ class LdapAuthentication
111 end 113 end
112 login_filter = Net::LDAP::Filter.eq( self.attr_login, login ) 114 login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
113 object_filter = Net::LDAP::Filter.eq( "objectClass", "*" ) 115 object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
  116 +
114 attrs = {} 117 attrs = {}
115 118
116 search_filter = object_filter & login_filter 119 search_filter = object_filter & login_filter
plugins/ldap/lib/ldap_plugin.rb
1 require File.dirname(__FILE__) + '/ldap_authentication.rb' 1 require File.dirname(__FILE__) + '/ldap_authentication.rb'
2 2
3 class LdapPlugin < Noosfero::Plugin 3 class LdapPlugin < Noosfero::Plugin
  4 + include Noosfero::Plugin::HotSpot
4 5
5 def self.plugin_name 6 def self.plugin_name
6 "LdapPlugin" 7 "LdapPlugin"
@@ -10,6 +11,25 @@ class LdapPlugin &lt; Noosfero::Plugin @@ -10,6 +11,25 @@ class LdapPlugin &lt; Noosfero::Plugin
10 _("A plugin that add ldap support.") 11 _("A plugin that add ldap support.")
11 end 12 end
12 13
  14 + module Hotspots
  15 + # -> Custom ldap plugin hotspot to set profile data before user creation
  16 + # receive the followings params:
  17 + # - attrs with ldap received data
  18 + # - login received by ldap
  19 + # - params from current context
  20 + # returns = updated person_data hash
  21 + def ldap_plugin_set_profile_data(attrs, login, params)
  22 + end
  23 +
  24 + # -> Custom ldap plugin hotspot to update user object
  25 + # receive the followings params:
  26 + # - user: user object
  27 + # - attrs with ldap received data
  28 + # returns = none
  29 + def ldap_plugin_update_user(user, attrs)
  30 + end
  31 + end
  32 +
13 def allow_user_registration 33 def allow_user_registration
14 false 34 false
15 end 35 end
@@ -39,13 +59,15 @@ class LdapPlugin &lt; Noosfero::Plugin @@ -39,13 +59,15 @@ class LdapPlugin &lt; Noosfero::Plugin
39 user.name = attrs[:fullname] 59 user.name = attrs[:fullname]
40 user.password = password 60 user.password = password
41 user.password_confirmation = password 61 user.password_confirmation = password
42 - user.person_data = context.params[:profile_data] 62 + person_data = plugins.dispatch(:ldap_plugin_set_profile_data, attrs, login, context.params)
  63 + user.person_data = person_data.blank? ? context.params[:profile_data] : person_data
43 user.activated_at = Time.now.utc 64 user.activated_at = Time.now.utc
44 user.activation_code = nil 65 user.activation_code = nil
45 66
46 ldap = LdapAuthentication.new(context.environment.ldap_plugin_attributes) 67 ldap = LdapAuthentication.new(context.environment.ldap_plugin_attributes)
47 begin 68 begin
48 - user = nil unless user.save 69 + user = nil unless user.save!
  70 + plugins.dispatch(:ldap_plugin_update_user, user, attrs)
49 rescue 71 rescue
50 #User not saved 72 #User not saved
51 end 73 end
@@ -54,7 +76,6 @@ class LdapPlugin &lt; Noosfero::Plugin @@ -54,7 +76,6 @@ class LdapPlugin &lt; Noosfero::Plugin
54 end 76 end
55 77
56 else 78 else
57 -  
58 return nil if !user.activated? 79 return nil if !user.activated?
59 80
60 begin 81 begin
plugins/profile_description_block/test/unit/profile_description_block_test.rb
1 require File.expand_path(File.dirname(__FILE__) + "/../../../../test/test_helper") 1 require File.expand_path(File.dirname(__FILE__) + "/../../../../test/test_helper")
2 2
3 class ProfileDescriptionBlockTest < ActiveSupport::TestCase 3 class ProfileDescriptionBlockTest < ActiveSupport::TestCase
4 - def setup  
5 - e = Environment.default 4 + def setup
  5 + e = Environment.default
6 e.enabled_plugins = ['ProfileDescriptionPlugin'] 6 e.enabled_plugins = ['ProfileDescriptionPlugin']
7 @person = create_user('test_user').person 7 @person = create_user('test_user').person
8 @profile = Profile.create!(:identifier => '1236', 8 @profile = Profile.create!(:identifier => '1236',
9 :name => 'blabla', 9 :name => 'blabla',
10 :description => "") 10 :description => "")
11 - end 11 + end
12 12
13 should 'describe itself' do 13 should 'describe itself' do
14 assert_not_equal Block.description, ProfileDescriptionBlock.description 14 assert_not_equal Block.description, ProfileDescriptionBlock.description
@@ -17,7 +17,7 @@ class ProfileDescriptionBlockTest &lt; ActiveSupport::TestCase @@ -17,7 +17,7 @@ class ProfileDescriptionBlockTest &lt; ActiveSupport::TestCase
17 should "show profile description inside block" do 17 should "show profile description inside block" do
18 new_block = ProfileDescriptionBlock.create! 18 new_block = ProfileDescriptionBlock.create!
19 @profile.boxes.first.blocks << new_block 19 @profile.boxes.first.blocks << new_block
20 - block_menssage = "Description field are empty" 20 + block_menssage = "Description field is empty"
21 assert (instance_eval(&Block.last.content).include?(block_menssage)), 21 assert (instance_eval(&Block.last.content).include?(block_menssage)),
22 "description block doesn't show not found description message" 22 "description block doesn't show not found description message"
23 description = "This is an test" 23 description = "This is an test"
plugins/stoa/lib/stoa_plugin.rb
@@ -60,13 +60,14 @@ class StoaPlugin &lt; Noosfero::Plugin @@ -60,13 +60,14 @@ class StoaPlugin &lt; Noosfero::Plugin
60 end 60 end
61 61
62 def account_controller_filters 62 def account_controller_filters
63 - block = lambda do |context| 63 + block = proc do
64 params[:profile_data] ||= {} 64 params[:profile_data] ||= {}
65 params[:profile_data][:invitation_code] = params[:invitation_code] 65 params[:profile_data][:invitation_code] = params[:invitation_code]
66 invitation = Task.pending.find(:first, :conditions => {:code => params[:invitation_code]}) 66 invitation = Task.pending.find(:first, :conditions => {:code => params[:invitation_code]})
67 if request.post? 67 if request.post?
68 if !invitation && !StoaPlugin::UspUser.matches?(params[:profile_data][:usp_id], params[:confirmation_field], params[params[:confirmation_field]]) 68 if !invitation && !StoaPlugin::UspUser.matches?(params[:profile_data][:usp_id], params[:confirmation_field], params[params[:confirmation_field]])
69 - @person = Person.new(:environment => context.environment) 69 + # `self` below is evaluated in the context of account_controller
  70 + @person = Person.new(:environment => self.environment)
70 @person.errors.add(:usp_id, _(' validation failed')) 71 @person.errors.add(:usp_id, _(' validation failed'))
71 render :action => :signup 72 render :action => :signup
72 end 73 end
plugins/stoa/lib/stoa_plugin/person_api.rb
@@ -16,7 +16,7 @@ class StoaPlugin::PersonApi &lt; Noosfero::FieldsDecorator @@ -16,7 +16,7 @@ class StoaPlugin::PersonApi &lt; Noosfero::FieldsDecorator
16 end 16 end
17 17
18 def homepage 18 def homepage
19 - context.url_for(url) 19 + profile_homepage(context, object)
20 end 20 end
21 21
22 def birth_date 22 def birth_date
@@ -35,6 +35,16 @@ class StoaPlugin::PersonApi &lt; Noosfero::FieldsDecorator @@ -35,6 +35,16 @@ class StoaPlugin::PersonApi &lt; Noosfero::FieldsDecorator
35 end 35 end
36 36
37 def communities 37 def communities
38 - object.communities.public.map {|community| {:url => context.url_for(community.url), :name => community.name}} 38 + object.communities.public.map {|community| {:url => profile_homepage(context, community), :name => community.name}}
  39 + end
  40 +
  41 + private
  42 +
  43 + def profile_homepage(context, profile)
  44 + if context.respond_to?(:url_for)
  45 + context.url_for(profile.url)
  46 + else
  47 + profile.environment.top_url + '/' + profile.identifier
  48 + end
39 end 49 end
40 end 50 end
plugins/stoa/test/functional/invite_controller_test.rb
@@ -57,7 +57,7 @@ class InviteControllerTest &lt; ActionController::TestCase @@ -57,7 +57,7 @@ class InviteControllerTest &lt; ActionController::TestCase
57 organization.add_admin(admin) 57 organization.add_admin(admin)
58 58
59 login_as(admin.identifier) 59 login_as(admin.identifier)
60 - get :search_friend, :profile => organization.identifier, :q => '1234' 60 + get :search, :profile => organization.identifier, :q => '1234'
61 61
62 assert_equal [{"id" => person.id, "name" => person.name}].to_json, @response.body 62 assert_equal [{"id" => person.id, "name" => person.name}].to_json, @response.body
63 assert_response 200 63 assert_response 200
plugins/sub_organizations/features/sub_organizations_display.feature
@@ -29,6 +29,7 @@ Feature: sub_organizations_display @@ -29,6 +29,7 @@ Feature: sub_organizations_display
29 And I follow "Manage sub-groups" 29 And I follow "Manage sub-groups"
30 And I follow "Register a new sub-enterprise" 30 And I follow "Register a new sub-enterprise"
31 And I fill in "Name" with "Bart" 31 And I fill in "Name" with "Bart"
  32 + And I fill in "Address" with "bart"
32 And I press "Next" 33 And I press "Next"
33 Then I should see "Enterprise registration completed" 34 Then I should see "Enterprise registration completed"
34 And I am logged in as admin 35 And I am logged in as admin
plugins/sub_organizations/lib/ext/create_enterprise.rb
@@ -2,4 +2,5 @@ require_dependency &#39;create_enterprise&#39; @@ -2,4 +2,5 @@ require_dependency &#39;create_enterprise&#39;
2 2
3 class CreateEnterprise 3 class CreateEnterprise
4 settings_items :sub_organizations_plugin_parent_to_be 4 settings_items :sub_organizations_plugin_parent_to_be
  5 + DATA_FIELDS << 'sub_organizations_plugin_parent_to_be'
5 end 6 end
po/pt/noosfero.po
@@ -13,8 +13,8 @@ msgid &quot;&quot; @@ -13,8 +13,8 @@ msgid &quot;&quot;
13 msgstr "" 13 msgstr ""
14 "Project-Id-Version: 1.0-690-gcb6e853\n" 14 "Project-Id-Version: 1.0-690-gcb6e853\n"
15 "POT-Creation-Date: 2015-03-05 12:10-0300\n" 15 "POT-Creation-Date: 2015-03-05 12:10-0300\n"
16 -"PO-Revision-Date: 2015-03-17 21:44+0200\n"  
17 -"Last-Translator: Evandro Junior <evandrojr@gmail.com>\n" 16 +"PO-Revision-Date: 2015-03-29 01:47+0200\n"
  17 +"Last-Translator: daniel <dtygel@eita.org.br>\n"
18 "Language-Team: Portuguese " 18 "Language-Team: Portuguese "
19 "<https://hosted.weblate.org/projects/noosfero/noosfero/pt/>\n" 19 "<https://hosted.weblate.org/projects/noosfero/noosfero/pt/>\n"
20 "Language: pt\n" 20 "Language: pt\n"
@@ -7281,7 +7281,7 @@ msgstr &quot;Seu nome&quot; @@ -7281,7 +7281,7 @@ msgstr &quot;Seu nome&quot;
7281 #: app/views/cms/_upload_file_form.html.erb:4 7281 #: app/views/cms/_upload_file_form.html.erb:4
7282 #: app/views/cms/_text_editor_sidebar.html.erb:16 7282 #: app/views/cms/_text_editor_sidebar.html.erb:16
7283 msgid "Choose folder to upload files:" 7283 msgid "Choose folder to upload files:"
7284 -msgstr "Escolha uma pasta para incluir arquivos:" 7284 +msgstr "O arquivo ficará na seguinte pasta:"
7285 7285
7286 #: app/views/cms/_upload_file_form.html.erb:16 7286 #: app/views/cms/_upload_file_form.html.erb:16
7287 msgid "More files" 7287 msgid "More files"
@@ -7535,7 +7535,7 @@ msgstr &quot;Houve problemas com os seguintes arquivos:&quot; @@ -7535,7 +7535,7 @@ msgstr &quot;Houve problemas com os seguintes arquivos:&quot;
7535 7535
7536 #: app/views/cms/upload_files.html.erb:15 7536 #: app/views/cms/upload_files.html.erb:15
7537 msgid "Publish media" 7537 msgid "Publish media"
7538 -msgstr "Publicar mídia" 7538 +msgstr "Publicar imagem ou documento"
7539 7539
7540 #: app/views/cms/upload_files.html.erb:17 7540 #: app/views/cms/upload_files.html.erb:17
7541 msgid "Select the files you want to upload (max size %s):" 7541 msgid "Select the files you want to upload (max size %s):"
@@ -7551,7 +7551,7 @@ msgstr &quot;Enviando arquivos para %s&quot; @@ -7551,7 +7551,7 @@ msgstr &quot;Enviando arquivos para %s&quot;
7551 7551
7552 #: app/views/cms/_text_editor_sidebar.html.erb:8 7552 #: app/views/cms/_text_editor_sidebar.html.erb:8
7553 msgid "Insert media" 7553 msgid "Insert media"
7554 -msgstr "Adicionar mídia" 7554 +msgstr "Adicionar imagem ou documento"
7555 7555
7556 #: app/views/cms/_text_editor_sidebar.html.erb:8 7556 #: app/views/cms/_text_editor_sidebar.html.erb:8
7557 msgid "Show/Hide" 7557 msgid "Show/Hide"
@@ -7559,7 +7559,7 @@ msgstr &quot;Mostrar/Ocultar&quot; @@ -7559,7 +7559,7 @@ msgstr &quot;Mostrar/Ocultar&quot;
7559 7559
7560 #: app/views/cms/_text_editor_sidebar.html.erb:21 7560 #: app/views/cms/_text_editor_sidebar.html.erb:21
7561 msgid "New folder" 7561 msgid "New folder"
7562 -msgstr "Nova pasta" 7562 +msgstr "Criar pasta"
7563 7563
7564 #: app/views/cms/_text_editor_sidebar.html.erb:26 7564 #: app/views/cms/_text_editor_sidebar.html.erb:26
7565 msgid "Hide all uploads" 7565 msgid "Hide all uploads"
public/javascripts/report-abuse.js
1 jQuery(function($) { 1 jQuery(function($) {
2 $('.report-abuse-action').live('click', function() { 2 $('.report-abuse-action').live('click', function() {
3 - if($(this).attr('href')){  
4 - noosfero.modal.inline($(this).attr('href'), {  
5 - innerHeight: '300px',  
6 - innerWidth: '445px'  
7 - });  
8 - } 3 + if($(this).attr('href'))
  4 + noosfero.modal.url($(this).attr('href'));
  5 +
9 return false; 6 return false;
10 }); 7 });
11 8
public/stylesheets/application.css
@@ -1501,6 +1501,14 @@ a.comment-picture { @@ -1501,6 +1501,14 @@ a.comment-picture {
1501 #content .title { 1501 #content .title {
1502 margin-bottom: 2px; 1502 margin-bottom: 2px;
1503 } 1503 }
  1504 +.blog-post .post-pic {
  1505 + background-position: 50% 40%;
  1506 + background-size: cover;
  1507 + height: 150px;
  1508 +}
  1509 +.blog-post .post-pic.empty {
  1510 + display: none;
  1511 +}
1504 .metadata, .blog-post .metadata { 1512 .metadata, .blog-post .metadata {
1505 display: block; 1513 display: block;
1506 text-align: center; 1514 text-align: center;
script/production
@@ -85,7 +85,7 @@ environments_loop() { @@ -85,7 +85,7 @@ environments_loop() {
85 } 85 }
86 86
87 do_running() { 87 do_running() {
88 - pids=$(cat tmp/pids/thin.*.pid 2>/dev/null || true) 88 + pids=$(sed "s/.*/& /" tmp/pids/thin.*.pid | tr -d '\n' 2>/dev/null || true)
89 # passes if any of $pids exist, fails otherwise 89 # passes if any of $pids exist, fails otherwise
90 kill -0 $pids > /dev/null 2>&1 90 kill -0 $pids > /dev/null 2>&1
91 } 91 }
test/factories.rb
@@ -454,7 +454,7 @@ module Noosfero::Factory @@ -454,7 +454,7 @@ module Noosfero::Factory
454 end 454 end
455 455
456 def defaults_for_suggest_article 456 def defaults_for_suggest_article
457 - { :name => 'Sender', :email => 'sender@example.com', :article_name => 'Some title', :article_body => 'some body text', :article_abstract => 'some abstract text'} 457 + { :name => 'Sender', :email => 'sender@example.com', :article => {:name => 'Some title', :body => 'some body text', :abstract => 'some abstract text'}}
458 end 458 end
459 459
460 def defaults_for_comment(params = {}) 460 def defaults_for_comment(params = {})
test/functional/cms_controller_test.rb
@@ -699,7 +699,7 @@ class CmsControllerTest &lt; ActionController::TestCase @@ -699,7 +699,7 @@ class CmsControllerTest &lt; ActionController::TestCase
699 xhr :get, :update_categories, :profile => profile.identifier, :category_id => top.id 699 xhr :get, :update_categories, :profile => profile.identifier, :category_id => top.id
700 assert_template 'shared/update_categories' 700 assert_template 'shared/update_categories'
701 assert_equal top, assigns(:current_category) 701 assert_equal top, assigns(:current_category)
702 - assert_equal [c1, c2], assigns(:categories) 702 + assert_equivalent [c1, c2], assigns(:categories)
703 end 703 end
704 704
705 should 'record when coming from public view on edit' do 705 should 'record when coming from public view on edit' do
@@ -1407,22 +1407,57 @@ class CmsControllerTest &lt; ActionController::TestCase @@ -1407,22 +1407,57 @@ class CmsControllerTest &lt; ActionController::TestCase
1407 assert_template 'suggest_an_article' 1407 assert_template 'suggest_an_article'
1408 end 1408 end
1409 1409
  1410 + should 'display name and email when a not logged in user suggest an article' do
  1411 + logout
  1412 + get :suggest_an_article, :profile => profile.identifier, :back_to => 'action_view'
  1413 +
  1414 + assert_select '#task_name'
  1415 + assert_select '#task_email'
  1416 + end
  1417 +
  1418 + should 'do not display name and email when a logged in user suggest an article' do
  1419 + get :suggest_an_article, :profile => profile.identifier, :back_to => 'action_view'
  1420 +
  1421 + assert_select '#task_name', 0
  1422 + assert_select '#task_email', 0
  1423 + end
  1424 +
  1425 + should 'display captcha when suggest an article for not logged in users' do
  1426 + logout
  1427 + get :suggest_an_article, :profile => profile.identifier, :back_to => 'action_view'
  1428 +
  1429 + assert_select '#dynamic_recaptcha'
  1430 + end
  1431 +
  1432 + should 'not display captcha when suggest an article for logged in users' do
  1433 + get :suggest_an_article, :profile => profile.identifier, :back_to => 'action_view'
  1434 +
  1435 + assert_select '#dynamic_recaptcha', 0
  1436 + end
  1437 +
1410 should 'render TinyMce Editor on suggestion of article' do 1438 should 'render TinyMce Editor on suggestion of article' do
1411 logout 1439 logout
1412 get :suggest_an_article, :profile => profile.identifier 1440 get :suggest_an_article, :profile => profile.identifier
1413 1441
1414 - assert_tag :tag => 'textarea', :attributes => { :name => /article_abstract/, :class => 'mceEditor' }  
1415 - assert_tag :tag => 'textarea', :attributes => { :name => /article_body/, :class => 'mceEditor' } 1442 + assert_tag :tag => 'textarea', :attributes => { :name => /task\[article\]\[abstract\]/, :class => 'mceEditor' }
  1443 + assert_tag :tag => 'textarea', :attributes => { :name => /task\[article\]\[body\]/, :class => 'mceEditor' }
1416 end 1444 end
1417 1445
1418 should 'create a task suggest task to a profile' do 1446 should 'create a task suggest task to a profile' do
1419 c = Community.create!(:name => 'test comm', :identifier => 'test_comm', :moderated_articles => true) 1447 c = Community.create!(:name => 'test comm', :identifier => 'test_comm', :moderated_articles => true)
1420 1448
1421 assert_difference 'SuggestArticle.count' do 1449 assert_difference 'SuggestArticle.count' do
1422 - post :suggest_an_article, :profile => c.identifier, :back_to => 'action_view', :task => {:article_name => 'some name', :article_body => 'some body', :email => 'some@localhost.com', :name => 'some name'} 1450 + post :suggest_an_article, :profile => c.identifier, :back_to => 'action_view', :task => {:article => {:name => 'some name', :body => 'some body'}, :email => 'some@localhost.com', :name => 'some name'}
1423 end 1451 end
1424 end 1452 end
1425 1453
  1454 + should 'create suggest task with logged in user as the article author' do
  1455 + c = Community.create!(:name => 'test comm', :identifier => 'test_comm', :moderated_articles => true)
  1456 +
  1457 + post :suggest_an_article, :profile => c.identifier, :back_to => 'action_view', :task => {:article => {:name => 'some name', :body => 'some body'}}
  1458 + assert_equal profile, SuggestArticle.last.requestor
  1459 + end
  1460 +
1426 should 'suggest an article from a profile' do 1461 should 'suggest an article from a profile' do
1427 c = Community.create!(:name => 'test comm', :identifier => 'test_comm', :moderated_articles => true) 1462 c = Community.create!(:name => 'test comm', :identifier => 'test_comm', :moderated_articles => true)
1428 get :suggest_an_article, :profile => c.identifier, :back_to => c.identifier 1463 get :suggest_an_article, :profile => c.identifier, :back_to => c.identifier
test/functional/content_viewer_controller_test.rb
@@ -780,6 +780,20 @@ class ContentViewerControllerTest &lt; ActionController::TestCase @@ -780,6 +780,20 @@ class ContentViewerControllerTest &lt; 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/spam_controller_test.rb
@@ -10,7 +10,7 @@ class SpamControllerTest &lt; ActionController::TestCase @@ -10,7 +10,7 @@ class SpamControllerTest &lt; ActionController::TestCase
10 @article = fast_create(TextileArticle, :profile_id => @community.id) 10 @article = fast_create(TextileArticle, :profile_id => @community.id)
11 @spam_comment = fast_create(Comment, :source_id => @article.id, :spam => true, :name => 'foo', :email => 'foo@example.com') 11 @spam_comment = fast_create(Comment, :source_id => @article.id, :spam => true, :name => 'foo', :email => 'foo@example.com')
12 12
13 - @spam_suggest_article = SuggestArticle.create!(:name => 'spammer', :article_name => 'Spam article', :email => 'spammer@shady.place', :article_body => "Something you don't need", :target => @community, :spam => true) 13 + @spam_suggest_article = SuggestArticle.create!(:name => 'spammer', :article => {:name => 'Spam article', :body => "Something you don't need"}, :email => 'spammer@shady.place', :target => @community, :spam => true)
14 login_as @profile.identifier 14 login_as @profile.identifier
15 end 15 end
16 16
test/functional/tasks_controller_test.rb
@@ -264,11 +264,11 @@ class TasksControllerTest &lt; ActionController::TestCase @@ -264,11 +264,11 @@ class TasksControllerTest &lt; ActionController::TestCase
264 c = fast_create(Community) 264 c = fast_create(Community)
265 c.add_admin profile 265 c.add_admin profile
266 @controller.stubs(:profile).returns(c) 266 @controller.stubs(:profile).returns(c)
267 - t = SuggestArticle.create!(:article_name => 'test name', :article_abstract => 'test abstract', :article_body => 'test body', :name => 'some name', :email => 'test@localhost.com', :target => c) 267 + t = SuggestArticle.create!(:article => {:name => 'test name', :abstract => 'test abstract', :body => 'test body'}, :name => 'some name', :email => 'test@localhost.com', :target => c)
268 268
269 get :index 269 get :index
270 - assert_tag :tag => 'textarea', :content => /test abstract/, :attributes => { :name => /article_abstract/, :class => 'mceEditor' }  
271 - assert_tag :tag => 'textarea', :content => /test body/, :attributes => { :name => /article_body/, :class => 'mceEditor' } 270 + assert_tag :tag => 'textarea', :content => /test abstract/, :attributes => { :name => /tasks\[#{t.id}\]\[task\]\[article\]\[abstract\]/, :class => 'mceEditor' }
  271 + assert_tag :tag => 'textarea', :content => /test body/, :attributes => { :name => /tasks\[#{t.id}\]\[task\]\[article\]\[body\]/, :class => 'mceEditor' }
272 end 272 end
273 273
274 should 'create TinyMceArticle article after finish approve suggested article task' do 274 should 'create TinyMceArticle article after finish approve suggested article task' do
@@ -276,7 +276,7 @@ class TasksControllerTest &lt; ActionController::TestCase @@ -276,7 +276,7 @@ class TasksControllerTest &lt; ActionController::TestCase
276 c = fast_create(Community) 276 c = fast_create(Community)
277 c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id)) 277 c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id))
278 @controller.stubs(:profile).returns(c) 278 @controller.stubs(:profile).returns(c)
279 - t = SuggestArticle.create!(:article_name => 'test name', :article_body => 'test body', :name => 'some name', :email => 'test@localhost.com', :target => c) 279 + t = SuggestArticle.create!(:article => {:name => 'test name', :body => 'test body'}, :name => 'some name', :email => 'test@localhost.com', :target => c)
280 280
281 post :close, :tasks => {t.id => { :task => {}, :decision => "finish"}} 281 post :close, :tasks => {t.id => { :task => {}, :decision => "finish"}}
282 assert_not_nil TinyMceArticle.find(:first) 282 assert_not_nil TinyMceArticle.find(:first)
@@ -288,16 +288,13 @@ class TasksControllerTest &lt; ActionController::TestCase @@ -288,16 +288,13 @@ class TasksControllerTest &lt; ActionController::TestCase
288 c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id)) 288 c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id))
289 @controller.stubs(:profile).returns(c) 289 @controller.stubs(:profile).returns(c)
290 t = SuggestArticle.new 290 t = SuggestArticle.new
291 - t.article_name = 'test name'  
292 - t.article_body = 'test body' 291 + t.article = {:name => 'test name', :body => 'test body', :source => 'http://test.com', :source_name => 'some source name'}
293 t.name = 'some name' 292 t.name = 'some name'
294 - t.source = 'http://test.com'  
295 - t.source_name = 'some source name'  
296 t.email = 'test@localhost.com' 293 t.email = 'test@localhost.com'
297 t.target = c 294 t.target = c
298 t.save! 295 t.save!
299 296
300 - post :close, :tasks => {t.id => { :task => {:article_name => 'new article name', :article_body => 'new body', :source => 'http://www.noosfero.com', :source_name => 'new source', :name => 'new name'}, :decision => "finish"}} 297 + post :close, :tasks => {t.id => { :task => {:article => {:name => 'new article name', :body => 'new body', :source => 'http://www.noosfero.com', :source_name => 'new source'}, :name => 'new name'}, :decision => "finish"}}
301 assert_equal 'new article name', TinyMceArticle.find(:first).name 298 assert_equal 'new article name', TinyMceArticle.find(:first).name
302 assert_equal 'new name', TinyMceArticle.find(:first).author_name 299 assert_equal 'new name', TinyMceArticle.find(:first).author_name
303 assert_equal 'new body', TinyMceArticle.find(:first).body 300 assert_equal 'new body', TinyMceArticle.find(:first).body
@@ -305,6 +302,28 @@ class TasksControllerTest &lt; ActionController::TestCase @@ -305,6 +302,28 @@ class TasksControllerTest &lt; ActionController::TestCase
305 assert_equal 'new source', TinyMceArticle.find(:first).source_name 302 assert_equal 'new source', TinyMceArticle.find(:first).source_name
306 end 303 end
307 304
  305 + should "display name from article suggestion when requestor was not setted" do
  306 + Task.destroy_all
  307 + c = fast_create(Community)
  308 + c.add_admin profile
  309 + @controller.stubs(:profile).returns(c)
  310 + t = SuggestArticle.create!(:article => {:name => 'test name', :abstract => 'test abstract', :body => 'test body'}, :name => 'some name', :email => 'test@localhost.com', :target => c)
  311 +
  312 + get :index
  313 + assert_select "#tasks_#{t.id}_task_name"
  314 + end
  315 +
  316 + should "not display name from article suggestion when requestor was setted" do
  317 + Task.destroy_all
  318 + c = fast_create(Community)
  319 + c.add_admin profile
  320 + @controller.stubs(:profile).returns(c)
  321 + t = SuggestArticle.create!(:article => {:name => 'test name', :abstract => 'test abstract', :body => 'test body'}, :requestor => fast_create(Person), :target => c)
  322 +
  323 + get :index
  324 + assert_select "#tasks_#{t.id}_task_name", 0
  325 + end
  326 +
308 should "not crash if accessing close without tasks parameter" do 327 should "not crash if accessing close without tasks parameter" do
309 assert_nothing_raised do 328 assert_nothing_raised do
310 post :close 329 post :close
test/unit/article_test.rb
@@ -1715,6 +1715,18 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1715,6 +1715,18 @@ class ArticleTest &lt; 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 &lt; ActionView::TestCase @@ -20,30 +20,36 @@ class BlogHelperTest &lt; 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
test/unit/boxes_helper_test.rb
@@ -3,6 +3,7 @@ require &#39;boxes_helper&#39; @@ -3,6 +3,7 @@ require &#39;boxes_helper&#39;
3 3
4 class BoxesHelperTest < ActionView::TestCase 4 class BoxesHelperTest < ActionView::TestCase
5 5
  6 + include ApplicationHelper
6 include BoxesHelper 7 include BoxesHelper
7 include ActionView::Helpers::TagHelper 8 include ActionView::Helpers::TagHelper
8 9
@@ -181,4 +182,20 @@ class BoxesHelperTest &lt; ActionView::TestCase @@ -181,4 +182,20 @@ class BoxesHelperTest &lt; ActionView::TestCase
181 display_box_content(box, '') 182 display_box_content(box, '')
182 end 183 end
183 184
  185 + should 'display embed button when a block is embedable' do
  186 + box = create(Box, position: 1, owner: fast_create(Profile))
  187 + block = Block.create!(:box => box)
  188 + block.stubs(:embedable?).returns(true)
  189 + stubs(:url_for).returns('')
  190 + assert_tag_in_string block_edit_buttons(block), :tag => 'a', :attributes => {:class => 'button icon-button icon-embed '}
  191 + end
  192 +
  193 + should 'not display embed button when a block is not embedable' do
  194 + box = create(Box, position: 1, owner: fast_create(Profile))
  195 + block = Block.create!(:box => box)
  196 + block.stubs(:embedable?).returns(false)
  197 + stubs(:url_for).returns('')
  198 + assert_no_tag_in_string block_edit_buttons(block), :tag => 'a', :attributes => {:class => 'button icon-button icon-embed '}
  199 + end
  200 +
184 end 201 end
test/unit/suggest_article_test.rb
@@ -13,16 +13,9 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase @@ -13,16 +13,9 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase
13 13
14 should 'have the article_name' do 14 should 'have the article_name' do
15 t = SuggestArticle.new 15 t = SuggestArticle.new
16 - assert !t.errors[:article_name.to_s].present?  
17 - t.valid?  
18 - assert t.errors[:article_name.to_s].present?  
19 - end  
20 -  
21 - should 'have the article_body' do  
22 - t = SuggestArticle.new  
23 - assert !t.errors[:article_body.to_s].present?  
24 - t.valid?  
25 - assert t.errors[:article_body.to_s].present? 16 + assert !t.article_object.errors[:name].present?
  17 + t.article_object.valid?
  18 + assert t.article_object.errors[:name].present?
26 end 19 end
27 20
28 should 'have the email' do 21 should 'have the email' do
@@ -46,19 +39,12 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase @@ -46,19 +39,12 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase
46 assert t.errors[:target_id.to_s].present? 39 assert t.errors[:target_id.to_s].present?
47 end 40 end
48 41
49 - should 'have the article_abstract' do 42 + should 'have the article' do
50 t = SuggestArticle.new 43 t = SuggestArticle.new
51 - assert t.respond_to?(:article_abstract)  
52 - end  
53 -  
54 - should 'have the article_parent_id' do  
55 - t = SuggestArticle.new  
56 - assert t.respond_to?(:article_parent_id)  
57 - end  
58 -  
59 - should 'source be defined' do  
60 - t = SuggestArticle.new  
61 - assert t.respond_to?(:source) 44 + assert t.respond_to?(:article_object)
  45 + assert !t.errors[:article_object].present?
  46 + t.valid?
  47 + assert t.errors[:article_object].present?
62 end 48 end
63 49
64 should 'create an article on with perfom method' do 50 should 'create an article on with perfom method' do
@@ -66,9 +52,7 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase @@ -66,9 +52,7 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase
66 name = 'some name' 52 name = 'some name'
67 body = 'some body' 53 body = 'some body'
68 abstract = 'some abstract' 54 abstract = 'some abstract'
69 - t.article_name = name  
70 - t.article_body = body  
71 - t.article_abstract = abstract 55 + t.article = {:name => name, :body => body, :abstract => abstract}
72 t.target = @profile 56 t.target = @profile
73 count = TinyMceArticle.count 57 count = TinyMceArticle.count
74 t.perform 58 t.perform
@@ -77,8 +61,7 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase @@ -77,8 +61,7 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase
77 61
78 should 'fill source name and URL into created article' do 62 should 'fill source name and URL into created article' do
79 t = build(SuggestArticle, :target => @profile) 63 t = build(SuggestArticle, :target => @profile)
80 - t.source_name = 'GNU project'  
81 - t.source = 'http://www.gnu.org/' 64 + t.article.merge!({:source_name => 'GNU project', :source => 'http://www.gnu.org/'})
82 t.perform 65 t.perform
83 66
84 article = TinyMceArticle.last 67 article = TinyMceArticle.last
@@ -95,7 +78,7 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase @@ -95,7 +78,7 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase
95 78
96 should 'highlight created article' do 79 should 'highlight created article' do
97 t = build(SuggestArticle, :target => @profile) 80 t = build(SuggestArticle, :target => @profile)
98 - t.highlighted = true 81 + t.article[:highlighted] = true
99 t.perform 82 t.perform
100 83
101 article = TinyMceArticle.last(:conditions => { :name => t.article_name}) # just to be sure 84 article = TinyMceArticle.last(:conditions => { :name => t.article_name}) # just to be sure
@@ -132,19 +115,19 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase @@ -132,19 +115,19 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase
132 end 115 end
133 116
134 should 'have target notification message' do 117 should 'have target notification message' do
135 - task = build(SuggestArticle, :target => @profile, :article_name => 'suggested article', :name => 'johndoe') 118 + task = build(SuggestArticle, :target => @profile, :article => {:name => 'suggested article'}, :name => 'johndoe')
136 119
137 assert_match(/#{task.name}.*suggested the publication of the article: #{task.subject}.*[\n]*.*to approve or reject/, task.target_notification_message) 120 assert_match(/#{task.name}.*suggested the publication of the article: #{task.subject}.*[\n]*.*to approve or reject/, task.target_notification_message)
138 end 121 end
139 122
140 should 'have target notification description' do 123 should 'have target notification description' do
141 - task = build(SuggestArticle,:target => @profile, :article_name => 'suggested article', :name => 'johndoe') 124 + task = build(SuggestArticle,:target => @profile, :article => {:name => 'suggested article'}, :name => 'johndoe')
142 125
143 assert_match(/#{task.name}.*suggested the publication of the article: #{task.subject}/, task.target_notification_description) 126 assert_match(/#{task.name}.*suggested the publication of the article: #{task.subject}/, task.target_notification_description)
144 end 127 end
145 128
146 should 'deliver target notification message' do 129 should 'deliver target notification message' do
147 - task = build(SuggestArticle, :target => @profile, :article_name => 'suggested article', :name => 'johndoe', :email => 'johndoe@example.com') 130 + task = build(SuggestArticle, :target => @profile, :article => {:name => 'suggested article'}, :name => 'johndoe', :email => 'johndoe@example.com')
148 131
149 email = TaskMailer.target_notification(task, task.target_notification_message).deliver 132 email = TaskMailer.target_notification(task, task.target_notification_message).deliver
150 133
@@ -160,7 +143,7 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase @@ -160,7 +143,7 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase
160 should 'delegate spam detection to plugins' do 143 should 'delegate spam detection to plugins' do
161 Environment.default.enable_plugin(EverythingIsSpam) 144 Environment.default.enable_plugin(EverythingIsSpam)
162 145
163 - t1 = build(SuggestArticle, :target => @profile, :article_name => 'suggested article', :name => 'johndoe', :email => 'johndoe@example.com') 146 + t1 = build(SuggestArticle, :target => @profile, :article => {:name => 'suggested article'}, :name => 'johndoe', :email => 'johndoe@example.com')
164 147
165 EverythingIsSpam.any_instance.expects(:check_for_spam) 148 EverythingIsSpam.any_instance.expects(:check_for_spam)
166 149
@@ -189,7 +172,7 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase @@ -189,7 +172,7 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase
189 should 'notify plugins of suggest_articles being marked as spam' do 172 should 'notify plugins of suggest_articles being marked as spam' do
190 Environment.default.enable_plugin(SpamNotification) 173 Environment.default.enable_plugin(SpamNotification)
191 174
192 - t = SuggestArticle.create!(:target => @profile, :article_name => 'suggested article', :name => 'johndoe', :article_body => 'wanna feel my body? my body baaaby', :email => 'johndoe@example.com') 175 + t = SuggestArticle.create!(:target => @profile, :article => {:name => 'suggested article', :body => 'wanna feel my body? my body baaaby'}, :name => 'johndoe', :email => 'johndoe@example.com')
193 176
194 t.spam! 177 t.spam!
195 process_delayed_job_queue 178 process_delayed_job_queue
@@ -200,7 +183,7 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase @@ -200,7 +183,7 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase
200 should 'notify plugins of suggest_articles being marked as ham' do 183 should 'notify plugins of suggest_articles being marked as ham' do
201 Environment.default.enable_plugin(SpamNotification) 184 Environment.default.enable_plugin(SpamNotification)
202 185
203 - t = SuggestArticle.create!(:target => @profile, :article_name => 'suggested article', :name => 'johndoe', :article_body => 'wanna feel my body? my body baaaby', :email => 'johndoe@example.com') 186 + t = SuggestArticle.create!(:target => @profile, :article => {:name => 'suggested article', :body => 'wanna feel my body? my body baaaby'}, :name => 'johndoe', :email => 'johndoe@example.com')
204 187
205 t.ham! 188 t.ham!
206 process_delayed_job_queue 189 process_delayed_job_queue
@@ -219,10 +202,23 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase @@ -219,10 +202,23 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase
219 end 202 end
220 203
221 should 'log spammer ip after marking comment as spam' do 204 should 'log spammer ip after marking comment as spam' do
222 - t = SuggestArticle.create!(:target => @profile, :article_name => 'suggested article', :name => 'johndoe', :article_body => 'wanna feel my body? my body baaaby', :email => 'johndoe@example.com', :ip_address => '192.168.0.1') 205 + t = SuggestArticle.create!(:target => @profile, :article => {:name => 'suggested article', :body => 'wanna feel my body? my body baaaby'}, :name => 'johndoe', :email => 'johndoe@example.com', :ip_address => '192.168.0.1')
223 t.spam! 206 t.spam!
224 log = File.open('log/test_spammers.log') 207 log = File.open('log/test_spammers.log')
225 assert_match "SuggestArticle-id: #{t.id} IP: 192.168.0.1", log.read 208 assert_match "SuggestArticle-id: #{t.id} IP: 192.168.0.1", log.read
226 end 209 end
227 210
  211 + should 'not require name and email when requestor is present' do
  212 + t = SuggestArticle.new(:requestor => fast_create(Person))
  213 + t.valid?
  214 + assert t.errors[:email].blank?
  215 + assert t.errors[:name].blank?
  216 + end
  217 +
  218 + should 'return name as sender when requestor is setted' do
  219 + person = fast_create(Person)
  220 + t = SuggestArticle.new(:requestor => person)
  221 + assert_equal person.name, t.sender
  222 + end
  223 +
228 end 224 end
test/unit/user_test.rb
@@ -87,6 +87,14 @@ class UserTest &lt; ActiveSupport::TestCase @@ -87,6 +87,14 @@ class UserTest &lt; ActiveSupport::TestCase
87 assert_equal person_count + 1, Person.count 87 assert_equal person_count + 1, Person.count
88 end 88 end
89 89
  90 + def test_should_create_person_with_identifier_different_from_login
  91 + user = User.create!(:login => 'new_user', :email => 'new_user@example.com', :password => 'test', :password_confirmation => 'test', :person_data => {:identifier => "new_test"})
  92 +
  93 + assert Person.exists?(['user_id = ?', user.id])
  94 +
  95 + assert user.login != user.person.identifier
  96 + end
  97 +
90 def test_login_validation 98 def test_login_validation
91 u = User.new 99 u = User.new
92 u.valid? 100 u.valid?
@@ -355,7 +363,7 @@ class UserTest &lt; ActiveSupport::TestCase @@ -355,7 +363,7 @@ class UserTest &lt; ActiveSupport::TestCase
355 Person.any_instance.stubs(:created_at).returns(DateTime.parse('16-08-2010')) 363 Person.any_instance.stubs(:created_at).returns(DateTime.parse('16-08-2010'))
356 expected_hash = { 364 expected_hash = {
357 'login' => 'x_and_y', 'is_admin' => true, 'since_month' => 8, 365 'login' => 'x_and_y', 'is_admin' => true, 'since_month' => 8,
358 - 'chat_enabled' => false, 'since_year' => 2010, 'email_domain' => nil, 366 + 'chat_enabled' => false, 'since_year' => 2010, 'email_domain' => nil,
359 'amount_of_friends' => 0, 'friends_list' => {}, 'enterprises' => [], 367 'amount_of_friends' => 0, 'friends_list' => {}, 'enterprises' => [],
360 } 368 }
361 369