Commit 37439649ee6ea45759cf3242012249e3eaeb0d55

Authored by Victor Costa
2 parents ab47509b 423aba17

Merge branch 'rails3' of gitlab.com:noosfero/noosfero into rails3

Conflicts:
	lib/noosfero/plugin/routes.rb
	plugins/container_block/test/unit/block_test.rb
	plugins/container_block/test/unit/environment_test.rb
	plugins/container_block/test/unit/profile_test.rb
	plugins/container_block/views/blocks/container.html.erb
Showing 81 changed files with 1032 additions and 190 deletions   Show diff stats
@@ -23,7 +23,7 @@ You need to install some packages Noosfero depends on. On Debian GNU/Linux or De @@ -23,7 +23,7 @@ You need to install some packages Noosfero depends on. On Debian GNU/Linux or De
23 # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby1.8 \ 23 # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby1.8 \
24 libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libhpricot-ruby \ 24 libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libhpricot-ruby \
25 libwill-paginate-ruby iso-codes libfeedparser-ruby libdaemons-ruby thin \ 25 libwill-paginate-ruby iso-codes libfeedparser-ruby libdaemons-ruby thin \
26 - tango-icon-theme libnokogiri-ruby 26 + tango-icon-theme
27 27
28 On other systems, they may or may not be available through your regular package management system. Below are the links to their homepages. 28 On other systems, they may or may not be available through your regular package management system. Below are the links to their homepages.
29 29
@@ -41,7 +41,6 @@ On other systems, they may or may not be available through your regular package @@ -41,7 +41,6 @@ On other systems, they may or may not be available through your regular package
41 * Thin: http://code.macournoyer.com/thin 41 * Thin: http://code.macournoyer.com/thin
42 * tango-icon-theme: http://tango.freedesktop.org/Tango_Icon_Library 42 * tango-icon-theme: http://tango.freedesktop.org/Tango_Icon_Library
43 * Hpricot: http://hpricot.com 43 * Hpricot: http://hpricot.com
44 -* Nokogiri: http://nokogiri.org/  
45 44
46 If you manage to install Noosfero successfully on other systems than Debian, 45 If you manage to install Noosfero successfully on other systems than Debian,
47 please feel free to contact the Noosfero development mailing with the 46 please feel free to contact the Noosfero development mailing with the
app/controllers/admin/users_controller.rb
@@ -7,7 +7,7 @@ class UsersController < AdminController @@ -7,7 +7,7 @@ class UsersController < AdminController
7 include UsersHelper 7 include UsersHelper
8 8
9 def index 9 def index
10 - @filter = params[:filter] 10 + @filter = params[:filter] || 'all_users'
11 scope = environment.people.no_templates 11 scope = environment.people.no_templates
12 if @filter == 'admin_users' 12 if @filter == 'admin_users'
13 scope = scope.admins 13 scope = scope.admins
@@ -16,6 +16,7 @@ class UsersController < AdminController @@ -16,6 +16,7 @@ class UsersController < AdminController
16 elsif @filter == 'deactivated_users' 16 elsif @filter == 'deactivated_users'
17 scope = scope.deactivated 17 scope = scope.deactivated
18 end 18 end
  19 + scope = scope.order('name ASC')
19 @q = params[:q] 20 @q = params[:q]
20 @collection = find_by_contents(:people, scope, @q, {:per_page => per_page, :page => params[:npage]})[:results] 21 @collection = find_by_contents(:people, scope, @q, {:per_page => per_page, :page => params[:npage]})[:results]
21 end 22 end
app/controllers/application_controller.rb
@@ -24,6 +24,7 @@ class ApplicationController < ActionController::Base @@ -24,6 +24,7 @@ class ApplicationController < ActionController::Base
24 include ApplicationHelper 24 include ApplicationHelper
25 layout :get_layout 25 layout :get_layout
26 def get_layout 26 def get_layout
  27 + return nil if request.format == :js
27 theme_layout = theme_option(:layout) 28 theme_layout = theme_option(:layout)
28 if theme_layout 29 if theme_layout
29 theme_view_file('layouts/'+theme_layout) || theme_layout 30 theme_view_file('layouts/'+theme_layout) || theme_layout
app/controllers/box_organizer_controller.rb
@@ -70,7 +70,7 @@ class BoxOrganizerController < ApplicationController @@ -70,7 +70,7 @@ class BoxOrganizerController < ApplicationController
70 else 70 else
71 @center_block_types = (Box.acceptable_center_blocks & available_blocks) + plugins.dispatch(:extra_blocks, :type => boxes_holder.class, :position => 1) 71 @center_block_types = (Box.acceptable_center_blocks & available_blocks) + plugins.dispatch(:extra_blocks, :type => boxes_holder.class, :position => 1)
72 @side_block_types = (Box.acceptable_side_blocks & available_blocks) + plugins.dispatch(:extra_blocks, :type => boxes_holder.class, :position => [2,3]) 72 @side_block_types = (Box.acceptable_side_blocks & available_blocks) + plugins.dispatch(:extra_blocks, :type => boxes_holder.class, :position => [2,3])
73 - @boxes = boxes_holder.boxes 73 + @boxes = boxes_holder.boxes.with_position
74 render :action => 'add_block', :layout => false 74 render :action => 'add_block', :layout => false
75 end 75 end
76 end 76 end
app/controllers/my_profile/profile_members_controller.rb
@@ -2,7 +2,7 @@ class ProfileMembersController < MyProfileController @@ -2,7 +2,7 @@ class ProfileMembersController < MyProfileController
2 protect 'manage_memberships', :profile 2 protect 'manage_memberships', :profile
3 3
4 def index 4 def index
5 - @members = profile.members 5 + @members = profile.members_by_name
6 @member_role = environment.roles.find_by_name('member') 6 @member_role = environment.roles.find_by_name('member')
7 end 7 end
8 8
app/controllers/public/profile_controller.rb
@@ -67,7 +67,7 @@ class ProfileController < PublicController @@ -67,7 +67,7 @@ class ProfileController < PublicController
67 67
68 def members 68 def members
69 if is_cache_expired?(profile.members_cache_key(params)) 69 if is_cache_expired?(profile.members_cache_key(params))
70 - @members = profile.members.includes(relations_to_include).paginate(:per_page => members_per_page, :page => params[:npage]) 70 + @members = profile.members_by_name.includes(relations_to_include).paginate(:per_page => members_per_page, :page => params[:npage])
71 end 71 end
72 end 72 end
73 73
app/helpers/application_helper.rb
@@ -1415,16 +1415,16 @@ module ApplicationHelper @@ -1415,16 +1415,16 @@ module ApplicationHelper
1415 end 1415 end
1416 1416
1417 def convert_macro(html, source) 1417 def convert_macro(html, source)
1418 - doc = Nokogiri::HTML(html) 1418 + doc = Hpricot(html)
1419 #TODO This way is more efficient but do not support macro inside of 1419 #TODO This way is more efficient but do not support macro inside of
1420 # macro. You must parse them from the inside-out in order to enable 1420 # macro. You must parse them from the inside-out in order to enable
1421 # that. 1421 # that.
1422 - doc.css('.macro').each do |macro| 1422 + doc.search('.macro').each do |macro|
1423 macro_name = macro['data-macro'] 1423 macro_name = macro['data-macro']
1424 result = @plugins.parse_macro(macro_name, macro, source) 1424 result = @plugins.parse_macro(macro_name, macro, source)
1425 - macro.content = result.kind_of?(Proc) ? self.instance_eval(&result) : result 1425 + macro.inner_html = result.kind_of?(Proc) ? self.instance_eval(&result) : result
1426 end 1426 end
1427 - CGI.unescapeHTML(doc.xpath('//body/*').to_s) 1427 + doc.html
1428 end 1428 end
1429 1429
1430 def default_folder_for_image_upload(profile) 1430 def default_folder_for_image_upload(profile)
app/helpers/boxes_helper.rb
@@ -39,7 +39,7 @@ module BoxesHelper @@ -39,7 +39,7 @@ module BoxesHelper
39 end 39 end
40 40
41 def display_boxes(holder, main_content) 41 def display_boxes(holder, main_content)
42 - boxes = holder.boxes.first(holder.boxes_limit) 42 + boxes = holder.boxes.with_position.first(holder.boxes_limit)
43 content = boxes.reverse.map { |item| display_box(item, main_content) }.join("\n") 43 content = boxes.reverse.map { |item| display_box(item, main_content) }.join("\n")
44 content = main_content if (content.blank?) 44 content = main_content if (content.blank?)
45 45
app/models/box.rb
@@ -7,6 +7,8 @@ class Box < ActiveRecord::Base @@ -7,6 +7,8 @@ class Box < ActiveRecord::Base
7 7
8 include Noosfero::Plugin::HotSpot 8 include Noosfero::Plugin::HotSpot
9 9
  10 + named_scope :with_position, :conditions => ['boxes.position > 0']
  11 +
10 def environment 12 def environment
11 owner ? (owner.kind_of?(Environment) ? owner : owner.environment) : nil 13 owner ? (owner.kind_of?(Environment) ? owner : owner.environment) : nil
12 end 14 end
app/models/environment.rb
@@ -190,7 +190,7 @@ class Environment < ActiveRecord::Base @@ -190,7 +190,7 @@ class Environment < ActiveRecord::Base
190 has_many :states 190 has_many :states
191 has_many :cities 191 has_many :cities
192 192
193 - has_many :roles 193 + has_many :roles, :dependent => :destroy
194 194
195 has_many :qualifiers 195 has_many :qualifiers
196 has_many :certifiers 196 has_many :certifiers
app/models/link_list_block.rb
@@ -65,7 +65,7 @@ class LinkListBlock < Block @@ -65,7 +65,7 @@ class LinkListBlock < Block
65 def link_html(link) 65 def link_html(link)
66 klass = 'icon-' + link[:icon] if link[:icon] 66 klass = 'icon-' + link[:icon] if link[:icon]
67 sanitize_link( 67 sanitize_link(
68 - link_to(link[:name], expand_address(link[:address]), :target => link[:target], :class => klass) 68 + link_to(link[:name], expand_address(link[:address]), :target => link[:target], :class => klass, :title => link[:title])
69 ) 69 )
70 end 70 end
71 71
app/models/profile.rb
@@ -96,6 +96,10 @@ class Profile < ActiveRecord::Base @@ -96,6 +96,10 @@ class Profile < ActiveRecord::Base
96 ScopeTool.union *scopes 96 ScopeTool.union *scopes
97 end 97 end
98 98
  99 + def members_by_name
  100 + members.order(:name)
  101 + end
  102 +
99 def members_count 103 def members_count
100 members.count 104 members.count
101 end 105 end
app/views/blocks/location.html.erb
@@ -3,7 +3,6 @@ @@ -3,7 +3,6 @@
3 <div class='the-localization-map'> 3 <div class='the-localization-map'>
4 <img src="https://maps.google.com/maps/api/staticmap?center=<%=profile.lat%>,<%=profile.lng%>&zoom=<%=block.zoom%>&size=190x250&maptype=<%=block.map_type%>&markers=<%=profile.lat%>,<%=profile.lng%>&sensor=false"/> 4 <img src="https://maps.google.com/maps/api/staticmap?center=<%=profile.lat%>,<%=profile.lng%>&zoom=<%=block.zoom%>&size=190x250&maptype=<%=block.map_type%>&markers=<%=profile.lat%>,<%=profile.lng%>&sensor=false"/>
5 </div> 5 </div>
6 -</div>  
7 <% else %> 6 <% else %>
8 <i><%= _('This profile has no geographical position registered.') %></i> 7 <i><%= _('This profile has no geographical position registered.') %></i>
9 <% end %> 8 <% end %>
app/views/box_organizer/_link_list_block.html.erb
1 <strong><%= _('Links') %></strong> 1 <strong><%= _('Links') %></strong>
2 -<div id='edit-link-list-block' style='width:450px'> 2 +<div id='edit-link-list-block'>
3 <table id='links' class='noborder'> 3 <table id='links' class='noborder'>
4 - <tr><th><%= _('Icon') %></th><th><%= _('Name') %></th><th><%= _('Address') %></th><th><%= _('Target') %></th></tr> 4 + <tr>
  5 + <th><%= _('Icon') %></th>
  6 + <th><%= _('Name') %></th>
  7 + <th><%= _('Address') %></th>
  8 + <th><%= _('Title') %></th>
  9 + <th><%= _('Target') %></th>
  10 + </tr>
5 <% for link in @block.links do %> 11 <% for link in @block.links do %>
6 - <tr>  
7 - <td>  
8 - <%= icon_selector(link['icon']) %>  
9 - </td>  
10 - <td><%= text_field_tag 'block[links][][name]', link[:name], :class => 'link-name', :maxlength => 20 %></td>  
11 - <td class='cel-address'><%= text_field_tag 'block[links][][address]', link[:address], :class => 'link-address' %></td>  
12 - <td>  
13 - <%= select_tag('block[links][][target]', options_for_select(LinkListBlock::TARGET_OPTIONS, link[:target])) %>  
14 - </td>  
15 - </tr> 12 + <tr>
  13 + <td><%= icon_selector(link['icon']) %></td>
  14 + <td><%= text_field_tag 'block[links][][name]', link[:name], :class => 'link-name', :maxlength => 20 %></td>
  15 + <td class='cel-address'><%= text_field_tag 'block[links][][address]', link[:address], :class => 'link-address' %></td>
  16 + <td><%= text_field_tag 'block[links][][title]', link[:title], :class => 'link-title' %></td>
  17 + <td><%= select_tag('block[links][][target]', options_for_select(LinkListBlock::TARGET_OPTIONS, link[:target])) %></td>
  18 + </tr>
16 <% end %> 19 <% end %>
17 </table> 20 </table>
18 </div> 21 </div>
@@ -22,8 +25,8 @@ @@ -22,8 +25,8 @@
22 content_tag('td', icon_selector('ok')) + 25 content_tag('td', icon_selector('ok')) +
23 content_tag('td', text_field_tag('block[links][][name]', '', :maxlength => 20)) + 26 content_tag('td', text_field_tag('block[links][][name]', '', :maxlength => 20)) +
24 content_tag('td', text_field_tag('block[links][][address]', nil, :class => 'link-address'), :class => 'cel-address') + 27 content_tag('td', text_field_tag('block[links][][address]', nil, :class => 'link-address'), :class => 'cel-address') +
25 - content_tag('td', select_tag('block[links][][target]',  
26 -options_for_select(LinkListBlock::TARGET_OPTIONS, '_self'))) 28 + content_tag('td', text_field_tag('block[links][][title]', '', :class => 'link-title')) +
  29 + content_tag('td', select_tag('block[links][][target]', options_for_select(LinkListBlock::TARGET_OPTIONS, '_self')))
27 ) + 30 ) +
28 javascript_tag("$('edit-link-list-block').scrollTop = $('edit-link-list-block').scrollHeight")) 31 javascript_tag("$('edit-link-list-block').scrollTop = $('edit-link-list-block').scrollHeight"))
29 end %> 32 end %>
app/views/content_viewer/view_page.html.erb
@@ -40,14 +40,6 @@ @@ -40,14 +40,6 @@
40 </div> 40 </div>
41 <% end %> 41 <% end %>
42 42
43 -<% if !@page.tags.empty? %>  
44 - <div id="article-tags">  
45 - <%= _("This article's tags:") %>  
46 - <%= @page.tags.map { |t| link_to(t, :controller => 'profile', :profile => @profile.identifier, :action => 'tags', :id => t.name ) }.join("\n") %>  
47 - </div>  
48 -<% end %>  
49 -  
50 -  
51 <%= render :partial => 'shared/disabled_enterprise' %> 43 <%= render :partial => 'shared/disabled_enterprise' %>
52 44
53 <% if NOOSFERO_CONF['addthis_enabled'] %> 45 <% if NOOSFERO_CONF['addthis_enabled'] %>
@@ -83,6 +75,13 @@ @@ -83,6 +75,13 @@
83 </div> 75 </div>
84 <% end %> 76 <% end %>
85 77
  78 +<% if !@page.tags.empty? %>
  79 + <div id="article-tags">
  80 + <%= _("This article's tags:") %>
  81 + <%= @page.tags.map { |t| link_to(t, :controller => 'profile', :profile => @profile.identifier, :action => 'tags', :id => t.name ) }.join("\n") %>
  82 + </div>
  83 +<% end %>
  84 +
86 <%= display_source_info(@page) %> 85 <%= display_source_info(@page) %>
87 86
88 <div class="comments" id="comments_list"> 87 <div class="comments" id="comments_list">
app/views/profile_members/_members_list.html.erb
1 -<% collection = @collection == :profile_admins ? profile.admins : profile.members %> 1 +<% collection = @collection == :profile_admins ? profile.admins : profile.members_by_name %>
2 <% title = @title ? @title : _('Current members') %> 2 <% title = @title ? @title : _('Current members') %>
3 <% remove_action = @remove_action ? @remove_action : {:action => 'unassociate'} %> 3 <% remove_action = @remove_action ? @remove_action : {:action => 'unassociate'} %>
4 4
debian/changelog
  1 +noosfero (0.46.1) unstable; urgency=low
  2 +
  3 + * Bugfixes release
  4 +
  5 + -- Daniela Soares Feitosa <daniela@colivre.coop.br> Fri, 07 Mar 2014 10:33:11 +0000
  6 +
1 noosfero (0.46.0) unstable; urgency=low 7 noosfero (0.46.0) unstable; urgency=low
2 8
3 * New features release 9 * New features release
lib/noosfero.rb
@@ -4,7 +4,7 @@ require &#39;fast_gettext&#39; @@ -4,7 +4,7 @@ require &#39;fast_gettext&#39;
4 4
5 module Noosfero 5 module Noosfero
6 PROJECT = 'noosfero' 6 PROJECT = 'noosfero'
7 - VERSION = '0.46.0' 7 + VERSION = '0.46.1'
8 8
9 def self.pattern_for_controllers_in_directory(dir) 9 def self.pattern_for_controllers_in_directory(dir)
10 disjunction = controllers_in_directory(dir).join('|') 10 disjunction = controllers_in_directory(dir).join('|')
lib/noosfero/core_ext/array.rb 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +class Array
  2 +
  3 + def uniq_by
  4 + hash, array = {}, []
  5 + each { |i| hash[yield(i)] ||= (array << i) }
  6 + array
  7 + end
  8 +
  9 +end
lib/noosfero/plugin/macro.rb
@@ -33,9 +33,9 @@ class Noosfero::Plugin::Macro @@ -33,9 +33,9 @@ class Noosfero::Plugin::Macro
33 end 33 end
34 34
35 def attributes(macro) 35 def attributes(macro)
36 - macro.attributes. 36 + macro.attributes.to_hash.
37 select {|key, value| key[0..10] == 'data-macro-'}. 37 select {|key, value| key[0..10] == 'data-macro-'}.
38 - inject({}){|result, a| result.merge({a[0][11..-1] => a[1].value})}. 38 + inject({}){|result, a| result.merge({a[0][11..-1] => a[1]})}.
39 with_indifferent_access 39 with_indifferent_access
40 end 40 end
41 41
lib/noosfero/plugin/routes.rb
@@ -15,7 +15,11 @@ Dir.glob(Rails.root.join(plugins_root, &#39;*&#39;, &#39;controllers&#39;)) do |controllers_dir| @@ -15,7 +15,11 @@ Dir.glob(Rails.root.join(plugins_root, &#39;*&#39;, &#39;controllers&#39;)) do |controllers_dir|
15 controllers_by_folder.each do |folder, controllers| 15 controllers_by_folder.each do |folder, controllers|
16 controllers.each do |controller| 16 controllers.each do |controller|
17 controller_name = controller.gsub("#{plugin_name}_plugin_",'') 17 controller_name = controller.gsub("#{plugin_name}_plugin_",'')
18 - match "#{prefixes_by_folder[folder]}/#{plugin_name}/#{controller_name}(/:action(/:id))", :controller => controller 18 + if %w[profile myprofile].include?(folder)
  19 + match "#{prefixes_by_folder[folder]}/#{plugin_name}/#{controller_name}(/:action(/:id))", :controller => controller, :profile => /#{Noosfero.identifier_format}/
  20 + else
  21 + match "#{prefixes_by_folder[folder]}/#{plugin_name}/#{controller_name}(/:action(/:id))", :controller => controller
  22 + end
19 end 23 end
20 end 24 end
21 25
plugins/comment_classification/README.md 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +README - Comment Classification Plugin
  2 +======================================
  3 +
  4 +This plugin creates the structure for classifying the comments. The
  5 +initial idea of this plugin is to support the management of public
  6 +consulting, but it can be used in different contexts.
  7 +For now, two kind of classification will be available:
  8 +
  9 + * Label: when creating a comment, the user identify the kind of it by
  10 +choosing the label of the comment. Example: "Suggestion",
  11 +"Disagreement"...
  12 + * Status: users with permission can include a Status for a comment.
  13 +Example: "Merged", "Unmerged"
  14 +
  15 +Dependency
  16 +==========
  17 +
  18 +This plugin was developed to help public consulting and needs the
  19 +CommentGroupPlugin enabled to be used.
plugins/comment_classification/controllers/admin/comment_classification_plugin_labels_controller.rb 0 → 100644
@@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
  1 +class CommentClassificationPluginLabelsController < AdminController
  2 + append_view_path File.join(File.dirname(__FILE__) + '/../../views')
  3 +
  4 + def index
  5 +# @labels = @environment.labels
  6 + @labels = CommentClassificationPlugin::Label.all
  7 + end
  8 +
  9 + def create
  10 + @label = CommentClassificationPlugin::Label.new(params[:label])
  11 + @colors = CommentClassificationPlugin::Label::COLORS
  12 + if request.post?
  13 + begin
  14 + @label.owner = environment
  15 + @label.save!
  16 + session[:notice] = _('Label created')
  17 + redirect_to :action => 'index'
  18 + rescue
  19 + session[:notice] = _('Label could not be created')
  20 + end
  21 + end
  22 + end
  23 +
  24 + def edit
  25 +# @labels = @environment.labels.find(params[:id])
  26 + @label = CommentClassificationPlugin::Label.find(params[:id])
  27 + @colors = CommentClassificationPlugin::Label::COLORS
  28 + if request.post?
  29 + begin
  30 + @label.update_attributes!(params[:label])
  31 + session[:notice] = _('Label updated')
  32 + redirect_to :action => :index
  33 + rescue
  34 + session[:notice] = _('Failed to edit label')
  35 + end
  36 + end
  37 + end
  38 +
  39 + def remove
  40 +# @label = environment.labels.find(params[:label])
  41 + @label = CommentClassificationPlugin::Label.find(params[:id])
  42 + if request.post?
  43 + begin
  44 + @label.destroy
  45 + session[:notice] = _('Label removed')
  46 + rescue
  47 + session[:notice] = _('Label could not be removed')
  48 + end
  49 + else
  50 + session[:notice] = _('Label could not be removed')
  51 + end
  52 + redirect_to :action => 'index'
  53 + end
  54 +
  55 +end
plugins/comment_classification/controllers/admin/comment_classification_plugin_status_controller.rb 0 → 100644
@@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
  1 +class CommentClassificationPluginStatusController < AdminController
  2 + append_view_path File.join(File.dirname(__FILE__) + '/../../views')
  3 +
  4 + def index
  5 +# @labels = @environment.labels
  6 + @status = CommentClassificationPlugin::Status.all
  7 + end
  8 +
  9 + def create
  10 + @status = CommentClassificationPlugin::Status.new(params[:status])
  11 + if request.post?
  12 + begin
  13 + @status.owner = environment
  14 + @status.save!
  15 + session[:notice] = _('Status created')
  16 + redirect_to :action => 'index'
  17 + rescue
  18 + session[:notice] = _('Status could not be created')
  19 + end
  20 + end
  21 + end
  22 +
  23 + def edit
  24 +# @labels = @environment.labels.find(params[:id])
  25 + @status = CommentClassificationPlugin::Status.find(params[:id])
  26 + if request.post?
  27 + begin
  28 + @status.update_attributes!(params[:status])
  29 + session[:notice] = _('Status updated')
  30 + redirect_to :action => :index
  31 + rescue
  32 + session[:notice] = _('Failed to edit status')
  33 + end
  34 + end
  35 + end
  36 +
  37 + def remove
  38 +# @label = environment.labels.find(params[:label])
  39 + @status = CommentClassificationPlugin::Status.find(params[:id])
  40 + if request.post?
  41 + begin
  42 + @status.destroy
  43 + session[:notice] = _('Status removed')
  44 + rescue
  45 + session[:notice] = _('Status could not be removed')
  46 + end
  47 + else
  48 + session[:notice] = _('Status could not be removed')
  49 + end
  50 + redirect_to :action => 'index'
  51 + end
  52 +
  53 +end
plugins/comment_classification/controllers/comment_classification_plugin_admin_controller.rb 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +class CommentClassificationPluginAdminController < AdminController
  2 + append_view_path File.join(File.dirname(__FILE__) + '/../views')
  3 +
  4 + def index
  5 + end
  6 +
  7 +end
plugins/comment_classification/controllers/comment_classification_plugin_myprofile_controller.rb 0 → 100644
@@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
  1 +class CommentClassificationPluginMyprofileController < MyProfileController
  2 + append_view_path File.join(File.dirname(__FILE__) + '/../views')
  3 +
  4 + before_filter :organizations_only
  5 + protect 'moderate_comments', :profile
  6 +
  7 + def index
  8 + @comments = Comment.all
  9 + end
  10 +
  11 + def add_status
  12 + @comment = Comment.find(params[:id])
  13 + @statuses = CommentClassificationPlugin::Status.enabled
  14 + @status = CommentClassificationPlugin::CommentStatusUser.new(:profile => user, :comment => @comment)
  15 + if request.post? && params[:status]
  16 + @status.update_attributes(params[:status])
  17 + @status.save
  18 + end
  19 + end
  20 +
  21 + private
  22 +
  23 + def organizations_only
  24 + render_not_found if !profile.organization?
  25 + end
  26 +end
plugins/comment_classification/db/migrate/20130822043033_create_comments_labels.rb 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +class CreateCommentsLabels < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :comment_classification_plugin_labels do |t|
  4 + t.string :name
  5 + t.string :color
  6 + t.boolean :enabled, :default => true
  7 + t.references :owner, :polymorphic => true
  8 +
  9 + t.timestamps
  10 + end
  11 + end
  12 +
  13 + def self.down
  14 + drop_table :comment_classification_plugin_labels
  15 + end
  16 +end
plugins/comment_classification/db/migrate/20130822075623_create_comment_label_user.rb 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +class CreateCommentLabelUser < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :comment_classification_plugin_comment_label_user do |t|
  4 + t.references :profile
  5 + t.references :comment
  6 + t.references :label
  7 +
  8 + t.timestamps
  9 + end
  10 +
  11 + end
  12 +
  13 + def self.down
  14 + drop_table :comment_classification_plugin_comment_label_user
  15 + end
  16 +end
plugins/comment_classification/db/migrate/20130829130226_create_comment_status.rb 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +class CreateCommentStatus < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :comment_classification_plugin_statuses do |t|
  4 + t.string :name
  5 + t.boolean :enabled, :default => true
  6 + t.boolean :enable_reason, :default => true
  7 + t.references :owner, :polymorphic => true
  8 + t.timestamps
  9 + end
  10 +
  11 + end
  12 +
  13 + def self.down
  14 + drop_table :comment_classification_plugin_statuses
  15 + end
  16 +end
plugins/comment_classification/db/migrate/20130829144037_create_comment_status_user.rb 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +class CreateCommentStatusUser < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :comment_classification_plugin_comment_status_user do |t|
  4 + t.references :profile
  5 + t.references :comment
  6 + t.references :status
  7 + t.text :reason
  8 +
  9 + t.timestamps
  10 + end
  11 + end
  12 +
  13 + def self.down
  14 + drop_table :comment_classification_plugin_comment_status_user
  15 + end
  16 +end
plugins/comment_classification/features/labels.feature 0 → 100644
@@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
  1 +Feature:
  2 + As a user
  3 + I want to add label for comments
  4 +
  5 +Background:
  6 + Given the following users
  7 + | login | name |
  8 + | joaosilva | Joao Silva |
  9 + | mariasilva | Maria Silva |
  10 + And the following communities
  11 + | identifier | name |
  12 + | sample-community | Sample Community |
  13 + And the following articles
  14 + | owner | name | body |
  15 + | sample-community | Article to comment | First post |
  16 + And CommentClassificationPlugin is enabled
  17 + And "Maria Silva" is a member of "Sample Community"
  18 + And "Joao Silva" is admin of "Sample Community"
  19 + And I am logged in as "joaosilva"
  20 +
  21 + @selenium
  22 + Scenario: dont display labels if admin did not configure status
  23 + Given I am on article "Article to comment"
  24 + And I follow "Post a comment"
  25 + Then I should not see "Label" within "#page-comment-form"
  26 +
  27 + Scenario: admin configure labels
  28 + Given I am logged in as "admin_user"
  29 + And I am on the environment control panel
  30 + And I follow "Plugins"
  31 + And I follow "Configuration"
  32 + And I follow "Manage Labels"
  33 + Then I should see "no label registered yet" within "#comment-classification-labels"
  34 + When I follow "Add a new label"
  35 + And I fill in "Name" with "Question"
  36 + And I check "Enable this label"
  37 + And I press "Save"
  38 + Then I should see "Question" within "#comment-classification-labels"
  39 +
  40 + @selenium
  41 + Scenario: save label for comment
  42 + Given the following labels
  43 + | owner | name | enabled |
  44 + | environment | Addition | true |
  45 + And I go to article "Article to comment"
  46 + And I follow "Post a comment"
  47 + And I fill in "Enter your comment" with "Hey ho, let's go!"
  48 + Then I select "Addition" from "comment_label_id"
  49 + And I press "Post comment"
  50 + Then I should see "Addition" within ".comment-details"
  51 +
  52 + @selenium
  53 + Scenario: users without permission should not edit the labels
  54 + Given the following labels
  55 + | owner | name | enabled |
  56 + | environment | Addition | true |
  57 + And I go to article "Article to comment"
  58 + And I follow "Post a comment"
  59 + Then I should see "Label" within "#page-comment-form"
  60 + And I should see "Addition" within "#comment_label_id"
  61 + When I am not logged in
  62 + And I am on article "Article to comment"
  63 + And I follow "Post a comment"
  64 + Then I should not see "Label" within "#page-comment-form"
plugins/comment_classification/features/status.feature 0 → 100644
@@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
  1 +Feature:
  2 + As a user
  3 + I want to add status for comments
  4 +
  5 +Background:
  6 + Given the following users
  7 + | login | name |
  8 + | joaosilva | Joao Silva |
  9 + | mariasilva | Maria Silva |
  10 + And the following communities
  11 + | identifier | name |
  12 + | sample-community | Sample Community |
  13 + And the following articles
  14 + | owner | name | body |
  15 + | sample-community | Article to comment | First post |
  16 + And the following comments
  17 + | article | author | body |
  18 + | Article to comment | mariasilva | great post! |
  19 + And CommentClassificationPlugin is enabled
  20 + And "Maria Silva" is a member of "Sample Community"
  21 + And "Joao Silva" is admin of "Sample Community"
  22 + And I am logged in as "joaosilva"
  23 +
  24 + Scenario: dont display to add status if not an organization
  25 + Given the following articles
  26 + | owner | name | body |
  27 + | joaosilva | Article on a person profile | First post |
  28 + And the following comments
  29 + | article | author | body |
  30 + | Article on a person profile | mariasilva | great post! |
  31 + Given I am on article "Article on a person profile"
  32 + Then I should see "great post!" within ".comment-details"
  33 + And I should not see "Status" within ".comment-details"
  34 +
  35 + Scenario: dont display to add status if admin did not configure status
  36 + Given I am on article "Article to comment"
  37 + Then I should see "great post!" within ".comment-details"
  38 + And I should not see "Status" within ".comment-details"
  39 +
  40 + Scenario: admin configure status
  41 + Given I am logged in as "admin_user"
  42 + And I am on the environment control panel
  43 + And I follow "Plugins"
  44 + And I follow "Configuration"
  45 + And I follow "Manage Status"
  46 + Then I should see "no status registered yet" within "#comment-classification-status"
  47 + When I follow "Add a new status"
  48 + And I fill in "Name" with "Merged"
  49 + And I check "Enable this status"
  50 + And I press "Save"
  51 + Then I should see "Merged" within "#comment-classification-status"
  52 +
  53 + Scenario: save status for comment
  54 + Given the following status
  55 + | owner | name | enabled |
  56 + | environment | Merged | true |
  57 + And I go to article "Article to comment"
  58 + And I follow "Status"
  59 + Then I select "Merged" from "status_status_id"
  60 + And I press "Save"
  61 + Then I should see "added the status Merged" within "#comment-classification-status-list"
  62 +
  63 + Scenario: dont display to add status if user not allowed
  64 + Given I am logged in as "mariasilva"
  65 + When I go to article "Article to comment"
  66 + Then I should see "great post!" within ".comment-details"
  67 + And I should not see "Status" within ".comment-details"
plugins/comment_classification/features/step_definitions/plugin_steps.rb 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +Given /^CommentClassificationPlugin is enabled$/ do
  2 + Given %{I am logged in as admin}
  3 + And %{I am on the environment control panel}
  4 + And %{I follow "Plugins"}
  5 + And %{I check "Comment Classification"}
  6 + And %{I press "Save changes"}
  7 + Environment.default.enabled_plugins.should include("CommentClassificationPlugin")
  8 +end
  9 +
  10 +Given /^the following labels$/ do |table|
  11 + table.hashes.map{|item| item.dup}.each do |item|
  12 + owner_type = item.delete('owner')
  13 + owner = owner_type == 'environment' ? Environment.default : Profile[owner_type]
  14 + CommentClassificationPlugin::Label.create!(item)
  15 + end
  16 +end
  17 +
  18 +Given /^the following status$/ do |table|
  19 + table.hashes.map{|item| item.dup}.each do |item|
  20 + owner_type = item.delete('owner')
  21 + owner = owner_type == 'environment' ? Environment.default : Profile[owner_type]
  22 + CommentClassificationPlugin::Status.create!(item)
  23 + end
  24 +end
plugins/comment_classification/lib/comment_classification_plugin.rb 0 → 100644
@@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
  1 +require 'ext/environment'
  2 +require 'ext/comment'
  3 +
  4 +class CommentClassificationPlugin < Noosfero::Plugin
  5 +
  6 + def self.plugin_name
  7 + "Comment Classification"
  8 + end
  9 +
  10 + def self.plugin_description
  11 + _("A plugin that allow classification of comments.")
  12 + end
  13 +
  14 +#TODO Each organization can add its own status and labels
  15 +# def control_panel_buttons
  16 +# if context.profile.organization?
  17 +# { :title => _('Manage comment classification'), :icon => 'comment_classification', :url => {:controller => 'comment_classification_plugin_myprofile'} }
  18 +# end
  19 +# end
  20 +
  21 + def comment_form_extra_contents(args)
  22 + comment = args[:comment]
  23 + lambda {
  24 + render :file => 'comment/comments_labels_select.rhtml', :locals => {:comment => comment }
  25 + }
  26 + end
  27 +
  28 + def comment_extra_contents(args)
  29 + comment = args[:comment]
  30 + lambda {
  31 + render :file => 'comment/comment_extra.rhtml', :locals => {:comment => comment}
  32 + }
  33 + end
  34 +
  35 + def process_extra_comment_params(args)
  36 + comment = Comment.find args[0]
  37 + label_id = args[1][:comment_label_id]
  38 + if label_id.blank?
  39 + if !CommentClassificationPlugin::CommentLabelUser.find_by_comment_id(comment.id).nil?
  40 + CommentClassificationPlugin::CommentLabelUser.find_by_comment_id(comment.id).destroy
  41 + end
  42 + else
  43 + label = CommentClassificationPlugin::Label.find label_id
  44 + relation = CommentClassificationPlugin::CommentLabelUser.new(:profile => comment.author, :comment => comment, :label => label )
  45 + relation.save
  46 + end
  47 + end
  48 +
  49 + def js_files
  50 + 'comment_classification.js'
  51 + end
  52 +
  53 + def stylesheet?
  54 + true
  55 + end
  56 +
  57 +end
plugins/comment_classification/lib/comment_classification_plugin/comment_label_user.rb 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +class CommentClassificationPlugin::CommentLabelUser < Noosfero::Plugin::ActiveRecord
  2 + set_table_name :comment_classification_plugin_comment_label_user
  3 +
  4 + belongs_to :profile
  5 + belongs_to :comment
  6 + belongs_to :label, :class_name => 'CommentClassificationPlugin::Label'
  7 +
  8 + validates_presence_of :profile
  9 + validates_presence_of :comment
  10 + validates_presence_of :label
  11 +end
plugins/comment_classification/lib/comment_classification_plugin/comment_status_user.rb 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +class CommentClassificationPlugin::CommentStatusUser < Noosfero::Plugin::ActiveRecord
  2 + set_table_name :comment_classification_plugin_comment_status_user
  3 +
  4 + belongs_to :profile
  5 + belongs_to :comment
  6 + belongs_to :status, :class_name => 'CommentClassificationPlugin::Status'
  7 +
  8 + validates_presence_of :profile
  9 + validates_presence_of :comment
  10 + validates_presence_of :status
  11 +end
plugins/comment_classification/lib/comment_classification_plugin/label.rb 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +class CommentClassificationPlugin::Label < Noosfero::Plugin::ActiveRecord
  2 +
  3 + belongs_to :owner, :polymorphic => true
  4 +
  5 + validates_presence_of :name
  6 +
  7 + named_scope :enabled, :conditions => { :enabled => true }
  8 +
  9 + COLORS = ['red', 'green', 'yellow', 'gray', 'blue']
  10 +end
plugins/comment_classification/lib/comment_classification_plugin/status.rb 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +class CommentClassificationPlugin::Status < Noosfero::Plugin::ActiveRecord
  2 +
  3 + belongs_to :owner, :polymorphic => true
  4 +
  5 + validates_presence_of :name
  6 +
  7 + named_scope :enabled, :conditions => { :enabled => true }
  8 +end
plugins/comment_classification/lib/ext/comment.rb 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +require_dependency 'comment'
  2 +require 'comment_classification_plugin.rb'
  3 +require 'comment_classification_plugin/label.rb'
  4 +
  5 +class Comment
  6 +
  7 + has_one :comment_classification_plugin_comment_label_user, :class_name => 'CommentClassificationPlugin::CommentLabelUser'
  8 + has_one :label, :through => :comment_classification_plugin_comment_label_user, :foreign_key => 'label_id'
  9 +
  10 + has_many :comment_classification_plugin_comment_status_users, :class_name => 'CommentClassificationPlugin::CommentStatusUser'
  11 + has_many :statuses, :through => :comment_classification_plugin_comment_status_users, :foreign_key => 'status_id'
  12 +
  13 +end
plugins/comment_classification/lib/ext/environment.rb 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +require_dependency 'environment'
  2 +
  3 +class Environment
  4 +
  5 + has_many :labels, :as => :owner, :class_name => 'CommentClassificationPlugin::Label'
  6 +
  7 +end
  8 +
plugins/comment_classification/public/images/comment-classification.png 0 → 100644

4.15 KB

plugins/comment_classification/public/style.css 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +.controller-profile_editor .control-panel a.control-panel-comment_classification {
  2 + background-image: url(images/comment-classification.png);
  3 +}
  4 +
  5 +#content .comment-classification-options .label-name {
  6 + font-style: italic;
  7 +}
  8 +
  9 +#content .comment-classification-options a.button {
  10 + background-color: transparent;
  11 + border: none;
  12 +}
plugins/comment_classification/views/comment/comment_extra.rhtml 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +<div class='comment-classification-options'>
  2 +
  3 + <% unless comment.label.nil? %>
  4 + <p class='label-name' style='color:<%= comment.label.color %>'>
  5 + <%= comment.label.name %>
  6 + </p>
  7 + <% end %>
  8 +
  9 + <% statuses = CommentClassificationPlugin::Status.enabled %>
  10 + <% if profile.organization? && user && user.has_permission?(:moderate_comments, profile) && !statuses.empty? %>
  11 + <div class='comment-classification-status'>
  12 + <%= link_to(_('Status'), :profile => profile.identifier, :controller => :comment_classification_plugin_myprofile, :action => :add_status, :id => comment.id)
  13 + %>
  14 + </div>
  15 + <% end %>
  16 +
  17 +</div>
plugins/comment_classification/views/comment/comments_labels_select.rhtml 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +<% labels = CommentClassificationPlugin::Label.enabled %>
  2 +<% if logged_in? && user.has_permission?(:moderate_comments, profile) && !labels.empty? %>
  3 + <%= labelled_form_field(_('Label'), select_tag('comment_label_id', options_for_select( [[_('[Select ...]'), nil]] + labels.map{|l|[l.name,l.id]}, @comment.label.nil? ? '' : @comment.label.id))) %>
  4 +<% end %>
plugins/comment_classification/views/comment_classification_plugin_admin/index.rhtml 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +<h1><%= _('Comments classification options')%></h1>
  2 +
  3 +<ul>
  4 + <li><%= link_to _('Manage Labels'), :controller => 'comment_classification_plugin_labels' %></li>
  5 + <li><%= link_to _('Manage Status'), :controller => 'comment_classification_plugin_status' %></li>
  6 +</ul>
plugins/comment_classification/views/comment_classification_plugin_labels/_form.rhtml 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +<%= error_messages_for :label %>
  2 +
  3 +<% form_for :label, @label do |f| %>
  4 + <%= required_fields_message %>
  5 +
  6 + <%= required labelled_form_field(_('Name'), f.text_field(:name)) %>
  7 + <%= labelled_form_field(_('Color'), f.select(:color, @colors.map{|s|[s.capitalize,s]})) %>
  8 + <%= labelled_form_field(f.check_box(:enabled) + _('Enable this label?'),'') %>
  9 +
  10 + <% button_bar do %>
  11 + <%= submit_button('save', _('Save'), :cancel => {:action => 'index'} ) %>
  12 + <% end %>
  13 +<% end %>
plugins/comment_classification/views/comment_classification_plugin_labels/create.rhtml 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<h2> <%= _("Add a new label") %> </h2>
  2 +
  3 +<%= render :partial => 'form' %>
plugins/comment_classification/views/comment_classification_plugin_labels/edit.rhtml 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<h2> <%= _("Editing label %s") % @label.name %> </h2>
  2 +
  3 +<%= render :partial => 'form' %>
plugins/comment_classification/views/comment_classification_plugin_labels/index.rhtml 0 → 100644
@@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
  1 +<h1><%= _("Manage comments labels") %></h1>
  2 +
  3 +<div id='comment-classification-labels'>
  4 + <% if @labels.empty? %>
  5 + <%= _('(no label registered yet)') %>
  6 + <% else %>
  7 + <table>
  8 + <tr>
  9 + <th><%= _('Label') %></th>
  10 + <th><%= _('Color') %></th>
  11 + <th><%= _('Enabled') %></th>
  12 + <th><%= _('Actions') %></th>
  13 + </tr>
  14 + <% @labels.each do |label| %>
  15 + <tr>
  16 + <td><%= label.name %></td>
  17 + <td><%= label.color %></td>
  18 + <td><%= label.enabled %></td>
  19 + <td>
  20 + <%= button_without_text :edit, _('Edit'), {:action => 'edit', :id => label} %>
  21 + <%= button_without_text :delete, _('Remove'), {:action => 'destroy', :id => label}, :confirm => _('Are you sure you want to remove this label?') %>
  22 + </td>
  23 + </tr>
  24 + <% end %>
  25 + </table>
  26 + <% end %>
  27 +
  28 + <% button_bar do %>
  29 + <%= button(:add, _('Add a new label'), :action => 'create')%>
  30 + <%= button :back, _('Back to admin panel'), :controller => 'admin_panel' %>
  31 + <% end %>
  32 +</div>
plugins/comment_classification/views/comment_classification_plugin_myprofile/_status_form.html.erb 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +<%= error_messages_for :status %>
  2 +
  3 +<% form_for :status, @status do |f| %>
  4 + <%= required_fields_message %>
  5 +
  6 + <%= labelled_form_field(_('Status'), f.select(:status_id, @statuses.map{|s|[s.name,s.id]})) %>
  7 + <%= labelled_form_field(_('Reason:'), f.text_area(:reason, :rows => 5)) %>
  8 +
  9 + <% button_bar do %>
  10 + <%= submit_button('save', _('Save') ) %>
  11 + <% end %>
  12 +<% end %>
plugins/comment_classification/views/comment_classification_plugin_myprofile/add_status.html.erb 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +<h1><%= _('Status for comment') %></h1>
  2 +
  3 +<div id='comment-classification-status-list'>
  4 + <% unless @comment.title.blank? %>
  5 + <div class='comment-title'><%= _("Title: %s") % @comment.title %></div>
  6 + <% end %>
  7 +
  8 + <b><%= _('Body:') %></b>
  9 + <p><%= @comment.body %></p>
  10 +
  11 + <h2> <%= _("History") %> </h2>
  12 +
  13 + <ul>
  14 + <% @comment.comment_classification_plugin_comment_status_users.each do |relation| %>
  15 + <li>
  16 + <%= _("<i>%{user}</i> added the status <i>%{status_name}</i> at <i>%{created_at}</i>.") % { :user => relation.profile.name, :status_name => relation.status.name, :created_at => time_ago_as_sentence(relation.created_at)} %>
  17 + <% unless relation.reason.blank? %>
  18 + <p><%= _("<i>Reason:</i> %s") % relation.reason %></p>
  19 + <% end %>
  20 + </li>
  21 + <% end %>
  22 + </ul>
  23 +
  24 + <h2> <%= _("Add a new status") %> </h2>
  25 +
  26 + <%= render :partial => 'status_form' %>
  27 +</div>
plugins/comment_classification/views/comment_classification_plugin_myprofile/index.html.erb 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<h1><%= _('Manage comment classification') %></h1>
  2 +
  3 +List all classifications
plugins/comment_classification/views/comment_classification_plugin_status/_form.rhtml 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +<%= error_messages_for :status %>
  2 +
  3 +<% form_for :status, @status do |f| %>
  4 + <%= required_fields_message %>
  5 +
  6 + <%= required labelled_form_field(_('Name'), f.text_field(:name)) %>
  7 + <%= labelled_form_field(f.check_box(:enabled) + _('Enable this status?'),'') %>
  8 + <%#= labelled_form_field(f.check_box(:enable_reason) + _('This status allows reason?'),'') %>
  9 +
  10 + <% button_bar do %>
  11 + <%= submit_button('save', _('Save'), :cancel => {:action => 'index'} ) %>
  12 + <% end %>
  13 +<% end %>
plugins/comment_classification/views/comment_classification_plugin_status/create.rhtml 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<h2> <%= _("Add a new status") %> </h2>
  2 +
  3 +<%= render :partial => 'form' %>
plugins/comment_classification/views/comment_classification_plugin_status/edit.rhtml 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<h2> <%= _("Editing status %s") % @status.name %> </h2>
  2 +
  3 +<%= render :partial => 'form' %>
plugins/comment_classification/views/comment_classification_plugin_status/index.rhtml 0 → 100644
@@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
  1 +<h1> <%= _("Manage comments status") %></h1>
  2 +
  3 +<div id='comment-classification-status'>
  4 + <% if @status.empty? %>
  5 + <%= _('(no status registered yet)') %>
  6 + <% else %>
  7 + <table>
  8 + <tr>
  9 + <th><%= _('Status') %></th>
  10 + <th><%= _('Enabled') %></th>
  11 + <th><%= _('Reason enabled?') %></th>
  12 + <th><%= _('Actions') %></th>
  13 + </tr>
  14 + <% @status.each do |st| %>
  15 + <tr>
  16 + <td><%= st.name %></td>
  17 + <td><%= st.enabled %></td>
  18 + <td><%= st.enable_reason %></td>
  19 + <td>
  20 + <%= button_without_text :edit, _('Edit'), {:action => 'edit', :id => st} %>
  21 + <%= button_without_text :delete, _('Remove'), {:action => 'destroy', :id => st}, :confirm => _('Are you sure you want to remove this status?') %>
  22 + </td>
  23 + </tr>
  24 + <% end %>
  25 + </table>
  26 + <% end %>
  27 +
  28 + <% button_bar do %>
  29 + <%= button(:add, _('Add a new status'), :action => 'create')%>
  30 + <%= button :back, _('Back to admin panel'), :controller => 'admin_panel' %>
  31 + <% end %>
  32 +</div>
plugins/container_block/lib/container_block_plugin.rb
@@ -16,4 +16,8 @@ class ContainerBlockPlugin &lt; Noosfero::Plugin @@ -16,4 +16,8 @@ class ContainerBlockPlugin &lt; Noosfero::Plugin
16 true 16 true
17 end 17 end
18 18
  19 + def js_files
  20 + 'container_block.js'
  21 + end
  22 +
19 end 23 end
plugins/container_block/lib/container_block_plugin/container_block.rb
@@ -7,6 +7,16 @@ class ContainerBlockPlugin::ContainerBlock &lt; Block @@ -7,6 +7,16 @@ class ContainerBlockPlugin::ContainerBlock &lt; Block
7 settings_items :container_box_id, :type => Integer, :default => nil 7 settings_items :container_box_id, :type => Integer, :default => nil
8 settings_items :children_settings, :type => Hash, :default => {} 8 settings_items :children_settings, :type => Hash, :default => {}
9 9
  10 + validate :no_cyclical_reference, :if => 'container_box_id.present?'
  11 +
  12 + def no_cyclical_reference
  13 + errors.add(:box_id, _('cyclical reference is not allowed.')) if box_id == container_box_id
  14 + end
  15 +
  16 + before_save do |b|
  17 + raise "cyclical reference is not allowed" if b.box_id == b.container_box_id && !b.container_box_id.blank?
  18 + end
  19 +
10 def self.description 20 def self.description
11 _('Container') 21 _('Container')
12 end 22 end
@@ -15,6 +25,10 @@ class ContainerBlockPlugin::ContainerBlock &lt; Block @@ -15,6 +25,10 @@ class ContainerBlockPlugin::ContainerBlock &lt; Block
15 _('This block acts as a container for another blocks') 25 _('This block acts as a container for another blocks')
16 end 26 end
17 27
  28 + def cacheable?
  29 + false
  30 + end
  31 +
18 def layout_template 32 def layout_template
19 nil 33 nil
20 end 34 end
@@ -24,8 +38,9 @@ class ContainerBlockPlugin::ContainerBlock &lt; Block @@ -24,8 +38,9 @@ class ContainerBlockPlugin::ContainerBlock &lt; Block
24 end 38 end
25 39
26 def create_box 40 def create_box
27 - box = Box.create!(:owner => owner)  
28 - settings[:container_box_id] = box.id 41 + container_box = Box.create!(:owner => owner)
  42 + container_box.update_attribute(:position, nil)
  43 + settings[:container_box_id] = container_box.id
29 save! 44 save!
30 end 45 end
31 46
plugins/container_block/public/container_block.js 0 → 100644
@@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
  1 +function enableMoveContainerChildren(container, box) {
  2 + var div = jQuery('#box-'+box+' > .block-outer > .block');
  3 + if(!div.is('.ui-resizable')) {
  4 + div.resizable({
  5 + handles: 'e, w',
  6 + containment: '#block-'+container+' .block-inner-2',
  7 + resize: function( event, ui ) {
  8 + ui.element.height('auto');
  9 + }
  10 + });
  11 + }
  12 +}
  13 +
  14 +function disableMoveContainerChildren(container, box) {
  15 + var div = jQuery('#box-'+box+' > .block-outer > .block');
  16 + if(div.is('.ui-resizable')) {
  17 + div.resizable('destroy');
  18 + }
  19 +}
  20 +
  21 +function containerChildrenWidth(container, box) {
  22 + widths = "";
  23 + jQuery('#box-'+box+' > .block-outer > .block').each(function(i) {
  24 + childId = jQuery(this).attr('id').match(/block-(\d+)/)[1];
  25 + widths+=childId+","+jQuery(this).width()+"|";
  26 + });
  27 + return "widths="+widths;
  28 +}
plugins/container_block/public/style.css
  1 +#box-organizer .container-block-plugin_container-block > .block-inner-1 > .block-inner-2 > .button-bar {
  2 + height: 22px;
  3 + padding-bottom: 0px;
  4 + width: auto;
  5 +}
  6 +
1 #content .boxes .container-block-plugin_container-block .container_block_child, .container-block-plugin_container-block .block-outer { 7 #content .boxes .container-block-plugin_container-block .container_block_child, .container-block-plugin_container-block .block-outer {
2 display: inline-block; 8 display: inline-block;
3 vertical-align: top; 9 vertical-align: top;
@@ -17,14 +23,10 @@ @@ -17,14 +23,10 @@
17 background-image: url(/designs/icons/default/Tango/16x16/actions/go-previous.png); 23 background-image: url(/designs/icons/default/Tango/16x16/actions/go-previous.png);
18 } 24 }
19 25
20 -#content .boxes .container-block-plugin_container-block .block {  
21 - outline-offset: -2px;  
22 -}  
23 -  
24 #content .boxes .container-block-plugin_container-block .block .ui-resizable-handle { 26 #content .boxes .container-block-plugin_container-block .block .ui-resizable-handle {
25 width: 10px; 27 width: 10px;
26 height: 28px; 28 height: 28px;
27 - z-index: 0; 29 + z-index: 1000;
28 } 30 }
29 31
30 #content .boxes .container-block-plugin_container-block .block .ui-resizable-e { 32 #content .boxes .container-block-plugin_container-block .block .ui-resizable-e {
@@ -37,6 +39,21 @@ @@ -37,6 +39,21 @@
37 background-image: url(/plugins/container_block/images/handle_w.png); 39 background-image: url(/plugins/container_block/images/handle_w.png);
38 } 40 }
39 41
40 -.container-block-plugin_container-block .button-bar .icon-resize { 42 +.container-block-plugin_container-block .container-block-button-bar .icon-resize {
41 background-image: url(/designs/icons/default/Tango/16x16/actions/view-fullscreen.png); 43 background-image: url(/designs/icons/default/Tango/16x16/actions/view-fullscreen.png);
42 } 44 }
  45 +
  46 +#box-organizer .block .container-block-button-bar {
  47 + right: 0px;
  48 + bottom: 0px;
  49 + height: auto;
  50 +}
  51 +
  52 +#box-organizer .container-block-plugin_container-block:hover .block {
  53 + outline: 1px dashed black;
  54 + outline-offset: -1px;
  55 +}
  56 +
  57 +.container-block-plugin_container-block .block-target {
  58 + background: #afd;
  59 +}
plugins/container_block/test/functional/container_block_home_controller_test.rb
@@ -31,6 +31,13 @@ class HomeControllerTest &lt; ActionController::TestCase @@ -31,6 +31,13 @@ class HomeControllerTest &lt; ActionController::TestCase
31 assert_tag :div, :attributes => { :class => 'block container-block-plugin_container-block' } 31 assert_tag :div, :attributes => { :class => 'block container-block-plugin_container-block' }
32 end 32 end
33 33
  34 + should 'display block title' do
  35 + @block.title = "Block Title"
  36 + @block.save!
  37 + get :index
  38 + assert_tag :div, :attributes => { :class => 'block container-block-plugin_container-block' }, :descendant => {:tag => 'h3', :attributes => { :class => "block-title"}, :content => @block.title }
  39 + end
  40 +
34 should 'display container children' do 41 should 'display container children' do
35 c1 = RawHTMLBlock.create!(:box_id => @block.container_box.id, :html => 'child1 content') 42 c1 = RawHTMLBlock.create!(:box_id => @block.container_box.id, :html => 'child1 content')
36 c2 = RawHTMLBlock.create!(:box_id => @block.container_box.id, :html => 'child2 content') 43 c2 = RawHTMLBlock.create!(:box_id => @block.container_box.id, :html => 'child2 content')
plugins/container_block/test/unit/block_test.rb
@@ -1,31 +0,0 @@ @@ -1,31 +0,0 @@
1 -require 'test_helper'  
2 -  
3 -class BlockTest < ActiveSupport::TestCase  
4 -  
5 - def setup  
6 - @environment = fast_create(Environment)  
7 - @box = Box.create!(:owner => @environment)  
8 - @container = ContainerBlockPlugin::ContainerBlock.create!(:box_id => @box.id)  
9 - end  
10 -  
11 - should 'return environment box if block owner is not a ContainerBlock' do  
12 - block = Block.create!(:box_id => @box.id)  
13 - assert_equal @box, block.box  
14 - end  
15 -  
16 - should 'return container box if block owner is a ContainerBlock' do  
17 - block = Block.create!(:box_id => @container.container_box.id)  
18 - assert_equal @container.container_box, block.box  
19 - end  
20 -  
21 - should 'return block owner if block onwer is not a ContainerBlock' do  
22 - block = Block.create!(:box_id => @box.id)  
23 - assert_equal @environment, block.owner  
24 - end  
25 -  
26 - should 'return environment as owner if block onwer is a ContainerBlock' do  
27 - block = Block.create!(:box_id => @container.container_box.id)  
28 - assert_equal @environment, block.owner  
29 - end  
30 -  
31 -end  
plugins/container_block/test/unit/container_block_plugin/container_block_test.rb
@@ -20,6 +20,11 @@ class ContainerBlockPlugin::ContainerBlockTest &lt; ActiveSupport::TestCase @@ -20,6 +20,11 @@ class ContainerBlockPlugin::ContainerBlockTest &lt; ActiveSupport::TestCase
20 assert @block.container_box_id 20 assert @block.container_box_id
21 end 21 end
22 22
  23 + should 'created box should have nil as position' do
  24 + @block.save!
  25 + assert_equal nil, @block.container_box.position
  26 + end
  27 +
23 should 'return created box' do 28 should 'return created box' do
24 @block.save! 29 @block.save!
25 assert @block.container_box 30 assert @block.container_box
@@ -89,4 +94,27 @@ class ContainerBlockPlugin::ContainerBlockTest &lt; ActiveSupport::TestCase @@ -89,4 +94,27 @@ class ContainerBlockPlugin::ContainerBlockTest &lt; ActiveSupport::TestCase
89 end 94 end
90 end 95 end
91 96
  97 + should 'not mess up with boxes positions when destroyed' do
  98 + env = fast_create(Environment)
  99 + box1 = fast_create(Box, :owner_id => env.id, :owner_type => 'Environment', :position => 1)
  100 + box2 = fast_create(Box, :owner_id => env.id, :owner_type => 'Environment', :position => 2)
  101 + box3 = fast_create(Box, :owner_id => env.id, :owner_type => 'Environment', :position => 3)
  102 + block = ContainerBlockPlugin::ContainerBlock.create!(:box => box1)
  103 + block.destroy
  104 + assert_equal [1, 2, 3], [box1.reload.position, box2.reload.position, box3.reload.position]
  105 + end
  106 +
  107 + should 'be able to change box' do
  108 + @block.save!
  109 + @block.box = Box.new(:owner => Environment.default)
  110 + @block.save!
  111 + end
  112 +
  113 + should 'not able to change box to be the same as container_box' do
  114 + @block.save!
  115 + @block.box = @block.container_box
  116 + @block.save
  117 + assert @block.errors.invalid?(:box_id)
  118 + end
  119 +
92 end 120 end
plugins/container_block/test/unit/environment_test.rb
@@ -1,32 +0,0 @@ @@ -1,32 +0,0 @@
1 -require 'test_helper'  
2 -  
3 -class EnvironmentTest < ActiveSupport::TestCase  
4 -  
5 - def setup  
6 - @environment = fast_create(Environment)  
7 -  
8 - @box = create(Box, :owner => @environment)  
9 - @block = create(Block, :box => @box)  
10 -  
11 - @container = create(ContainerBlockPlugin::ContainerBlock, :box => @box)  
12 - end  
13 -  
14 - should 'return blocks as usual' do  
15 - assert_equal [@block, @container], @environment.blocks  
16 - end  
17 -  
18 - should 'return blocks with container children' do  
19 - child = Block.create!(:box_id => @container.container_box.id)  
20 - assert_equal [@block, @container, child], @environment.blocks  
21 - end  
22 -  
23 - should 'return block with id at find method' do  
24 - assert_equal @block, @environment.blocks.find(@block.id)  
25 - end  
26 -  
27 - should 'return child block with id at find method' do  
28 - child = Block.create!(:box_id => @container.container_box.id)  
29 - assert_equal child, @environment.blocks.find(child.id)  
30 - end  
31 -  
32 -end  
plugins/container_block/test/unit/profile_test.rb
@@ -1,32 +0,0 @@ @@ -1,32 +0,0 @@
1 -require 'test_helper'  
2 -  
3 -class ProfileTest < ActiveSupport::TestCase  
4 -  
5 - def setup  
6 - @profile = fast_create(Profile)  
7 -  
8 - @box = create(Box, :owner => @profile)  
9 - @block = create(Block, :box => @box)  
10 -  
11 - @container = create(ContainerBlockPlugin::ContainerBlock, :box => @box)  
12 - end  
13 -  
14 - should 'return blocks as usual' do  
15 - assert_equal [@block, @container], @profile.blocks  
16 - end  
17 -  
18 - should 'return blocks with container children' do  
19 - child = Block.create!(:box_id => @container.container_box.id)  
20 - assert_equal [@block, @container, child], @profile.blocks  
21 - end  
22 -  
23 - should 'return block with id at find method' do  
24 - assert_equal @block, @profile.blocks.find(@block.id)  
25 - end  
26 -  
27 - should 'return child block with id at find method' do  
28 - child = Block.create!(:box_id => @container.container_box.id)  
29 - assert_equal child, @profile.blocks.find(child.id)  
30 - end  
31 -  
32 -end  
plugins/container_block/views/blocks/container.html.erb
1 <% edit_mode = controller.send(:boxes_editor?) && controller.send(:uses_design_blocks?) %> 1 <% edit_mode = controller.send(:boxes_editor?) && controller.send(:uses_design_blocks?) %>
2 <% box_decorator = edit_mode ? self : BoxesHelper::DontMoveBlocks %> 2 <% box_decorator = edit_mode ? self : BoxesHelper::DontMoveBlocks %>
3 3
  4 +<%= block_title(block.title) %>
4 5
5 <div class="box" id="box-<%= block.container_box.id %>"> 6 <div class="box" id="box-<%= block.container_box.id %>">
6 <%= display_box_content(block.container_box, nil) %> 7 <%= display_box_content(block.container_box, nil) %>
@@ -15,46 +16,23 @@ @@ -15,46 +16,23 @@
15 </style> 16 </style>
16 17
17 <% if edit_mode %> 18 <% if edit_mode %>
18 - <div class="button-bar">  
19 - <a href="#" onclick="toggleMoveContainerChildren(<%= block.id %>, <%= block.container_box.id %>); return false;" class="button icon-resize" title=<%= _('Resize blocks').to_json %>></a>  
20 - <%= link_to_remote '', :url => { :controller => controller.boxes_holder.kind_of?(Environment) ? 'container_block_plugin_admin' : 'container_block_plugin_myprofile', :action => 'saveWidths', :id => block.id }, 19 +
  20 + <script>
  21 + jQuery("#block-<%= block.id %>").hover(
  22 + function() {
  23 + enableMoveContainerChildren(<%= block.id %>, <%= block.container_box.id %>);
  24 + }, function() {
  25 + disableMoveContainerChildren(<%= block.id %>, <%= block.container_box.id %>);
  26 + }
  27 + );
  28 + </script>
  29 +
  30 + <div class="container-block-button-bar button-bar">
  31 + <%= link_to_remote '', :url => { :controller => @controller.boxes_holder.kind_of?(Environment) ? 'container_block_plugin_admin' : 'container_block_plugin_myprofile', :action => 'saveWidths', :id => block.id },
21 :with => "containerChildrenWidth(#{block.id}, #{block.container_box.id})", 32 :with => "containerChildrenWidth(#{block.id}, #{block.container_box.id})",
22 :html => {:class => "button icon-save container_block_save", :id => "container_block_save_#{block.id}", :title => _('Save') }, 33 :html => {:class => "button icon-save container_block_save", :id => "container_block_save_#{block.id}", :title => _('Save') },
23 :loading => "open_loading(DEFAULT_LOADING_MESSAGE);", 34 :loading => "open_loading(DEFAULT_LOADING_MESSAGE);",
24 :loaded => "close_loading();", 35 :loaded => "close_loading();",
25 :complete => "display_notice(request.responseText);"%> 36 :complete => "display_notice(request.responseText);"%>
26 </div> 37 </div>
27 -  
28 - <script>  
29 - function toggleMoveContainerChildren(container, box) {  
30 - var div = jQuery('#box-'+box+' > .block-outer > .block');  
31 - var targetDiv = jQuery('#box-'+box+' .block-outer .block-target');  
32 - if(div.is('.ui-resizable')) {  
33 - targetDiv.show();  
34 - div.find("a").die("click");  
35 - div.resizable('destroy');  
36 - } else {  
37 - targetDiv.hide();  
38 - div.find("a").live("click", function(e) {  
39 - e.preventDefault();  
40 - });  
41 - div.resizable({  
42 - handles: 'e, w',  
43 - containment: '#block-'+container+' .block-inner-2',  
44 - resize: function( event, ui ) {  
45 - ui.element.height('auto');  
46 - }  
47 - });  
48 - }  
49 - }  
50 -  
51 - function containerChildrenWidth(container, box) {  
52 - widths = "";  
53 - jQuery('#box-'+box+' > .block-outer > .block').each(function(i) {  
54 - childId = jQuery(this).attr('id').match(/block-(\d+)/)[1];  
55 - widths+=childId+","+jQuery(this).width()+"|";  
56 - });  
57 - return "widths="+widths;  
58 - }  
59 - </script>  
60 <% end %> 38 <% end %>
plugins/require_auth_to_comment/public/hide_comment_form.js
1 (function($) { 1 (function($) {
2 $(window).bind('userDataLoaded', function(event, data) { 2 $(window).bind('userDataLoaded', function(event, data) {
3 - if (data.login || $('meta[name=profile.allow_unauthenticated_comments]').length > 0) { 3 + if (data.login || $('meta[name="profile.allow_unauthenticated_comments"]').length > 0) {
4 $('.post-comment-button').livequery(function() { 4 $('.post-comment-button').livequery(function() {
5 $(this).show(); 5 $(this).show();
6 }); 6 });
@@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
8 $(this).show(); 8 $(this).show();
9 }); 9 });
10 $('.comment-footer').livequery(function() { 10 $('.comment-footer').livequery(function() {
11 - $(this).show(); 11 + $(this).show();
12 }); 12 });
13 } 13 }
14 }); 14 });
public/stylesheets/application.css
  1 +/* browser fixes */
  2 +
  3 +img:-moz-broken {
  4 + -moz-force-broken-image-icon:1;
  5 +}
  6 +
  7 +/* general styles */
  8 +
1 body { 9 body {
2 padding: 0px; 10 padding: 0px;
3 margin: 0px; 11 margin: 0px;
@@ -1727,8 +1735,8 @@ a.button.disabled, input.disabled { @@ -1727,8 +1735,8 @@ a.button.disabled, input.disabled {
1727 display: none; 1735 display: none;
1728 } 1736 }
1729 1737
1730 -#box-organizer .block:focus .button-bar,  
1731 -#box-organizer .block:hover .button-bar { 1738 +#box-organizer .block-outer:focus .button-bar,
  1739 +#box-organizer .block-outer:hover .button-bar {
1732 display: block; 1740 display: block;
1733 } 1741 }
1734 1742
@@ -1834,8 +1842,13 @@ a.button.disabled, input.disabled { @@ -1834,8 +1842,13 @@ a.button.disabled, input.disabled {
1834 } 1842 }
1835 /* ==> blocks/link-list-block.css <<= */ 1843 /* ==> blocks/link-list-block.css <<= */
1836 1844
  1845 +#edit-link-list-block {
  1846 + width: 820px;
  1847 +}
  1848 +
1837 #edit-link-list-block table { 1849 #edit-link-list-block table {
1838 - width: 100%; 1850 + width: auto;
  1851 + margin-bottom: 10px;
1839 } 1852 }
1840 #edit-link-list-block table .cel-address { 1853 #edit-link-list-block table .cel-address {
1841 width: 220px; 1854 width: 220px;
script/install-dependencies/debian-squeeze.sh
@@ -5,7 +5,7 @@ run sudo apt-get -y install $runtime_dependencies @@ -5,7 +5,7 @@ run sudo apt-get -y install $runtime_dependencies
5 sudo apt-get -y install iceweasel || sudo apt-get -y install firefox 5 sudo apt-get -y install iceweasel || sudo apt-get -y install firefox
6 6
7 # needed for development 7 # needed for development
8 -run sudo apt-get -y install libtidy-ruby libhpricot-ruby libnokogiri-ruby libmocha-ruby imagemagick po4a xvfb libxml2-dev libxslt-dev postgresql openjdk-6-jre 8 +run sudo apt-get -y install libtidy-ruby libhpricot-ruby libmocha-ruby imagemagick po4a xvfb libxml2-dev libxslt-dev postgresql openjdk-6-jre
9 gem which bundler >/dev/null 2>&1 || gem_install bundler 9 gem which bundler >/dev/null 2>&1 || gem_install bundler
10 setup_rubygems_path 10 setup_rubygems_path
11 run bundle install 11 run bundle install
test/functional/profile_themes_controller_test.rb
@@ -310,4 +310,23 @@ class ProfileThemesControllerTest &lt; ActionController::TestCase @@ -310,4 +310,23 @@ class ProfileThemesControllerTest &lt; ActionController::TestCase
310 assert_no_tag :content => "Select theme" 310 assert_no_tag :content => "Select theme"
311 end 311 end
312 312
  313 + should 'not duplicate themes that are included by the user and by the environment' do
  314 + t1 = Theme.create('theme1')
  315 + t2 = Theme.create('theme2')
  316 + Environment.any_instance.stubs('themes').returns([t1,t2])
  317 + Theme.stubs(:approved_themes).returns([t2])
  318 +
  319 + get :index, :profile => "testinguser"
  320 + assert_equivalent [t1, t2], assigns(:themes)
  321 + end
  322 +
  323 + should 'sort themes by name' do
  324 + t1 = Theme.create('bill-theme')
  325 + t2 = Theme.create('ana-theme')
  326 + Theme.stubs(:approved_themes).returns([t1,t2])
  327 +
  328 + get :index, :profile => "testinguser"
  329 + assert_equal [t2, t1], assigns(:themes)
  330 + end
  331 +
313 end 332 end
test/functional/users_controller_test.rb
@@ -107,6 +107,21 @@ class UsersControllerTest &lt; ActionController::TestCase @@ -107,6 +107,21 @@ class UsersControllerTest &lt; ActionController::TestCase
107 assert_equal false, u.activated? 107 assert_equal false, u.activated?
108 end 108 end
109 109
  110 + should 'order users by name' do
  111 + create_user('jeremy')
  112 + create_user('bill')
  113 + create_user('ana')
  114 + create_user('creed')
  115 + get :index
  116 +
  117 + assert_order ['ana', 'bill', 'creed', 'jeremy'], assigns(:collection).map(&:name)
  118 + end
  119 +
  120 + should 'set filter to all_users by default' do
  121 + get :index
  122 + assert_equal 'all_users', assigns(:filter)
  123 + end
  124 +
110 should 'response as XML to export users' do 125 should 'response as XML to export users' do
111 get :download, :format => 'xml' 126 get :download, :format => 'xml'
112 assert_equal 'text/xml', @response.content_type 127 assert_equal 'text/xml', @response.content_type
test/test_helper.rb
@@ -178,6 +178,19 @@ class ActiveSupport::TestCase @@ -178,6 +178,19 @@ class ActiveSupport::TestCase
178 assert !tag, "expected no tag #{options.inspect}, but tag found in #{text.inspect}" 178 assert !tag, "expected no tag #{options.inspect}, but tag found in #{text.inspect}"
179 end 179 end
180 180
  181 + def assert_order(reference, original)
  182 + original.each do |value|
  183 + if reference.include?(value)
  184 + if reference.first == value
  185 + reference.shift
  186 + else
  187 + assert false, "'#{value}' was found before it should be on: #{original.inspect}"
  188 + end
  189 + end
  190 + end
  191 + assert reference.blank?, "The following elements are not in the collection: #{reference.inspect}"
  192 + end
  193 +
181 # For models that render views (blocks, articles, ...) 194 # For models that render views (blocks, articles, ...)
182 def render(*args) 195 def render(*args)
183 view_paths = @explicit_view_paths || ActionController::Base.view_paths 196 view_paths = @explicit_view_paths || ActionController::Base.view_paths
test/unit/array_core_ext_test.rb 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +# tests for Array core extension. See lib/noosfero/core_ext/array.rb
  4 +class StringCoreExtTest < ActiveSupport::TestCase
  5 +
  6 + should 'allow uniq by a block' do
  7 + array = [0,1,2,3,4,5,6]
  8 + assert_equal [0,1], array.uniq_by {|number| number%2 }
  9 + end
  10 +
  11 +end
test/unit/box_test.rb
@@ -140,4 +140,11 @@ class BoxTest &lt; ActiveSupport::TestCase @@ -140,4 +140,11 @@ class BoxTest &lt; ActiveSupport::TestCase
140 assert !blocks.include?('box-test_plugin-block') 140 assert !blocks.include?('box-test_plugin-block')
141 end 141 end
142 142
  143 + should 'list only boxes with a postion greater than zero' do
  144 + profile = fast_create(Profile)
  145 + box = fast_create(Box, :owner_id => profile.id, :owner_type => 'Profile', :position => 0)
  146 + box2 = fast_create(Box, :owner_id => profile.id, :owner_type => 'Profile', :position => 1)
  147 + assert_equal [box2], profile.boxes.with_position
  148 + end
  149 +
143 end 150 end
test/unit/boxes_helper_test.rb
@@ -12,7 +12,8 @@ class BoxesHelperTest &lt; ActionView::TestCase @@ -12,7 +12,8 @@ class BoxesHelperTest &lt; ActionView::TestCase
12 12
13 should 'include profile-specific header' do 13 should 'include profile-specific header' do
14 holder = mock 14 holder = mock
15 - holder.stubs(:boxes).returns([]) 15 + holder.stubs(:boxes).returns(boxes = [])
  16 + boxes.stubs(:with_position).returns([])
16 holder.stubs(:boxes_limit).returns(0) 17 holder.stubs(:boxes_limit).returns(0)
17 holder.stubs(:custom_header_expanded).returns('my custom header') 18 holder.stubs(:custom_header_expanded).returns('my custom header')
18 @controller.stubs(:boxes_holder).returns(holder) 19 @controller.stubs(:boxes_holder).returns(holder)
@@ -22,7 +23,8 @@ class BoxesHelperTest &lt; ActionView::TestCase @@ -22,7 +23,8 @@ class BoxesHelperTest &lt; ActionView::TestCase
22 23
23 should 'include profile-specific footer' do 24 should 'include profile-specific footer' do
24 holder = mock 25 holder = mock
25 - holder.stubs(:boxes).returns([]) 26 + holder.stubs(:boxes).returns(boxes = [])
  27 + boxes.stubs(:with_position).returns([])
26 holder.stubs(:boxes_limit).returns(0) 28 holder.stubs(:boxes_limit).returns(0)
27 holder.stubs(:custom_footer_expanded).returns('my custom footer') 29 holder.stubs(:custom_footer_expanded).returns('my custom footer')
28 @controller.stubs(:boxes_holder).returns(holder) 30 @controller.stubs(:boxes_holder).returns(holder)
test/unit/comment_test.rb
@@ -285,6 +285,37 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -285,6 +285,37 @@ class CommentTest &lt; ActiveSupport::TestCase
285 assert_equal [c1,c3], c.reload.children 285 assert_equal [c1,c3], c.reload.children
286 end 286 end
287 287
  288 + should "return activities comments as a thread" do
  289 + person = fast_create(Person)
  290 + a = TextileArticle.create!(:profile => person, :name => 'My article', :body => 'Article body')
  291 + c0 = Comment.create!(:source => a, :body => 'My comment', :author => person)
  292 + c1 = Comment.create!(:reply_of_id => c0.id, :source => a, :body => 'bla', :author => person)
  293 + c2 = Comment.create!(:reply_of_id => c1.id, :source => a, :body => 'bla', :author => person)
  294 + c3 = Comment.create!(:reply_of_id => c0.id, :source => a, :body => 'bla', :author => person)
  295 + c4 = Comment.create!(:source => a, :body => 'My comment', :author => person)
  296 + result = a.activity.comments
  297 + assert_equal c0, result[0]
  298 + assert_equal [c1, c3], result[0].replies
  299 + assert_equal [c2], result[0].replies[0].replies
  300 + assert_equal c4, result[1]
  301 + assert result[1].replies.empty?
  302 + end
  303 +
  304 + should "return activities comments when some comment on thread is spam and not display its replies" do
  305 + person = fast_create(Person)
  306 + a = TextileArticle.create!(:profile => person, :name => 'My article', :body => 'Article body')
  307 + c0 = Comment.create(:source => a, :body => 'Root comment', :author => person)
  308 + c1 = Comment.create(:reply_of_id => c0.id, :source => a, :body => 'c1', :author => person)
  309 + c2 = Comment.create(:source => a, :body => 'c2', :author => person)
  310 + spam = Comment.create(:spam => true, :reply_of_id => c2.id, :source => a, :body => 'spam', :author => person)
  311 + spam_reply = Comment.create(:reply_of_id => spam.id, :source => a, :body => 'spam reply', :author => person)
  312 + result = a.activity.comments
  313 + assert_equal c0, result[0]
  314 + assert_equal [c1], result[0].replies.without_spam
  315 + assert_equal c2, result[1]
  316 + assert_equal [], result[1].replies.without_spam
  317 + end
  318 +
288 should 'provide author url for authenticated user' do 319 should 'provide author url for authenticated user' do
289 author = Person.new 320 author = Person.new
290 author.expects(:url).returns('http://blabla.net/author') 321 author.expects(:url).returns('http://blabla.net/author')
@@ -389,6 +420,7 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -389,6 +420,7 @@ class CommentTest &lt; ActiveSupport::TestCase
389 end 420 end
390 421
391 should 'be able to select non-spam comments' do 422 should 'be able to select non-spam comments' do
  423 + Comment.destroy_all
392 c1 = fast_create(Comment) 424 c1 = fast_create(Comment)
393 c2 = fast_create(Comment, :spam => false) 425 c2 = fast_create(Comment, :spam => false)
394 c3 = fast_create(Comment, :spam => true) 426 c3 = fast_create(Comment, :spam => true)
@@ -660,6 +692,7 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -660,6 +692,7 @@ class CommentTest &lt; ActiveSupport::TestCase
660 end 692 end
661 693
662 should 'be able to select non-reply comments' do 694 should 'be able to select non-reply comments' do
  695 + Comment.destroy_all
663 c1 = fast_create(Comment) 696 c1 = fast_create(Comment)
664 c2 = fast_create(Comment, :reply_of_id => c1.id) 697 c2 = fast_create(Comment, :reply_of_id => c1.id)
665 c3 = fast_create(Comment, :reply_of_id => c2.id) 698 c3 = fast_create(Comment, :reply_of_id => c2.id)
test/unit/environment_test.rb
@@ -783,6 +783,18 @@ class EnvironmentTest &lt; ActiveSupport::TestCase @@ -783,6 +783,18 @@ class EnvironmentTest &lt; ActiveSupport::TestCase
783 assert role2.valid? 783 assert role2.valid?
784 end 784 end
785 785
  786 + should 'destroy roles when its environment is destroyed' do
  787 + e1 = fast_create(Environment)
  788 + role1 = Role.create!(:name => 'test_role', :environment => e1, :key => 'a_member')
  789 + e2 = fast_create(Environment)
  790 + role2 = Role.create!(:name => 'test_role', :environment => e2, :key => 'a_member')
  791 +
  792 + e2.destroy
  793 +
  794 + assert_nothing_raised {Role.find(role1.id)}
  795 + assert_raise(ActiveRecord::RecordNotFound) {Role.find(role2.id)}
  796 + end
  797 +
786 should 'have a help_message_to_add_enterprise attribute' do 798 should 'have a help_message_to_add_enterprise attribute' do
787 env = Environment.new 799 env = Environment.new
788 800
test/unit/link_list_block_test.rb
@@ -88,4 +88,9 @@ class LinkListBlockTest &lt; ActiveSupport::TestCase @@ -88,4 +88,9 @@ class LinkListBlockTest &lt; ActiveSupport::TestCase
88 assert_equivalent LinkListBlock::TARGET_OPTIONS.map {|t|t[1]}, ['_self', '_blank', '_new'] 88 assert_equivalent LinkListBlock::TARGET_OPTIONS.map {|t|t[1]}, ['_self', '_blank', '_new']
89 end 89 end
90 90
  91 + should 'link with title' do
  92 + l = LinkListBlock.new
  93 + assert_match /title="mytitle"/, l.link_html({:name => 'mylink', :address => '/myaddress', :title => 'mytitle'})
  94 + end
  95 +
91 end 96 end
test/unit/macro_test.rb
@@ -15,7 +15,7 @@ class MacroTest &lt; ActiveSupport::TestCase @@ -15,7 +15,7 @@ class MacroTest &lt; ActiveSupport::TestCase
15 15
16 def setup 16 def setup
17 @macro = Plugin1::Macro.new 17 @macro = Plugin1::Macro.new
18 - @macro_element = Nokogiri::HTML(MACRO).css('.macro').first 18 + @macro_element = Hpricot(MACRO).search('.macro').first
19 end 19 end
20 20
21 attr_reader :macro, :macro_element 21 attr_reader :macro, :macro_element
test/unit/profile_test.rb
@@ -1462,7 +1462,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1462,7 +1462,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1462 should 'list events by month' do 1462 should 'list events by month' do
1463 profile = fast_create(Profile) 1463 profile = fast_create(Profile)
1464 1464
1465 - today = Date.today 1465 + today = Date.new(2014, 03, 2)
1466 yesterday_event = Event.new(:name => 'Joao Birthday', :start_date => today - 1.day) 1466 yesterday_event = Event.new(:name => 'Joao Birthday', :start_date => today - 1.day)
1467 today_event = Event.new(:name => 'Ze Birthday', :start_date => today) 1467 today_event = Event.new(:name => 'Ze Birthday', :start_date => today)
1468 tomorrow_event = Event.new(:name => 'Mane Birthday', :start_date => today + 1.day) 1468 tomorrow_event = Event.new(:name => 'Mane Birthday', :start_date => today + 1.day)
@@ -1693,6 +1693,28 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1693,6 +1693,28 @@ class ProfileTest &lt; ActiveSupport::TestCase
1693 assert_equal 1, community.members_count 1693 assert_equal 1, community.members_count
1694 end 1694 end
1695 1695
  1696 + should 'order members by name alphabetically considering special characters' do
  1697 + community = fast_create(Community)
  1698 +
  1699 + community.add_member(create_user('José').person)
  1700 + community.add_member(create_user('João').person)
  1701 + community.add_member(create_user('Mariana').person)
  1702 + members = community.members_by_name
  1703 +
  1704 + assert_equal ["João", "José", "Mariana"], members.map(&:name)
  1705 + end
  1706 +
  1707 + should 'order members by name alphabetically considering upper and lower cases' do
  1708 + community = fast_create(Community)
  1709 +
  1710 + community.add_member(create_user('mariana').person)
  1711 + community.add_member(create_user('João').person)
  1712 + community.add_member(create_user('guest').person)
  1713 + members = community.members_by_name
  1714 +
  1715 + assert_equal ["guest", "João", "mariana"], members.map(&:name)
  1716 + end
  1717 +
1696 should 'know if url is the profile homepage' do 1718 should 'know if url is the profile homepage' do
1697 profile = fast_create(Profile) 1719 profile = fast_create(Profile)
1698 1720
vendor/plugins/action_tracker_has_comments/init.rb
@@ -11,5 +11,6 @@ Rails.configuration.to_prepare do @@ -11,5 +11,6 @@ Rails.configuration.to_prepare do
11 type, id = (self.target_type == 'Article' ? ['Article', self.target_id] : [self.class.to_s, self.id]) 11 type, id = (self.target_type == 'Article' ? ['Article', self.target_id] : [self.class.to_s, self.id])
12 "source_type = '#{type}' AND source_id = '#{id}' AND spam IS NOT TRUE AND reply_of_id IS NULL" 12 "source_type = '#{type}' AND source_id = '#{id}' AND spam IS NOT TRUE AND reply_of_id IS NULL"
13 end 13 end
  14 +
14 end 15 end
15 end 16 end