Commit 645f9328979e3efa711c1f06d0a9d6ef364719df

Authored by Joenio Costa
2 parents 225bf66e 12a28da7

Merge branch 'master' into AI2694-network_activity_email

Showing 134 changed files with 2941 additions and 355 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 134 files displayed.

app/controllers/admin/environment_design_controller.rb
... ... @@ -3,6 +3,8 @@ class EnvironmentDesignController < BoxOrganizerController
3 3 protect 'edit_environment_design', :environment
4 4  
5 5 def available_blocks
  6 + # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
  7 + # the Noosfero core soon, see ActionItem3045
6 8 @available_blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
7 9 @available_blocks += plugins.dispatch(:extra_blocks, :type => Environment)
8 10 end
... ...
app/controllers/admin/users_controller.rb
... ... @@ -7,7 +7,7 @@ class UsersController < AdminController
7 7 include UsersHelper
8 8  
9 9 def index
10   - @filter = params[:filter]
  10 + @filter = params[:filter] || 'all_users'
11 11 scope = environment.people.no_templates
12 12 if @filter == 'admin_users'
13 13 scope = scope.admins
... ... @@ -16,6 +16,7 @@ class UsersController < AdminController
16 16 elsif @filter == 'deactivated_users'
17 17 scope = scope.deactivated
18 18 end
  19 + scope = scope.order('name ASC')
19 20 @q = params[:q]
20 21 @collection = find_by_contents(:people, scope, @q, {:per_page => per_page, :page => params[:npage]})[:results]
21 22 end
... ... @@ -44,6 +45,20 @@ class UsersController < AdminController
44 45 redirect_to :action => :index, :q => params[:q], :filter => params[:filter]
45 46 end
46 47  
  48 +
  49 + def destroy_user
  50 + if request.post?
  51 + person = environment.people.find_by_id(params[:id])
  52 + if person && person.destroy
  53 + session[:notice] = _('The profile was deleted.')
  54 + else
  55 + session[:notice] = _('Could not remove profile')
  56 + end
  57 + end
  58 + redirect_to :action => :index, :q => params[:q], :filter => params[:filter]
  59 + end
  60 +
  61 +
47 62 def download
48 63 respond_to do |format|
49 64 format.html
... ...
app/controllers/application_controller.rb
... ... @@ -21,6 +21,7 @@ class ApplicationController < ActionController::Base
21 21 include ApplicationHelper
22 22 layout :get_layout
23 23 def get_layout
  24 + return nil if request.format == :js
24 25 theme_layout = theme_option(:layout)
25 26 if theme_layout
26 27 theme_view_file('layouts/'+theme_layout) || theme_layout
... ...
app/controllers/box_organizer_controller.rb
... ... @@ -70,7 +70,7 @@ class BoxOrganizerController < ApplicationController
70 70 else
71 71 @center_block_types = (Box.acceptable_center_blocks & available_blocks) + plugins.dispatch(:extra_blocks, :type => boxes_holder.class, :position => 1)
72 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 74 render :action => 'add_block', :layout => false
75 75 end
76 76 end
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -221,11 +221,10 @@ class CmsController < MyProfileController
221 221  
222 222 def update_categories
223 223 @object = params[:id] ? @profile.articles.find(params[:id]) : Article.new
  224 + @categories = @toplevel_categories = environment.top_level_categories
224 225 if params[:category_id]
225 226 @current_category = Category.find(params[:category_id])
226 227 @categories = @current_category.children
227   - else
228   - @categories = environment.top_level_categories.select{|i| !i.children.empty?}
229 228 end
230 229 render :partial => 'shared/select_categories', :locals => {:object_name => 'article', :multiple => true}, :layout => false
231 230 end
... ...
app/controllers/my_profile/profile_editor_controller.rb
... ... @@ -55,11 +55,10 @@ class ProfileEditorController < MyProfileController
55 55  
56 56 def update_categories
57 57 @object = profile
  58 + @categories = @toplevel_categories = environment.top_level_categories
58 59 if params[:category_id]
59 60 @current_category = Category.find(params[:category_id])
60 61 @categories = @current_category.children
61   - else
62   - @categories = environment.top_level_categories.select{|i| !i.children.empty?}
63 62 end
64 63 render :partial => 'shared/select_categories', :locals => {:object_name => 'profile_data', :multiple => true}, :layout => false
65 64 end
... ...
app/controllers/my_profile/profile_members_controller.rb
... ... @@ -2,7 +2,7 @@ class ProfileMembersController < MyProfileController
2 2 protect 'manage_memberships', :profile
3 3  
4 4 def index
5   - @members = profile.members
  5 + @members = profile.members_by_name
6 6 @member_role = environment.roles.find_by_name('member')
7 7 end
8 8  
... ...
app/controllers/public/profile_controller.rb
... ... @@ -67,7 +67,7 @@ class ProfileController < PublicController
67 67  
68 68 def members
69 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 71 end
72 72 end
73 73  
... ... @@ -304,14 +304,6 @@ class ProfileController < PublicController
304 304 end
305 305 end
306 306  
307   - def profile_info
308   - begin
309   - @block = profile.blocks.find(params[:block_id])
310   - rescue
311   - render :text => _('Profile information could not be loaded')
312   - end
313   - end
314   -
315 307 def report_abuse
316 308 @abuse_report = AbuseReport.new
317 309 render :layout => false
... ...
app/controllers/themes_controller.rb
... ... @@ -12,7 +12,7 @@ class ThemesController < ApplicationController
12 12  
13 13 def index
14 14 @environment = environment
15   - @themes = environment.themes + Theme.approved_themes(target)
  15 + @themes = (environment.themes + Theme.approved_themes(target)).sort_by { |t| t.name }
16 16  
17 17 @current_theme = target.theme
18 18  
... ...
app/helpers/application_helper.rb
... ... @@ -608,49 +608,18 @@ module ApplicationHelper
608 608 end
609 609  
610 610 attr_reader :environment
  611 +
611 612 def select_categories(object_name, title=nil, title_size=4)
612 613 return nil if environment.enabled?(:disable_categories)
613 614 if title.nil?
614 615 title = _('Categories')
615 616 end
616 617  
617   - object = instance_variable_get("@#{object_name}")
618   -
619   - result = content_tag 'h'+title_size.to_s(), title
620   - result << javascript_tag( 'function open_close_cat( link ) {
621   - var div = link.parentNode.getElementsByTagName("div")[0];
622   - var end = function(){
623   - if ( div.style.display == "none" ) {
624   - this.link.className="button icon-button icon-down"
625   - } else {
626   - this.link.className="button icon-button icon-up-red"
627   - }
628   - }
629   - Effect.toggle( div, "slide", { link:link, div:div, afterFinish:end } )
630   - }')
631   - environment.top_level_categories.select{|i| !i.children.empty?}.each do |toplevel|
632   - next unless object.accept_category?(toplevel)
633   - # FIXME
634   - ([toplevel] + toplevel.children_for_menu).each do |cat|
635   - if cat.top_level?
636   - result << '<div class="categorie_box">'.html_safe
637   - result << icon_button( :down, _('open'), '#', :onclick => 'open_close_cat(this); return false' )
638   - result << content_tag('h5', toplevel.name)
639   - result << '<div style="display:none"><ul class="categories">'.html_safe
640   - else
641   - checkbox_id = "#{object_name}_#{cat.full_name.downcase.gsub(/\s+|\//, '_')}"
642   - result << content_tag('li', labelled_check_box(
643   - cat.full_name_without_leading(1, " &rarr; "),
644   - "#{object_name}[category_ids][]", cat.id,
645   - object.category_ids.include?(cat.id), :id => checkbox_id,
646   - :onchange => 'this.parentNode.className=(this.checked?"cat_checked":"")' ),
647   - :class => ( object.category_ids.include?(cat.id) ? 'cat_checked' : '' ) ) + "\n"
648   - end
649   - end
650   - result << '</ul></div></div>'.html_safe
651   - end
  618 + @object = instance_variable_get("@#{object_name}")
  619 + @categories = environment.top_level_categories
652 620  
653   - content_tag('div', result)
  621 + @current_categories = environment.top_level_categories.select{|i| !i.children.empty?}
  622 + render :partial => 'shared/select_categories_top', :locals => {:object_name => object_name, :title => title, :title_size => title_size, :multiple => true, :categories_selected => @object.categories }, :layout => false
654 623 end
655 624  
656 625 def theme_option(opt = nil)
... ...
app/helpers/boxes_helper.rb
... ... @@ -39,7 +39,7 @@ module BoxesHelper
39 39 end
40 40  
41 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 43 content = boxes.reverse.map { |item| display_box(item, main_content) }.join("\n")
44 44 content = main_content if (content.blank?)
45 45  
... ...
app/helpers/categories_helper.rb
... ... @@ -48,4 +48,12 @@ module CategoriesHelper
48 48 labelled_form_field(_('Type of category'), select_tag('type', options_for_select(TYPES, value)))
49 49 end
50 50  
  51 + #FIXME make this test
  52 + def selected_category_link(cat)
  53 + content_tag('div', button_to_function_without_text(:remove, _('Remove'), nil) {|page| page["selected-category-#{cat.id}"].remove} +
  54 + link_to_function(cat.full_name(' &rarr; '), nil, :id => "remove-selected-category-#{cat.id}-button", :class => 'select-subcategory-link') {|page| page["selected-category-#{cat.id}"].remove},
  55 + :class => 'selected-category'
  56 + )
  57 + end
  58 +
51 59 end
... ...
app/helpers/comment_helper.rb
... ... @@ -22,6 +22,12 @@ module CommentHelper
22 22 title
23 23 end
24 24  
  25 + def comment_extra_contents(comment)
  26 + @plugins.dispatch(:comment_extra_contents, comment).collect do |extra_content|
  27 + extra_content.kind_of?(Proc) ? self.instance_eval(&extra_content) : extra_content
  28 + end.join('\n')
  29 + end
  30 +
25 31 def comment_actions(comment)
26 32 url = url_for(:profile => profile.identifier, :controller => :comment, :action => :check_actions, :id => comment.id)
27 33 links = links_for_comment_actions(comment)
... ...
app/models/box.rb
... ... @@ -5,6 +5,8 @@ class Box &lt; ActiveRecord::Base
5 5  
6 6 include Noosfero::Plugin::HotSpot
7 7  
  8 + named_scope :with_position, :conditions => ['boxes.position > 0']
  9 +
8 10 def environment
9 11 owner ? (owner.kind_of?(Environment) ? owner : owner.environment) : nil
10 12 end
... ... @@ -24,6 +26,8 @@ class Box &lt; ActiveRecord::Base
24 26 CategoriesBlock,
25 27 CommunitiesBlock,
26 28 EnterprisesBlock,
  29 + # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
  30 + # the Noosfero core soon, see ActionItem3045
27 31 EnvironmentStatisticsBlock,
28 32 FansBlock,
29 33 FavoriteEnterprisesBlock,
... ... @@ -50,6 +54,8 @@ class Box &lt; ActiveRecord::Base
50 54 CommunitiesBlock,
51 55 DisabledEnterpriseMessageBlock,
52 56 EnterprisesBlock,
  57 + # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
  58 + # the Noosfero core soon, see ActionItem3045
53 59 EnvironmentStatisticsBlock,
54 60 FansBlock,
55 61 FavoriteEnterprisesBlock,
... ...
app/models/environment.rb
... ... @@ -161,6 +161,8 @@ class Environment &lt; ActiveRecord::Base
161 161  
162 162 # "left" area
163 163 env.boxes[1].blocks << LoginBlock.new
  164 + # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
  165 + # the Noosfero core soon, see ActionItem3045
164 166 env.boxes[1].blocks << EnvironmentStatisticsBlock.new
165 167 env.boxes[1].blocks << RecentDocumentsBlock.new
166 168  
... ... @@ -186,7 +188,7 @@ class Environment &lt; ActiveRecord::Base
186 188 has_many :product_categories, :conditions => { :type => 'ProductCategory'}
187 189 has_many :regions
188 190  
189   - has_many :roles
  191 + has_many :roles, :dependent => :destroy
190 192  
191 193 has_many :qualifiers
192 194 has_many :certifiers
... ...
app/models/environment_statistics_block.rb
  1 +# TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
  2 +# the Noosfero core soon, see ActionItem3045
  3 +
1 4 class EnvironmentStatisticsBlock < Block
2 5  
3 6 def self.description
4   - _('Environment stastistics')
  7 + _('Environment stastistics (DEPRECATED)')
5 8 end
6 9  
7 10 def default_title
... ...
app/models/link_list_block.rb
... ... @@ -63,7 +63,7 @@ class LinkListBlock &lt; Block
63 63 def link_html(link)
64 64 klass = 'icon-' + link[:icon] if link[:icon]
65 65 sanitize_link(
66   - link_to(link[:name], expand_address(link[:address]), :target => link[:target], :class => klass)
  66 + link_to(link[:name], expand_address(link[:address]), :target => link[:target], :class => klass, :title => link[:title])
67 67 )
68 68 end
69 69  
... ...
app/models/profile.rb
... ... @@ -88,6 +88,10 @@ class Profile &lt; ActiveRecord::Base
88 88 ScopeTool.union *scopes
89 89 end
90 90  
  91 + def members_by_name
  92 + members.order(:name)
  93 + end
  94 +
91 95 def members_count
92 96 members.count
93 97 end
... ...
app/sweepers/profile_sweeper.rb
... ... @@ -8,6 +8,8 @@ class ProfileSweeper # &lt; ActiveRecord::Observer
8 8 end
9 9  
10 10 def after_create(profile)
  11 + # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
  12 + # the Noosfero core soon, see ActionItem3045
11 13 expire_statistics_block_cache(profile)
12 14 end
13 15  
... ... @@ -29,6 +31,8 @@ protected
29 31 expire_blogs(profile) if profile.organization?
30 32 end
31 33  
  34 + # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
  35 + # the Noosfero core soon, see ActionItem3045
32 36 def expire_statistics_block_cache(profile)
33 37 blocks = profile.environment.blocks.select { |b| b.kind_of?(EnvironmentStatisticsBlock) }
34 38 BlockSweeper.expire_blocks(blocks)
... ...
app/views/blocks/location.html.erb
... ... @@ -3,7 +3,6 @@
3 3 <div class='the-localization-map'>
4 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 5 </div>
6   -</div>
7 6 <% else %>
8 7 <i><%= _('This profile has no geographical position registered.') %></i>
9 8 <% end %>
... ...
app/views/blocks/profile_image.rhtml
... ... @@ -16,7 +16,7 @@
16 16  
17 17 <% if !user.nil? and user.has_permission?('edit_profile', profile) %>
18 18 <div class='admin-link'>
19   - <%= link_to _('Control panel'), :controller => 'profile_editor' %>
  19 + <%= link_to _('Control panel'), block.owner.admin_url %>
20 20 </div>
21 21 <% end %>
22 22  
... ...
app/views/blocks/profile_info.rhtml
... ... @@ -21,7 +21,7 @@
21 21 <li><%= link_to(_('Products/Services'), :controller => 'catalog', :profile => block.owner.identifier) %></li>
22 22 <% end %>
23 23 <% if !user.nil? and user.has_permission?('edit_profile', profile) %>
24   - <li><%= link_to _('Control panel'), :controller => 'profile_editor' %></li>
  24 + <li><%= link_to _('Control panel'), block.owner.admin_url %></li>
25 25 <% end %>
26 26 <% if profile.person? %>
27 27 <li><%= _('Since %{year}/%{month}') % { :year => block.owner.created_at.year, :month => block.owner.created_at.month } %></li>
... ... @@ -40,7 +40,7 @@
40 40 <% end %>
41 41  
42 42 <div class="profile-info-options">
43   - <%= render :file => view_for_profile_actions(@block.owner.class) %>
  43 + <%= render :file => view_for_profile_actions(block.owner.class) %>
44 44 </div>
45 45  
46 46 </div><!-- end class="vcard" -->
... ...
app/views/box_organizer/_link_list_block.rhtml
1 1 <strong><%= _('Links') %></strong>
2   -<div id='edit-link-list-block' style='width:450px'>
  2 +<div id='edit-link-list-block'>
3 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 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 19 <% end %>
17 20 </table>
18 21 </div>
... ... @@ -22,8 +25,8 @@
22 25 content_tag('td', icon_selector('ok')) +
23 26 content_tag('td', text_field_tag('block[links][][name]', '', :maxlength => 20)) +
24 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 31 javascript_tag("$('edit-link-list-block').scrollTop = $('edit-link-list-block').scrollHeight")
29 32 end %>
... ...
app/views/content_viewer/view_page.rhtml
... ... @@ -40,14 +40,6 @@
40 40 </div>
41 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 43 <%= render :partial => 'shared/disabled_enterprise' %>
52 44  
53 45 <% if NOOSFERO_CONF['addthis_enabled'] %>
... ... @@ -83,8 +75,17 @@
83 75 </div>
84 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 85 <%= display_source_info(@page) %>
87 86  
  87 +<%= @plugins.dispatch(:article_extra_contents, @page).collect { |content| instance_eval(&content) }.join("") %>
  88 +
88 89 <div class="comments" id="comments_list">
89 90  
90 91 <% if @page.accept_comments? || @comments_count > 0 %>
... ...
app/views/features/_manage_community_fields.rhtml
1   -<h2><%= __('Manage community fields') %></h2>
2   -
3 1 <% labelled_form_for(:environment, @environment, :url => {:action => 'manage_community_fields'}) do |f| %>
4 2  
5 3 <table id='community_fields_conf'>
... ... @@ -9,21 +7,37 @@
9 7 <th><%= _('Required') %></th>
10 8 <th><%= _('Display on creation?') %></th>
11 9 </tr>
  10 +
  11 + <tr class='manage-fields-batch-actions'>
  12 + <td>
  13 + <%= _("Check/Uncheck All")%>
  14 + </td>
  15 + <td>
  16 + <input type="checkbox" id="community_active" />
  17 + </td>
  18 + <td>
  19 + <input type="checkbox" id="community_required" />
  20 + </td>
  21 + <td>
  22 + <input type="checkbox" id="community_signup" />
  23 + </td>
  24 + </tr>
  25 +
12 26 <% @community_fields.each do |field| %>
13 27 <tr>
14 28 <td><label for="community_fields[<%= field %>][active]"><%= _(field.humanize) %></label></td>
15 29  
16 30 <td>
17 31 <%= hidden_field_tag "community_fields[#{field}][active]", false %>
18   - <%= check_box_tag "community_fields[#{field}][active]", true, environment.custom_community_field(field, 'active'), :onclick => "$('community_fields[#{field}][required]').disabled=$('community_fields[#{field}][signup]').disabled=!this.checked;" %>
  32 + <%= check_box_tag "community_fields[#{field}][active]", true, environment.custom_community_field(field, 'active'), :onclick => "active_action(this, 'community_fields[#{field}][required]', 'community_fields[#{field}][signup]')" %>
19 33 </td>
20 34 <td>
21 35 <%= hidden_field_tag "community_fields[#{field}][required]", false %>
22   - <%= check_box_tag "community_fields[#{field}][required]", true, environment.custom_community_field(field, 'required'), :onclick => "if(this.checked) $('community_fields[#{field}][signup]').checked = true;" %>
  36 + <%= check_box_tag "community_fields[#{field}][required]", true, environment.custom_community_field(field, 'required'), :onclick => "required_action('community_fields[#{field}][active]','community_fields[#{field}][required]', 'community_fields[#{field}][signup]')" %>
23 37 </td>
24 38 <td>
25 39 <%= hidden_field_tag "community_fields[#{field}][signup]", false %>
26   - <%= check_box_tag "community_fields[#{field}][signup]", true, environment.custom_community_field(field, 'signup'), :onclick => "if(!this.checked) $('community_fields[#{field}][required]').checked = false;" %>
  40 + <%= check_box_tag "community_fields[#{field}][signup]", true, environment.custom_community_field(field, 'signup'), :onclick => "signup_action('community_fields[#{field}][active]','community_fields[#{field}][required]', 'community_fields[#{field}][signup]')" %>
27 41 </td>
28 42  
29 43 </tr>
... ... @@ -31,18 +45,18 @@
31 45 </table>
32 46  
33 47 <script type='text/javascript'>
34   - var trs = $$('#community_fields_conf tr');
  48 + var trs = jQuery('#community_fields_conf tr');
35 49 var tr, td2;
36   - for ( var i=0; tr=trs[i]; i++ ) {
  50 + for ( var i=2; tr=trs[i]; i++ ) {
37 51 if ( td2 = tr.getElementsByTagName('td')[1] ) {
38   - td2.getElementsByTagName('input')[0].onclick();
  52 + td2.getElementsByTagName('input')[1].onclick();
39 53 }
40 54 }
41 55 </script>
42 56  
43 57 <div>
44 58 <% button_bar do %>
45   - <%= submit_button('save', _('Save changes')) %>
  59 + <%= submit_button('save', _('Save changes'), :id=>"save_community_fields") %>
46 60 <%= button :back, _('Back to admin panel'), :controller => 'admin_panel', :action => 'index' %>
47 61 <% end %>
48 62 </div>
... ...
app/views/features/_manage_enterprise_fields.rhtml
1   -<h2><%= __('Manage enterprise fields') %></h2>
2   -
3 1 <% labelled_form_for(:environment, @environment, :url => {:action => 'manage_enterprise_fields'}) do |f| %>
4 2  
5 3 <table id='enterprise_fields_conf'>
... ... @@ -9,21 +7,37 @@
9 7 <th><%= _('Required') %></th>
10 8 <th><%= _('Display on registration?') %></th>
11 9 </tr>
  10 +
  11 + <tr class='manage-fields-batch-actions'>
  12 + <td>
  13 + <%= _("Check/Uncheck All")%>
  14 + </td>
  15 + <td>
  16 + <input type="checkbox" id="enterprise_active" />
  17 + </td>
  18 + <td>
  19 + <input type="checkbox" id="enterprise_required" />
  20 + </td>
  21 + <td>
  22 + <input type="checkbox" id="enterprise_signup" />
  23 + </td>
  24 + </tr>
  25 +
12 26 <% @enterprise_fields.each do |field| %>
13 27 <tr>
14 28  
15 29 <td><label for="enterprise_fields[<%= field %>][active]"><%= _(field.humanize) %></label></td>
16 30 <td>
17 31 <%= hidden_field_tag "enterprise_fields[#{field}][active]", false %>
18   - <%= check_box_tag "enterprise_fields[#{field}][active]", true, environment.custom_enterprise_field(field, 'active'), :onclick => "$('enterprise_fields[#{field}][required]').disabled=$('enterprise_fields[#{field}][signup]').disabled=!this.checked;" %>
  32 + <%= check_box_tag "enterprise_fields[#{field}][active]", true, environment.custom_enterprise_field(field, 'active'), :onclick => "active_action(this, 'enterprise_fields[#{field}][required]', 'enterprise_fields[#{field}][signup]')" %>
19 33 </td>
20 34 <td>
21 35 <%= hidden_field_tag "enterprise_fields[#{field}][required]", false %>
22   - <%= check_box_tag "enterprise_fields[#{field}][required]", true, environment.custom_enterprise_field(field, 'required'), :onclick => "if(this.checked) $('enterprise_fields[#{field}][signup]').checked = true;" %>
  36 + <%= check_box_tag "enterprise_fields[#{field}][required]", true, environment.custom_enterprise_field(field, 'required'), :onclick => "required_action('enterprise_fields[#{field}][active]','enterprise_fields[#{field}][required]', 'enterprise_fields[#{field}][signup]')" %>
23 37 </td>
24 38 <td>
25 39 <%= hidden_field_tag "enterprise_fields[#{field}][signup]", false %>
26   - <%= check_box_tag "enterprise_fields[#{field}][signup]", true, environment.custom_enterprise_field(field, 'signup'), :onclick => "if(!this.checked) $('enterprise_fields[#{field}][required]').checked = false;" %>
  40 + <%= check_box_tag "enterprise_fields[#{field}][signup]", true, environment.custom_enterprise_field(field, 'signup'), :onclick => "signup_action('enterprise_fields[#{field}][active]','enterprise_fields[#{field}][required]', 'enterprise_fields[#{field}][signup]')" %>
27 41 </td>
28 42  
29 43 </tr>
... ... @@ -31,18 +45,18 @@
31 45 </table>
32 46  
33 47 <script type='text/javascript'>
34   - var trs = $$('#enterprise_fields_conf tr');
  48 + var trs = jQuery('#enterprise_fields_conf tr');
35 49 var tr, td2;
36   - for ( var i=0; tr=trs[i]; i++ ) {
  50 + for ( var i=2; tr=trs[i]; i++ ) {
37 51 if ( td2 = tr.getElementsByTagName('td')[1] ) {
38   - td2.getElementsByTagName('input')[0].onclick();
  52 + td2.getElementsByTagName('input')[1].onclick();
39 53 }
40 54 }
41 55 </script>
42 56  
43 57 <div>
44 58 <% button_bar do %>
45   - <%= submit_button('save', _('Save changes')) %>
  59 + <%= submit_button('save', _('Save changes'), :id=>"save_enterprise_fields") %>
46 60 <%= button :back, _('Back to admin panel'), :controller => 'admin_panel', :action => 'index' %>
47 61 <% end %>
48 62 </div>
... ...
app/views/features/_manage_person_fields.rhtml
1   -<h2><%= _('Manage person fields') %></h2>
2   -
3 1 <% labelled_form_for(:environment, @environment, :url => {:action => 'manage_person_fields'}) do |f| %>
4 2  
5 3 <table id='person_fields_conf'>
... ... @@ -9,31 +7,48 @@
9 7 <th><%= _('Required') %></th>
10 8 <th><%= _('Display on signup?') %></th>
11 9 </tr>
  10 +
  11 + <tr class='manage-fields-batch-actions'>
  12 + <td>
  13 + <%= _("Check/Uncheck All")%>
  14 + </td>
  15 + <td>
  16 + <input type="checkbox" id="person_active" />
  17 + </td>
  18 + <td>
  19 + <input type="checkbox" id="person_required" />
  20 + </td>
  21 + <td>
  22 + <input type="checkbox" id="person_signup" />
  23 + </td>
  24 + </tr>
  25 +
12 26 <% @person_fields.each do |field| %>
13 27 <tr>
14 28 <td><label for="person_fields[<%= field %>][active]"><%= _(field.humanize) %></label></td>
15 29 <td>
16 30 <%= hidden_field_tag "person_fields[#{field}][active]", false %>
17   - <%= check_box_tag "person_fields[#{field}][active]", true, environment.custom_person_field(field, 'active'), :onclick => "$('person_fields[#{field}][required]').disabled=$('person_fields[#{field}][signup]').disabled=!this.checked;" %>
  31 + <%= check_box_tag "person_fields[#{field}][active]", true, environment.custom_person_field(field, 'active'), :onclick => "active_action(this, 'person_fields[#{field}][required]', 'person_fields[#{field}][signup]')" %>
18 32 </td>
19 33 <td>
20 34 <%= hidden_field_tag "person_fields[#{field}][required]", false %>
21   - <%= check_box_tag "person_fields[#{field}][required]", true, environment.custom_person_field(field, 'required'), :onclick => "if(this.checked) $('person_fields[#{field}][signup]').checked = true;" %>
  35 + <%= check_box_tag "person_fields[#{field}][required]", true, environment.custom_person_field(field, 'required'), :onclick => "required_action('person_fields[#{field}][active]','person_fields[#{field}][required]', 'person_fields[#{field}][signup]')" %>
22 36 </td>
23 37 <td>
24 38 <%= hidden_field_tag "person_fields[#{field}][signup]", false %>
25   - <%= check_box_tag "person_fields[#{field}][signup]", true, environment.custom_person_field(field, 'signup'), :onclick => "if(!this.checked) $('person_fields[#{field}][required]').checked = false;" %>
  39 + <%= check_box_tag "person_fields[#{field}][signup]", true, environment.custom_person_field(field, 'signup'), :onclick => "signup_action('person_fields[#{field}][active]','person_fields[#{field}][required]', 'person_fields[#{field}][signup]')" %>
26 40 </td>
27 41 </tr>
28 42 <% end %>
29 43 </table>
30 44  
31 45 <script type='text/javascript'>// <!--
32   - var trs = $$('#person_fields_conf tr');
  46 + var trs = jQuery('#person_fields_conf tr');
  47 +
33 48 var tr, td2;
34   - for ( var i=0; tr=trs[i]; i++ ) {
  49 + for ( var i=2; tr=trs[i]; i++ ) {
35 50 if ( td2 = tr.getElementsByTagName('td')[1] ) {
36   - td2.getElementsByTagName('input')[0].onclick();
  51 + td2.getElementsByTagName('input')[1].onclick();
37 52 }
38 53 }
39 54 // -->
... ... @@ -41,7 +56,7 @@
41 56  
42 57 <div>
43 58 <% button_bar do %>
44   - <%= submit_button('save', _('Save changes')) %>
  59 + <%= submit_button('save', _('Save changes'), :id=>"save_person_fields") %>
45 60 <%= button :back, _('Back to admin panel'), :controller => 'admin_panel', :action => 'index' %>
46 61 <% end %>
47 62 </div>
... ...
app/views/features/manage_fields.rhtml
1   -<%= render :partial => 'manage_person_fields' %>
  1 +<h1><%= _('Manage fields displayed for profiles') %></h1>
2 2  
3   -<% if !environment.enabled?('disable_asset_enterprises') %>
4   - <%= render :partial => 'manage_enterprise_fields' %>
  3 +<% tabs = [] %>
  4 +<% tabs << {:title => _("Person's fields"), :id => 'person-fields',
  5 + :content => (render :partial => 'manage_person_fields')} %>
  6 +<% tabs << {:title => _("Community's fields"), :id => 'community-fields',
  7 + :content => (render :partial => 'manage_community_fields')} %>
  8 +<% unless environment.enabled?('disable_asset_enterprises') %>
  9 + <% tabs << {:title => _("Enterprise's fields"), :id => 'enterprise-fields',
  10 + :content => (render :partial => 'manage_enterprise_fields')} %>
5 11 <% end %>
6 12  
7   -<%= render :partial => 'manage_community_fields' %>
  13 +<%= render_tabs(tabs) %>
  14 +
  15 +<%= javascript_include_tag "manage-fields.js" %>
... ...
app/views/profile_members/_members_list.rhtml
1   -<% collection = @collection == :profile_admins ? profile.admins : profile.members %>
  1 +<% collection = @collection == :profile_admins ? profile.admins : profile.members_by_name %>
2 2 <% title = @title ? @title : _('Current members') %>
3 3 <% remove_action = @remove_action ? @remove_action : {:action => 'unassociate'} %>
4 4  
... ...
app/views/shared/_select_categories.rhtml
1   -<div id="category-ajax-selector">
  1 +<% extend CategoriesHelper %>
  2 +
2 3 <% if !@current_category.nil? %>
3   - <h3 class="box-title"><%= _('Current category:') %></h3>
4 4 <%= hidden_field_tag "#{object_name}[#{object_name}_category_id]", @current_category.id unless multiple %>
  5 + <%= hidden_field_tag "#{object_name}[category_ids][]", @current_category.id if multiple %>
  6 + <%= button_to_remote_without_text(:back, _('Back'),
  7 + { :update => "select-categories",
  8 + :url => { :action => 'update_categories', :id => @object },
  9 + :loaded => visual_effect(:highlight, "select-categories")
  10 + },
  11 + :id => 'cancel-category-button') %>
5 12 <%
6 13 categories = [@current_category]
7 14 categories.push(@current_category) while @current_category = @current_category.parent
8 15 %>
9 16 <%= categories.compact.reverse.map{|i|
10   - link_to_remote(i.name,
  17 + link_to_remote(i.name,
11 18 :update => "select-categories",
12 19 :url => { :action => 'update_categories', :category_id => i.id, :id => @object },
13 20 :loaded => visual_effect(:highlight, "select-categories"),
14 21 :class => 'select-current-category-link')}.join(' &rarr; ')
15 22 %>
16   - <strong>
17   - <%= button_to_function_without_text(:save, _('Save'), nil, :id => 'save-category-button') do |page|
18   - page.insert_html :bottom, 'selected-categories', content_tag('li', categories.first.full_name +
  23 + <%= button_to_function_without_text(:add, _('Add'), nil, :id => 'save-category-button') do |page|
  24 + page.insert_html :bottom, 'selected-categories', content_tag('div',
19 25 hidden_field_tag("#{object_name}[category_ids][]", categories.first.id) +
20   - button_to_function_without_text(:cancel, _('Remove'), nil, :id => "remove-selected-category-#{categories.first.id}-button") {|page| page["selected-category-#{categories.first.id}"].remove}, :id => "selected-category-#{categories.first.id}")
  26 + selected_category_link(categories.first), :id => "selected-category-#{categories.first.id}")
  27 + page.replace_html 'select-categories', :partial => 'shared/select_subcategories',
  28 + :locals => {:object_name => object_name, :categories => @toplevel_categories}
21 29 end if multiple %>
22   - <%= button_to_remote_without_text(:cancel, _('Cancel'),
23   - { :update => "select-categories",
24   - :url => { :action => 'update_categories', :id => @object },
25   - :loaded => visual_effect(:highlight, "select-categories")
26   - },
27   - :id => 'cancel-category-button') %>
28   - </strong>
29   -<% else %>
30   - <h3 class="box-title"><%= _('Select a category:') %></h3>
31 30 <% end %>
32 31  
33   -<% if !@categories.empty? %>
34   - <h3><%= _('Categories:') %></h3>
35   - <% @categories.select{|i| !@object.respond_to?(:accept_category?) || @object.accept_category?(i)}.each do |category| %>
36   - <%= link_to_remote category.name,
37   - { :update => "select-categories",
38   - :url => { :action => "update_categories", :category_id => category.id, :id => @object},
39   - :loaded => visual_effect(:highlight, "select-categories")
40   - },
41   - :class => 'select-subcategory-link',
42   - :id => "select-category-#{category.id}-link"
43   - %>
44   - <% end %> &nbsp;
45   -<% end %>
  32 +<div class="toplevel-categories">
  33 + <%= render :partial => 'shared/select_subcategories', :locals => {:object_name => object_name, :categories => @categories} %>
46 34 </div>
... ...
app/views/shared/_select_categories_top.rhtml 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +<% categories_selected ||= nil %>
  2 +<% title ||= nil %>
  3 +
  4 +<% extend CategoriesHelper %>
  5 +
  6 +<%= content_tag "h#{title_size}", title, :class => "box-title" %>
  7 +
  8 +<%= hidden_field_tag "#{object_name}[category_ids][]", nil %>
  9 +
  10 +<div id="category-ajax-selector">
  11 +<% unless categories_selected.nil? %>
  12 +<div id="selected-categories">
  13 + <div class="label"><%= _('Selected categories:') %></div>
  14 + <% categories_selected.each do |cat| %>
  15 + <div id="selected-category-<%= cat.id %>">
  16 + <%= hidden_field_tag("#{object_name}[category_ids][]", cat.id) %>
  17 + <%= selected_category_link(cat) %>
  18 + </div>
  19 + <% end %>
  20 +</div>
  21 +<% end %>
  22 +<div id="select-categories">
  23 + <%= render :partial => 'shared/select_categories', :locals => {:object_name => object_name, :multiple => true, :categories_selected => categories_selected }, :layout => false %>
  24 +</div>
  25 +
  26 +</div>
... ...
app/views/shared/_select_subcategories.rhtml 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +<% if !categories.nil? && !categories.empty? && !@object.nil? %>
  2 + <hr>
  3 + <div class="category-helper-label"><%= _('Click to select a category') %></div>
  4 +
  5 + <% categories.select{|i| @object.accept_category?(i)}.each do |category| %>
  6 +
  7 + <%= link_to_remote category.name,
  8 + { :update => "select-categories",
  9 + :url => { :action => "update_categories", :category_id => category.id, :id => @object},
  10 + :loaded => visual_effect(:highlight, "select-categories")
  11 + },
  12 + :class => 'select-subcategory-link',
  13 + :id => "select-category-#{category.id}-link"
  14 + %>
  15 + <% end %>
  16 +<% end %>
... ...
app/views/users/_users_list.rhtml
... ... @@ -19,16 +19,17 @@
19 19 <td class='actions'>
20 20 <div class="members-buttons-cell">
21 21 <% if p.is_admin? %>
22   - <%= button_without_text :'reset-admin-role', _('Reset admin role'), :action => 'reset_admin_role', :id => p, :q => @q, :filter => @filter %>
  22 + <%= button_without_text :'reset-admin-role', _('Reset admin role'), {:action => 'reset_admin_role', :id => p, :q => @q}, :filter => @filter, :confirm => _("Do you want to reset this user as administrator?") %>
23 23 <% else %>
24   - <%= button_without_text :'set-admin-role', _('Set admin role'), :action => 'set_admin_role', :id => p, :q => @q, :filter => @filter %>
  24 + <%= button_without_text :'set-admin-role', _('Set admin role'), {:action => 'set_admin_role', :id => p, :q => @q}, :filter => @filter, :confirm => _("Do you want to set this user as administrator?") %>
25 25 <% end %>
26 26 <% if !p.user.activated? %>
27   - <%= button_without_text :'activate-user', _('Activate user'), :action => 'activate', :id => p, :q => @q, :filter => @filter %>
  27 + <%= button_without_text :'activate-user', _('Activate user'), {:action => 'activate', :id => p, :q => @q}, :filter => @filter, :confirm => _("Do you want to activate this user?") %>
28 28 <% else %>
29   - <%= button_without_text :'deactivate-user', _('Deactivate user'), :action => 'deactivate', :id => p, :q => @q, :filter => @filter %>
  29 + <%= button_without_text :'deactivate-user', _('Deactivate user'), {:action => 'deactivate', :id => p, :q => @q}, :filter => @filter, :confirm => _("Do you want to deactivate this user?") %>
30 30 <% end %>
31   - </div>
  31 + <%= button_without_text :'delete', _('Remove'), {:action => :destroy_user, :id => p, :q => @q}, :method => :post, :filter => @filter, :confirm => _("Do you want to remove this user?") %>
  32 + </div>
32 33 </td>
33 34 </tr>
34 35 <% end %>
... ...
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 7 noosfero (0.46.0) unstable; urgency=low
2 8  
3 9 * New features release
... ...
features/manage_fields.feature 0 → 100644
... ... @@ -0,0 +1,76 @@
  1 +Feature: check all manage fields
  2 + As an administrator
  3 + I want to check and uncheck all person, enterprise and community's fields
  4 +
  5 + Background:
  6 + Given the following users
  7 + | login | name |
  8 + | mariasilva | Maria Silva |
  9 + And the following enterprises
  10 + | identifier | owner | name | contact_email | contact_phone | enabled |
  11 + | paper-street | mariasilva | Paper Street | marial.silva@workerbees.org | (288) 555-0153 | true |
  12 + And the following community
  13 + | identifier | name |
  14 + | mycommunity | My Community |
  15 + And I am logged in as admin
  16 + And I go to /admin/features/manage_fields
  17 +
  18 + @selenium
  19 + Scenario: check all active person fields
  20 + Given I follow "Person's fields"
  21 + And I check "person_active"
  22 + And I press "save_person_fields"
  23 + When I go to admin_user's control panel
  24 + And I follow "Edit Profile"
  25 + Then I should see "Custom area of study"
  26 +
  27 + @selenium
  28 + Scenario: check all active enterprise fields
  29 + Given I follow "Enterprise's fields"
  30 + And I check "enterprise_active"
  31 + And I press "save_enterprise_fields"
  32 + When I go to paper-street's control panel
  33 + And I follow "Enterprise Info and settings"
  34 + Then I should see "Historic and current context"
  35 +
  36 + @selenium
  37 + Scenario: check all active community fields
  38 + Given I follow "Community's fields"
  39 + And I check "community_active"
  40 + And I press "save_community_fields"
  41 + When I go to mycommunity's control panel
  42 + And I follow "Community Info and settings"
  43 + Then I should see "Economic activity"
  44 +
  45 + @selenium
  46 + Scenario: uncheck Check/Uncheck All active person field
  47 + Given I follow "Person's fields"
  48 + And I check "person_active"
  49 + And I press "save_person_fields"
  50 + And I uncheck "person_active"
  51 + And I press "save_person_fields"
  52 + And I follow "Control panel"
  53 + When I follow "Edit Profile"
  54 + Then I should not see "Custom area of study"
  55 +
  56 + @selenium
  57 + Scenario: uncheck Check/Uncheck All active community field
  58 + Given I follow "Community's fields"
  59 + And I check "community_active"
  60 + And I press "save_community_fields"
  61 + And I uncheck "community_active"
  62 + And I press "save_community_fields"
  63 + When I go to mycommunity's control panel
  64 + And I follow "Community Info and settings"
  65 + Then I should not see "Economic activity"
  66 +
  67 + @selenium
  68 + Scenario: uncheck Check/Uncheck All active enterprise field
  69 + Given I follow "Enterprise's fields"
  70 + And I check "enterprise_active"
  71 + And I press "save_enterprise_fields"
  72 + And I uncheck "enterprise_active"
  73 + And I press "save_enterprise_fields"
  74 + When I go to paper-street's control panel
  75 + And I follow "Enterprise Info and settings"
  76 + Then I should not see "Historic and current context"
... ...
features/manage_users.feature 0 → 100644
... ... @@ -0,0 +1,47 @@
  1 +Feature: manage users
  2 + As an environment administrator
  3 + I want to manage users
  4 + In order to remove, activate, deactivate users, and set admin roles.
  5 +
  6 +Background:
  7 + Given the following users
  8 + | login | name |
  9 + | joaosilva | Joao Silva |
  10 + | paulosantos | Paulo Santos |
  11 + Given I am logged in as admin
  12 + Given I go to /admin/users
  13 +
  14 + @selenium
  15 + Scenario: deactive user
  16 + When I follow "Deactivate user" within "tr[title='Joao Silva']"
  17 + And I confirm the "Do you want to deactivate this user?" dialog
  18 + Then I should see "Activate user" within "tr[title='Joao Silva']"
  19 +
  20 + @selenium
  21 + Scenario: activate user
  22 + Given I follow "Deactivate user" within "tr[title='Paulo Santos']"
  23 + Given I confirm the "Do you want to deactivate this user?" dialog
  24 + When I follow "Activate user" within "tr[title='Paulo Santos']"
  25 + And I confirm the "Do you want to activate this user?" dialog
  26 + Then I should see "Deactivate user" within "tr[title='Paulo Santos']"
  27 +
  28 + @selenium
  29 + Scenario: remove user
  30 + When I follow "Remove" within "tr[title='Joao Silva']"
  31 + And I confirm the "Do you want to remove this user?" dialog
  32 + And I go to /admin/users
  33 + Then I should not see "Joao Silva"
  34 +
  35 + @selenium
  36 + Scenario: admin user
  37 + When I follow "Set admin role" within "tr[title='Joao Silva']"
  38 + And I confirm the "Do you want to set this user as administrator?" dialog
  39 + Then I should see "Reset admin role" within "tr[title='Joao Silva']"
  40 +
  41 + @selenium
  42 + Scenario: unadmin user
  43 + Given I follow "Set admin role" within "tr[title='Paulo Santos']"
  44 + And I confirm the "Do you want to set this user as administrator?" dialog
  45 + When I follow "Reset admin role" within "tr[title='Paulo Santos']"
  46 + And I confirm the "Do you want to reset this user as administrator?" dialog
  47 + Then I should see "Set admin role" within "tr[title='Paulo Santos']"
... ...
lib/noosfero.rb
... ... @@ -3,7 +3,7 @@ require &#39;fast_gettext&#39;
3 3  
4 4 module Noosfero
5 5 PROJECT = 'noosfero'
6   - VERSION = '0.46.0'
  6 + VERSION = '0.46.1'
7 7  
8 8 def self.pattern_for_controllers_in_directory(dir)
9 9 disjunction = controllers_in_directory(dir).join('|')
... ...
lib/noosfero/core_ext.rb
1 1 require 'noosfero/core_ext/string'
2 2 require 'noosfero/core_ext/integer'
  3 +require 'noosfero/core_ext/array'
3 4 require 'noosfero/core_ext/object'
4 5 require 'noosfero/core_ext/active_record'
... ...
lib/noosfero/core_ext/array.rb 0 → 100644
... ... @@ -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.rb
... ... @@ -349,6 +349,12 @@ class Noosfero::Plugin
349 349 []
350 350 end
351 351  
  352 + # -> Adds adicional content to article
  353 + # returns = lambda block that creates html code
  354 + def article_extra_contents(article)
  355 + nil
  356 + end
  357 +
352 358 # -> Adds fields to the signup form
353 359 # returns = lambda block that creates html code
354 360 def signup_extra_contents
... ...
lib/noosfero/plugin/routes.rb
... ... @@ -15,12 +15,16 @@ Dir.glob(File.join(Rails.root, plugins_root, &#39;*&#39;, &#39;controllers&#39;)) do |controller
15 15 controllers_by_folder.each do |folder, controllers|
16 16 controllers.each do |controller|
17 17 controller_name = controller.gsub("#{plugin_name}_plugin_",'')
18   - map.connect "#{prefixes_by_folder[folder]}/#{plugin_name}/#{controller_name}/:action/:id", :controller => controller
  18 + if %w[profile myprofile].include?(folder)
  19 + map.connect "#{prefixes_by_folder[folder]}/#{plugin_name}/#{controller_name}/:action/:id", :controller => controller, :profile => /#{Noosfero.identifier_format}/
  20 + else
  21 + map.connect "#{prefixes_by_folder[folder]}/#{plugin_name}/#{controller_name}/:action/:id", :controller => controller
  22 + end
19 23 end
20 24 end
21 25  
22 26 map.connect 'plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin'
23   - map.connect 'profile/:profile/plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_profile'
24   - map.connect 'myprofile/:profile/plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_myprofile'
  27 + map.connect 'profile/:profile/plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_profile', :profile => /#{Noosfero.identifier_format}/
  28 + map.connect 'myprofile/:profile/plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_myprofile', :profile => /#{Noosfero.identifier_format}/
25 29 map.connect 'admin/plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_admin'
26 30 end
... ...
plugins/comment_classification/README.md 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 16 true
17 17 end
18 18  
  19 + def js_files
  20 + 'container_block.js'
  21 + end
  22 +
19 23 end
... ...
plugins/container_block/lib/container_block_plugin/container_block.rb
... ... @@ -7,6 +7,16 @@ class ContainerBlockPlugin::ContainerBlock &lt; Block
7 7 settings_items :container_box_id, :type => Integer, :default => nil
8 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 20 def self.description
11 21 _('Container')
12 22 end
... ... @@ -15,6 +25,10 @@ class ContainerBlockPlugin::ContainerBlock &lt; Block
15 25 _('This block acts as a container for another blocks')
16 26 end
17 27  
  28 + def cacheable?
  29 + false
  30 + end
  31 +
18 32 def layout_template
19 33 nil
20 34 end
... ... @@ -24,8 +38,9 @@ class ContainerBlockPlugin::ContainerBlock &lt; Block
24 38 end
25 39  
26 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 44 save!
30 45 end
31 46  
... ...
plugins/container_block/public/container_block.js 0 → 100644
... ... @@ -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 7 #content .boxes .container-block-plugin_container-block .container_block_child, .container-block-plugin_container-block .block-outer {
2 8 display: inline-block;
3 9 vertical-align: top;
... ... @@ -17,14 +23,10 @@
17 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 26 #content .boxes .container-block-plugin_container-block .block .ui-resizable-handle {
25 27 width: 10px;
26 28 height: 28px;
27   - z-index: 0;
  29 + z-index: 1000;
28 30 }
29 31  
30 32 #content .boxes .container-block-plugin_container-block .block .ui-resizable-e {
... ... @@ -37,6 +39,21 @@
37 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 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 31 assert_tag :div, :attributes => { :class => 'block container-block-plugin_container-block' }
32 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 41 should 'display container children' do
35 42 c1 = RawHTMLBlock.create!(:box => @block.container_box, :html => 'child1 content')
36 43 c2 = RawHTMLBlock.create!(:box => @block.container_box, :html => 'child2 content')
... ...
plugins/container_block/test/unit/block_test.rb
... ... @@ -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 => @box)
9   - end
10   -
11   - should 'return environment box if block owner is not a ContainerBlock' do
12   - block = Block.create!(:box => @box)
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 => @container.container_box)
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 => @box)
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 => @container.container_box)
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 20 assert @block.container_box_id
21 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 28 should 'return created box' do
24 29 @block.save!
25 30 assert @block.container_box
... ... @@ -89,4 +94,27 @@ class ContainerBlockPlugin::ContainerBlockTest &lt; ActiveSupport::TestCase
89 94 end
90 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 120 end
... ...
plugins/container_block/test/unit/environment_test.rb
... ... @@ -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 = Box.create!(:owner => @environment)
9   - @block = Block.create!(:box => @box)
10   -
11   - @container = ContainerBlockPlugin::ContainerBlock.create!(: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 => @container.container_box)
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 => @container.container_box)
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   -require 'test_helper'
2   -
3   -class ProfileTest < ActiveSupport::TestCase
4   -
5   - def setup
6   - @profile = fast_create(Profile)
7   -
8   - @box = Box.create!(:owner => @profile)
9   - @block = Block.create!(:box => @box)
10   -
11   - @container = ContainerBlockPlugin::ContainerBlock.create!(: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 => @container.container_box)
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 => @container.container_box)
29   - assert_equal child, @profile.blocks.find(child.id)
30   - end
31   -
32   -end
plugins/container_block/views/blocks/container.rhtml
1 1 <% edit_mode = @controller.send(:boxes_editor?) && @controller.send(:uses_design_blocks?) %>
2 2 <% box_decorator = edit_mode ? self : BoxesHelper::DontMoveBlocks %>
3 3  
  4 +<%= block_title(block.title) %>
4 5  
5 6 <div class="box" id="box-<%= block.container_box.id %>">
6 7 <%= display_box_content(block.container_box, nil) %>
... ... @@ -15,8 +16,18 @@
15 16 </style>
16 17  
17 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>
  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">
20 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 32 :with => "containerChildrenWidth(#{block.id}, #{block.container_box.id})",
22 33 :html => {:class => "button icon-save container_block_save", :id => "container_block_save_#{block.id}", :title => _('Save') },
... ... @@ -24,37 +35,4 @@
24 35 :loaded => "close_loading();",
25 36 :complete => "display_notice(request.responseText);"%>
26 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 38 <% end %>
... ...
plugins/context_content/views/blocks/_more.rhtml
1 1 <% if contents.total_pages > 1 %>
2   - <%= link_to_remote(nil, :url => {:id => block.id, :controller => 'context_content_plugin_profile', :action => 'view_content', :page => contents.previous_page, :article_id => article_id }, :html => {:class => "button icon-button icon-left #{contents.previous_page ? '':'disabled'}".strip}, :condition => "#{!contents.previous_page.nil?}", :success => "jQuery('#context_content_#{block.id}').effect('slide', {direction: 'left'});" )%>
3   - <%= link_to_remote(nil, :url => {:id => block.id, :controller => 'context_content_plugin_profile', :action => 'view_content', :page => contents.next_page, :article_id => article_id }, :html => {:class => "button icon-button icon-right #{contents.next_page ? '':'disabled'}".strip}, :condition => "#{!contents.next_page.nil?}", :success => "jQuery('#context_content_#{block.id}').effect('slide', {direction: 'right'});" )%>
  2 + <%= link_to_remote(nil, :url => {:profile => block.owner.identifier, :id => block.id, :controller => 'context_content_plugin_profile', :action => 'view_content', :page => contents.previous_page, :article_id => article_id }, :html => {:class => "button icon-button icon-left #{contents.previous_page ? '':'disabled'}".strip}, :condition => "#{!contents.previous_page.nil?}", :success => "jQuery('#context_content_#{block.id}').effect('slide', {direction: 'left'});" )%>
  3 + <%= link_to_remote(nil, :url => {:profile => block.owner.identifier, :id => block.id, :controller => 'context_content_plugin_profile', :action => 'view_content', :page => contents.next_page, :article_id => article_id }, :html => {:class => "button icon-button icon-right #{contents.next_page ? '':'disabled'}".strip}, :condition => "#{!contents.next_page.nil?}", :success => "jQuery('#context_content_#{block.id}').effect('slide', {direction: 'right'});" )%>
4 4 <% end %>
... ...
plugins/display_content/lib/display_content_block.rb
... ... @@ -61,9 +61,12 @@ class DisplayContentBlock &lt; Block
61 61  
62 62 VALID_CONTENT = ['RawHTMLArticle', 'TextArticle', 'TextileArticle', 'TinyMceArticle', 'Folder', 'Blog', 'Forum']
63 63  
  64 + include Noosfero::Plugin::HotSpot
  65 +
64 66 def articles_of_parent(parent = nil)
65 67 return [] if self.holder.nil?
66   - holder.articles.find(:all, :conditions => {:type => VALID_CONTENT, :parent_id => (parent.nil? ? nil : parent)})
  68 + types = VALID_CONTENT + plugins.dispatch(:content_types).map(&:name)
  69 + holder.articles.find(:all, :conditions => {:type => types, :parent_id => (parent.nil? ? nil : parent)})
67 70 end
68 71  
69 72 include ActionController::UrlWriter
... ...
plugins/display_content/test/unit/display_content_block_test.rb
... ... @@ -238,6 +238,7 @@ class DisplayContentBlockTest &lt; ActiveSupport::TestCase
238 238 block.nodes= [a1.id, a2.id, a3.id]
239 239 box = mock()
240 240 box.stubs(:owner).returns(profile)
  241 + box.stubs(:environment).returns(Environment.default)
241 242 block.stubs(:box).returns(box)
242 243 assert_equal [], [a1, a2] - block.articles_of_parent
243 244 assert_equal [], block.articles_of_parent - [a1, a2]
... ... @@ -253,6 +254,7 @@ class DisplayContentBlockTest &lt; ActiveSupport::TestCase
253 254 block = DisplayContentBlock.new
254 255 box = mock()
255 256 box.stubs(:owner).returns(profile)
  257 + box.stubs(:environment).returns(Environment.default)
256 258 block.stubs(:box).returns(box)
257 259 assert_equal [], [a3] - block.articles_of_parent(a2)
258 260 assert_equal [], block.articles_of_parent(a2) - [a3]
... ... @@ -270,6 +272,7 @@ class DisplayContentBlockTest &lt; ActiveSupport::TestCase
270 272 box = mock()
271 273 block.stubs(:box).returns(box)
272 274 box.stubs(:owner).returns(environment)
  275 + box.stubs(:environment).returns(Environment.default)
273 276 environment.stubs(:portal_community).returns(profile)
274 277  
275 278 assert_equal [], [a1, a2] - block.articles_of_parent
... ... @@ -288,6 +291,7 @@ class DisplayContentBlockTest &lt; ActiveSupport::TestCase
288 291 box = mock()
289 292 block.stubs(:box).returns(box)
290 293 box.stubs(:owner).returns(environment)
  294 + box.stubs(:environment).returns(Environment.default)
291 295 environment.stubs(:portal_community).returns(profile)
292 296  
293 297 assert_equal [], [a3] - block.articles_of_parent(a2)
... ... @@ -301,6 +305,7 @@ class DisplayContentBlockTest &lt; ActiveSupport::TestCase
301 305 box = mock()
302 306 block.stubs(:box).returns(box)
303 307 box.stubs(:owner).returns(environment)
  308 + box.stubs(:environment).returns(Environment.default)
304 309  
305 310 assert_equal [], block.articles_of_parent()
306 311 end
... ... @@ -316,6 +321,7 @@ class DisplayContentBlockTest &lt; ActiveSupport::TestCase
316 321 block = DisplayContentBlock.new
317 322 box = mock()
318 323 box.stubs(:owner).returns(profile)
  324 + box.stubs(:environment).returns(Environment.default)
319 325 block.stubs(:box).returns(box)
320 326 assert_equal [], [a2] - block.articles_of_parent
321 327 assert_equal [], block.articles_of_parent - [a2]
... ... @@ -334,6 +340,7 @@ class DisplayContentBlockTest &lt; ActiveSupport::TestCase
334 340 block = DisplayContentBlock.new
335 341 box = mock()
336 342 box.stubs(:owner).returns(profile)
  343 + box.stubs(:environment).returns(Environment.default)
337 344 block.stubs(:box).returns(box)
338 345 assert_equal [a1], block.articles_of_parent
339 346 end
... ... @@ -526,4 +533,28 @@ class DisplayContentBlockTest &lt; ActiveSupport::TestCase
526 533 assert_equivalent [f1.id, a1.id, a2.id, a3.id], block.nodes
527 534 end
528 535  
  536 + should "test should return plugins articles in articles of parent method" do
  537 + class PluginArticle < Article; end
  538 +
  539 + class Plugin1 < Noosfero::Plugin
  540 + def content_types
  541 + [PluginArticle]
  542 + end
  543 + end
  544 +
  545 + profile = create_user('testuser').person
  546 + Article.delete_all
  547 + a1 = fast_create(PluginArticle, :name => 'test article 1', :profile_id => profile.id)
  548 +
  549 + env = fast_create(Environment)
  550 + env.enable_plugin(Plugin1)
  551 +
  552 + block = DisplayContentBlock.new
  553 + box = mock()
  554 + box.stubs(:owner).returns(profile)
  555 + box.stubs(:environment).returns(env)
  556 + block.stubs(:box).returns(box)
  557 + assert_equal [a1], block.articles_of_parent
  558 + end
  559 +
529 560 end
... ...
plugins/mark_comment_as_read/controllers/mark_comment_as_read_plugin_profile_controller.rb 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +class MarkCommentAsReadPluginProfileController < ProfileController
  2 +
  3 + append_view_path File.join(File.dirname(__FILE__) + '/../views')
  4 +
  5 + def mark_as_read
  6 + comment = Comment.find(params[:id])
  7 + comment.mark_as_read(user)
  8 + render :text => {'ok' => true}.to_json, :content_type => 'application/json'
  9 + end
  10 +
  11 + def mark_as_not_read
  12 + comment = Comment.find(params[:id])
  13 + comment.mark_as_not_read(user)
  14 + render :text => {'ok' => true}.to_json, :content_type => 'application/json'
  15 + end
  16 +
  17 +end
... ...
plugins/mark_comment_as_read/db/migrate/20130509184338_create_mark_comment_as_read_plugin.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +class CreateMarkCommentAsReadPlugin < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :mark_comment_as_read_plugin do |t|
  4 + t.integer :comment_id
  5 + t.integer :person_id
  6 + end
  7 + add_index :mark_comment_as_read_plugin, [:comment_id, :person_id], :unique => true
  8 + end
  9 +
  10 + def self.down
  11 + drop_table :mark_comment_as_read_plugin
  12 + end
  13 +end
... ...
plugins/mark_comment_as_read/lib/mark_comment_as_read_plugin.rb 0 → 100644
... ... @@ -0,0 +1,45 @@
  1 +require_dependency 'mark_comment_as_read_plugin/ext/comment'
  2 +
  3 +class MarkCommentAsReadPlugin < Noosfero::Plugin
  4 +
  5 + def self.plugin_name
  6 + "MarkCommentAsReadPlugin"
  7 + end
  8 +
  9 + def self.plugin_description
  10 + _("Provide a button to mark a comment as read.")
  11 + end
  12 +
  13 + def js_files
  14 + 'mark_comment_as_read.js'
  15 + end
  16 +
  17 + def stylesheet?
  18 + true
  19 + end
  20 +
  21 + def comment_actions(comment)
  22 + lambda do
  23 + [{:link => link_to_function(_('Mark as not read'), 'toggle_comment_read(this, %s, false);' % url_for(:controller => 'mark_comment_as_read_plugin_profile', :profile => profile.identifier, :action => 'mark_as_not_read', :id => comment.id).to_json, :class => 'comment-footer comment-footer-link comment-footer-hide comment-action-extra', :style => 'display: none', :id => "comment-action-mark-as-not-read-#{comment.id}")},
  24 + {:link => link_to_function(_('Mark as read'), 'toggle_comment_read(this, %s, true);' % url_for(:controller => 'mark_comment_as_read_plugin_profile', :profile => profile.identifier, :action => 'mark_as_read', :id => comment.id).to_json, :class => 'comment-footer comment-footer-link comment-footer-hide comment-action-extra', :style => 'display: none', :id => "comment-action-mark-as-read-#{comment.id}")}] if user
  25 + end
  26 + end
  27 +
  28 + def check_comment_actions(comment)
  29 + lambda do
  30 + if user
  31 + comment.marked_as_read?(user) ? "#comment-action-mark-as-not-read-#{comment.id}" : "#comment-action-mark-as-read-#{comment.id}"
  32 + end
  33 + end
  34 + end
  35 +
  36 + def article_extra_contents(article)
  37 + lambda do
  38 + if user
  39 + ids = article.comments.marked_as_read(user).collect { |comment| comment.id}
  40 + "<script type=\"text/javascript\">mark_comments_as_read(#{ids.to_json});</script>" if !ids.empty?
  41 + end
  42 + end
  43 + end
  44 +
  45 +end
... ...
plugins/mark_comment_as_read/lib/mark_comment_as_read_plugin/ext/comment.rb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +require_dependency 'comment'
  2 +
  3 +class Comment
  4 +
  5 + has_many :read_comments, :class_name => 'MarkCommentAsReadPlugin::ReadComments'
  6 + has_many :people, :through => :read_comments
  7 +
  8 + def mark_as_read(person)
  9 + people << person
  10 + end
  11 +
  12 + def mark_as_not_read(person)
  13 + people.delete(person)
  14 + end
  15 +
  16 + def marked_as_read?(person)
  17 + person && people.find(:first, :conditions => {:id => person.id})
  18 + end
  19 +
  20 + def self.marked_as_read(person)
  21 + find(:all, :joins => [:read_comments], :conditions => {:author_id => person.id})
  22 + end
  23 +
  24 +end
... ...
plugins/mark_comment_as_read/lib/mark_comment_as_read_plugin/read_comments.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +class MarkCommentAsReadPlugin::ReadComments < Noosfero::Plugin::ActiveRecord
  2 + set_table_name 'mark_comment_as_read_plugin'
  3 + belongs_to :comment
  4 + belongs_to :person
  5 +
  6 + validates_presence_of :comment, :person
  7 +end
... ...
plugins/mark_comment_as_read/public/mark_comment_as_read.js 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +function mark_comments_as_read(comments) {
  2 + jQuery(document).ready(function($) {
  3 + for(var i=0; i<comments.length; i++) {
  4 + $comment = jQuery('#comment-'+comments[i]);
  5 + $comment.find('.comment-content').first().addClass('comment-mark-read');
  6 + }
  7 + });
  8 +}
  9 +
  10 +function toggle_comment_read(button, url, mark) {
  11 + var $ = jQuery;
  12 + var $button = $(button);
  13 + $button.addClass('comment-button-loading');
  14 + $.post(url, function(data) {
  15 + if (data.ok) {
  16 + var $comment = $button.closest('.article-comment');
  17 + var $content = $comment.find('.comment-content').first();
  18 + if(mark)
  19 + $content.addClass('comment-mark-read');
  20 + else
  21 + $content.removeClass('comment-mark-read');
  22 + $button.hide();
  23 + $button.removeClass('comment-button-loading');
  24 + return;
  25 + }
  26 + });
  27 +}
  28 +
... ...
plugins/mark_comment_as_read/public/style.css 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +.article-comments-list .comment-mark-read .comment-text, .article-comments-list .comment-mark-read h4, .article-comments-list .comment-mark-read .comment-picture {
  2 + opacity: 0.2;
  3 +}
... ...
plugins/mark_comment_as_read/test/functional/mark_comment_as_read_plugin_profile_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,33 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +require File.dirname(__FILE__) + '/../../controllers/mark_comment_as_read_plugin_profile_controller'
  3 +
  4 +# Re-raise errors caught by the controller.
  5 +class MarkCommentAsReadPluginProfileController; def rescue_action(e) raise e end; end
  6 +
  7 +class MarkCommentAsReadPluginProfileControllerTest < ActionController::TestCase
  8 + def setup
  9 + @controller = MarkCommentAsReadPluginProfileController.new
  10 + @request = ActionController::TestRequest.new
  11 + @response = ActionController::TestResponse.new
  12 + @profile = create_user('profile').person
  13 + @article = TinyMceArticle.create!(:profile => @profile, :name => 'An article')
  14 + @comment = Comment.new(:source => @article, :author => @profile, :body => 'test')
  15 + @comment.save!
  16 + login_as(@profile.identifier)
  17 + environment = Environment.default
  18 + environment.enable_plugin(MarkCommentAsReadPlugin)
  19 + self.stubs(:user).returns(@profile)
  20 + end
  21 +
  22 + attr_reader :profile, :comment
  23 +
  24 + should 'mark comment as read' do
  25 + xhr :post, :mark_as_read, :profile => profile.identifier, :id => comment.id
  26 + assert_match /\{\"ok\":true\}/, @response.body
  27 + end
  28 +
  29 + should 'mark comment as not read' do
  30 + xhr :post, :mark_as_not_read, :profile => profile.identifier, :id => comment.id
  31 + assert_match /\{\"ok\":true\}/, @response.body
  32 + end
  33 +end
... ...
plugins/mark_comment_as_read/test/unit/mark_comment_as_read_plugin/comment_test.rb 0 → 100644
... ... @@ -0,0 +1,38 @@
  1 +require File.dirname(__FILE__) + '/../../../../../test/test_helper'
  2 +
  3 +class MarkCommentAsReadPlugin::CommentTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @person = create_user('user').person
  7 + @article = TinyMceArticle.create!(:profile => @person, :name => 'An article')
  8 + @comment = Comment.create!(:title => 'title', :body => 'body', :author_id => @person.id, :source => @article)
  9 + end
  10 +
  11 + should 'mark comment as read' do
  12 + assert !@comment.marked_as_read?(@person)
  13 + @comment.mark_as_read(@person)
  14 + assert @comment.marked_as_read?(@person)
  15 + end
  16 +
  17 + should 'do not mark a comment as read again' do
  18 + @comment.mark_as_read(@person)
  19 + assert_raise ActiveRecord::StatementInvalid do
  20 + @comment.mark_as_read(@person)
  21 + end
  22 + end
  23 +
  24 + should 'mark comment as not read' do
  25 + @comment.mark_as_read(@person)
  26 + assert @comment.marked_as_read?(@person)
  27 + @comment.mark_as_not_read(@person)
  28 + assert !@comment.marked_as_read?(@person)
  29 + end
  30 +
  31 + should 'return comments marked as read for a user' do
  32 + person2 = create_user('user2').person
  33 + @comment.mark_as_read(@person)
  34 + assert_equal [], @article.comments.marked_as_read(@person) - [@comment]
  35 + assert_equal [], @article.comments.marked_as_read(person2)
  36 + end
  37 +
  38 +end
... ...
plugins/mark_comment_as_read/test/unit/mark_comment_as_read_test.rb 0 → 100644
... ... @@ -0,0 +1,87 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +
  3 +class MarkCommentAsReadPluginTest < ActiveSupport::TestCase
  4 +
  5 + include ActionView::Helpers::TagHelper
  6 + include NoosferoTestHelper
  7 +
  8 + def setup
  9 + @plugin = MarkCommentAsReadPlugin.new
  10 + @person = create_user('user').person
  11 + @article = TinyMceArticle.create!(:profile => @person, :name => 'An article')
  12 + @comment = Comment.create!(:source => @article, :author => @person, :body => 'test')
  13 + self.stubs(:user).returns(@person)
  14 + self.stubs(:profile).returns(@person)
  15 + end
  16 +
  17 + attr_reader :plugin, :comment
  18 +
  19 + should 'show link when person is logged in' do
  20 + action = @plugin.comment_actions(@comment)
  21 + link = self.instance_eval(&action)
  22 + assert link
  23 + end
  24 +
  25 + should 'do not show link when person is not logged in' do
  26 + self.stubs(:user).returns(nil)
  27 + action = @plugin.comment_actions(@comment)
  28 + link = self.instance_eval(&action)
  29 + assert !link
  30 + end
  31 +
  32 + should 'return actions when comment is not read' do
  33 + action = @plugin.comment_actions(@comment)
  34 + links = self.instance_eval(&action)
  35 + assert_equal 2, links.size
  36 + end
  37 +
  38 + should 'return actions when comment is read' do
  39 + @comment.mark_as_read(@person)
  40 + action = @plugin.comment_actions(@comment)
  41 + links = self.instance_eval(&action)
  42 + assert_equal 2, links.size
  43 + end
  44 +
  45 + should 'do not return any id when user is not logged in' do
  46 + self.stubs(:user).returns(nil)
  47 + action = @plugin.check_comment_actions(@comment)
  48 + id = self.instance_eval(&action)
  49 + assert !id
  50 + end
  51 +
  52 + should 'return id of mark as not read link when comment is read' do
  53 + @comment.mark_as_read(@person)
  54 + action = @plugin.check_comment_actions(@comment)
  55 + id = self.instance_eval(&action)
  56 + assert_equal "#comment-action-mark-as-not-read-#{@comment.id}", id
  57 + end
  58 +
  59 + should 'return id of mark as read link when comment is not read' do
  60 + action = @plugin.check_comment_actions(@comment)
  61 + id = self.instance_eval(&action)
  62 + assert_equal "#comment-action-mark-as-read-#{@comment.id}", id
  63 + end
  64 +
  65 + should 'return javascript to mark comment as read' do
  66 + @comment.mark_as_read(@person)
  67 + content = @plugin.article_extra_contents(@article)
  68 + assert self.instance_eval(&content)
  69 + end
  70 +
  71 + should 'do not return extra content if comment is not marked as read' do
  72 + content = @plugin.article_extra_contents(@article)
  73 + assert !self.instance_eval(&content)
  74 + end
  75 +
  76 + should 'do not return extra content if user is not logged in' do
  77 + @comment.mark_as_read(@person)
  78 + self.stubs(:user).returns(nil)
  79 + content = @plugin.article_extra_contents(@article)
  80 + assert !self.instance_eval(&content)
  81 + end
  82 +
  83 + def link_to_function(content, url, options = {})
  84 + link_to(content, url, options)
  85 + end
  86 +
  87 +end
... ...
plugins/require_auth_to_comment/public/hide_comment_form.js
1 1 (function($) {
2 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 4 $('.post-comment-button').livequery(function() {
5 5 $(this).show();
6 6 });
... ... @@ -8,7 +8,7 @@
8 8 $(this).show();
9 9 });
10 10 $('.comment-footer').livequery(function() {
11   - $(this).show();
  11 + $(this).show();
12 12 });
13 13 }
14 14 });
... ...