Commit 37439649ee6ea45759cf3242012249e3eaeb0d55
Exists in
master
and in
22 other branches
Merge branch 'rails3' of gitlab.com:noosfero/noosfero into rails3
Conflicts: lib/noosfero/plugin/routes.rb plugins/container_block/test/unit/block_test.rb plugins/container_block/test/unit/environment_test.rb plugins/container_block/test/unit/profile_test.rb plugins/container_block/views/blocks/container.html.erb
Showing
81 changed files
with
1032 additions
and
190 deletions
Show diff stats
INSTALL.md
... | ... | @@ -23,7 +23,7 @@ You need to install some packages Noosfero depends on. On Debian GNU/Linux or De |
23 | 23 | # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby1.8 \ |
24 | 24 | libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libhpricot-ruby \ |
25 | 25 | libwill-paginate-ruby iso-codes libfeedparser-ruby libdaemons-ruby thin \ |
26 | - tango-icon-theme libnokogiri-ruby | |
26 | + tango-icon-theme | |
27 | 27 | |
28 | 28 | On other systems, they may or may not be available through your regular package management system. Below are the links to their homepages. |
29 | 29 | |
... | ... | @@ -41,7 +41,6 @@ On other systems, they may or may not be available through your regular package |
41 | 41 | * Thin: http://code.macournoyer.com/thin |
42 | 42 | * tango-icon-theme: http://tango.freedesktop.org/Tango_Icon_Library |
43 | 43 | * Hpricot: http://hpricot.com |
44 | -* Nokogiri: http://nokogiri.org/ | |
45 | 44 | |
46 | 45 | If you manage to install Noosfero successfully on other systems than Debian, |
47 | 46 | please feel free to contact the Noosfero development mailing with the | ... | ... |
app/controllers/admin/users_controller.rb
... | ... | @@ -7,7 +7,7 @@ class UsersController < AdminController |
7 | 7 | 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 | ... | ... |
app/controllers/application_controller.rb
... | ... | @@ -24,6 +24,7 @@ class ApplicationController < ActionController::Base |
24 | 24 | include ApplicationHelper |
25 | 25 | layout :get_layout |
26 | 26 | def get_layout |
27 | + return nil if request.format == :js | |
27 | 28 | theme_layout = theme_option(:layout) |
28 | 29 | if theme_layout |
29 | 30 | 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/profile_members_controller.rb
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 | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -1415,16 +1415,16 @@ module ApplicationHelper |
1415 | 1415 | end |
1416 | 1416 | |
1417 | 1417 | def convert_macro(html, source) |
1418 | - doc = Nokogiri::HTML(html) | |
1418 | + doc = Hpricot(html) | |
1419 | 1419 | #TODO This way is more efficient but do not support macro inside of |
1420 | 1420 | # macro. You must parse them from the inside-out in order to enable |
1421 | 1421 | # that. |
1422 | - doc.css('.macro').each do |macro| | |
1422 | + doc.search('.macro').each do |macro| | |
1423 | 1423 | macro_name = macro['data-macro'] |
1424 | 1424 | result = @plugins.parse_macro(macro_name, macro, source) |
1425 | - macro.content = result.kind_of?(Proc) ? self.instance_eval(&result) : result | |
1425 | + macro.inner_html = result.kind_of?(Proc) ? self.instance_eval(&result) : result | |
1426 | 1426 | end |
1427 | - CGI.unescapeHTML(doc.xpath('//body/*').to_s) | |
1427 | + doc.html | |
1428 | 1428 | end |
1429 | 1429 | |
1430 | 1430 | def default_folder_for_image_upload(profile) | ... | ... |
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/models/box.rb
app/models/environment.rb
app/models/link_list_block.rb
... | ... | @@ -65,7 +65,7 @@ class LinkListBlock < Block |
65 | 65 | def link_html(link) |
66 | 66 | klass = 'icon-' + link[:icon] if link[:icon] |
67 | 67 | sanitize_link( |
68 | - link_to(link[:name], expand_address(link[:address]), :target => link[:target], :class => klass) | |
68 | + link_to(link[:name], expand_address(link[:address]), :target => link[:target], :class => klass, :title => link[:title]) | |
69 | 69 | ) |
70 | 70 | end |
71 | 71 | ... | ... |
app/models/profile.rb
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/box_organizer/_link_list_block.html.erb
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.html.erb
... | ... | @@ -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,6 +75,13 @@ |
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 | |
88 | 87 | <div class="comments" id="comments_list"> | ... | ... |
app/views/profile_members/_members_list.html.erb
1 | -<% collection = @collection == :profile_admins ? profile.admins : profile.members %> | |
1 | +<% collection = @collection == :profile_admins ? profile.admins : profile.members_by_name %> | |
2 | 2 | <% title = @title ? @title : _('Current members') %> |
3 | 3 | <% remove_action = @remove_action ? @remove_action : {:action => 'unassociate'} %> |
4 | 4 | ... | ... |
debian/changelog
lib/noosfero.rb
lib/noosfero/plugin/macro.rb
... | ... | @@ -33,9 +33,9 @@ class Noosfero::Plugin::Macro |
33 | 33 | end |
34 | 34 | |
35 | 35 | def attributes(macro) |
36 | - macro.attributes. | |
36 | + macro.attributes.to_hash. | |
37 | 37 | select {|key, value| key[0..10] == 'data-macro-'}. |
38 | - inject({}){|result, a| result.merge({a[0][11..-1] => a[1].value})}. | |
38 | + inject({}){|result, a| result.merge({a[0][11..-1] => a[1]})}. | |
39 | 39 | with_indifferent_access |
40 | 40 | end |
41 | 41 | ... | ... |
lib/noosfero/plugin/routes.rb
... | ... | @@ -15,7 +15,11 @@ Dir.glob(Rails.root.join(plugins_root, '*', 'controllers')) do |controllers_dir| |
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 | - match "#{prefixes_by_folder[folder]}/#{plugin_name}/#{controller_name}(/:action(/:id))", :controller => controller | |
18 | + if %w[profile myprofile].include?(folder) | |
19 | + match "#{prefixes_by_folder[folder]}/#{plugin_name}/#{controller_name}(/:action(/:id))", :controller => controller, :profile => /#{Noosfero.identifier_format}/ | |
20 | + else | |
21 | + match "#{prefixes_by_folder[folder]}/#{plugin_name}/#{controller_name}(/:action(/:id))", :controller => controller | |
22 | + end | |
19 | 23 | end |
20 | 24 | end |
21 | 25 | ... | ... |
... | ... | @@ -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
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 | ... | ... |
... | ... | @@ -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" | ... | ... |
... | ... | @@ -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,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/public/images/comment-classification.png
0 → 100644
4.15 KB
... | ... | @@ -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
plugins/comment_classification/views/comment_classification_plugin_labels/edit.rhtml
0 → 100644
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
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
plugins/comment_classification/views/comment_classification_plugin_status/edit.rhtml
0 → 100644
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
plugins/container_block/lib/container_block_plugin/container_block.rb
... | ... | @@ -7,6 +7,16 @@ class ContainerBlockPlugin::ContainerBlock < 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 < 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 < 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 | ... | ... |
... | ... | @@ -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 < 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_id => @block.container_box.id, :html => 'child1 content') |
36 | 43 | c2 = RawHTMLBlock.create!(:box_id => @block.container_box.id, :html => 'child2 content') | ... | ... |
plugins/container_block/test/unit/block_test.rb
... | ... | @@ -1,31 +0,0 @@ |
1 | -require 'test_helper' | |
2 | - | |
3 | -class BlockTest < ActiveSupport::TestCase | |
4 | - | |
5 | - def setup | |
6 | - @environment = fast_create(Environment) | |
7 | - @box = Box.create!(:owner => @environment) | |
8 | - @container = ContainerBlockPlugin::ContainerBlock.create!(:box_id => @box.id) | |
9 | - end | |
10 | - | |
11 | - should 'return environment box if block owner is not a ContainerBlock' do | |
12 | - block = Block.create!(:box_id => @box.id) | |
13 | - assert_equal @box, block.box | |
14 | - end | |
15 | - | |
16 | - should 'return container box if block owner is a ContainerBlock' do | |
17 | - block = Block.create!(:box_id => @container.container_box.id) | |
18 | - assert_equal @container.container_box, block.box | |
19 | - end | |
20 | - | |
21 | - should 'return block owner if block onwer is not a ContainerBlock' do | |
22 | - block = Block.create!(:box_id => @box.id) | |
23 | - assert_equal @environment, block.owner | |
24 | - end | |
25 | - | |
26 | - should 'return environment as owner if block onwer is a ContainerBlock' do | |
27 | - block = Block.create!(:box_id => @container.container_box.id) | |
28 | - assert_equal @environment, block.owner | |
29 | - end | |
30 | - | |
31 | -end |
plugins/container_block/test/unit/container_block_plugin/container_block_test.rb
... | ... | @@ -20,6 +20,11 @@ class ContainerBlockPlugin::ContainerBlockTest < 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 < 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 = create(Box, :owner => @environment) | |
9 | - @block = create(Block, :box => @box) | |
10 | - | |
11 | - @container = create(ContainerBlockPlugin::ContainerBlock, :box => @box) | |
12 | - end | |
13 | - | |
14 | - should 'return blocks as usual' do | |
15 | - assert_equal [@block, @container], @environment.blocks | |
16 | - end | |
17 | - | |
18 | - should 'return blocks with container children' do | |
19 | - child = Block.create!(:box_id => @container.container_box.id) | |
20 | - assert_equal [@block, @container, child], @environment.blocks | |
21 | - end | |
22 | - | |
23 | - should 'return block with id at find method' do | |
24 | - assert_equal @block, @environment.blocks.find(@block.id) | |
25 | - end | |
26 | - | |
27 | - should 'return child block with id at find method' do | |
28 | - child = Block.create!(:box_id => @container.container_box.id) | |
29 | - assert_equal child, @environment.blocks.find(child.id) | |
30 | - end | |
31 | - | |
32 | -end |
plugins/container_block/test/unit/profile_test.rb
... | ... | @@ -1,32 +0,0 @@ |
1 | -require 'test_helper' | |
2 | - | |
3 | -class ProfileTest < ActiveSupport::TestCase | |
4 | - | |
5 | - def setup | |
6 | - @profile = fast_create(Profile) | |
7 | - | |
8 | - @box = create(Box, :owner => @profile) | |
9 | - @block = create(Block, :box => @box) | |
10 | - | |
11 | - @container = create(ContainerBlockPlugin::ContainerBlock, :box => @box) | |
12 | - end | |
13 | - | |
14 | - should 'return blocks as usual' do | |
15 | - assert_equal [@block, @container], @profile.blocks | |
16 | - end | |
17 | - | |
18 | - should 'return blocks with container children' do | |
19 | - child = Block.create!(:box_id => @container.container_box.id) | |
20 | - assert_equal [@block, @container, child], @profile.blocks | |
21 | - end | |
22 | - | |
23 | - should 'return block with id at find method' do | |
24 | - assert_equal @block, @profile.blocks.find(@block.id) | |
25 | - end | |
26 | - | |
27 | - should 'return child block with id at find method' do | |
28 | - child = Block.create!(:box_id => @container.container_box.id) | |
29 | - assert_equal child, @profile.blocks.find(child.id) | |
30 | - end | |
31 | - | |
32 | -end |
plugins/container_block/views/blocks/container.html.erb
1 | 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,46 +16,23 @@ |
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> | |
20 | - <%= link_to_remote '', :url => { :controller => controller.boxes_holder.kind_of?(Environment) ? 'container_block_plugin_admin' : 'container_block_plugin_myprofile', :action => 'saveWidths', :id => block.id }, | |
19 | + | |
20 | + <script> | |
21 | + jQuery("#block-<%= block.id %>").hover( | |
22 | + function() { | |
23 | + enableMoveContainerChildren(<%= block.id %>, <%= block.container_box.id %>); | |
24 | + }, function() { | |
25 | + disableMoveContainerChildren(<%= block.id %>, <%= block.container_box.id %>); | |
26 | + } | |
27 | + ); | |
28 | + </script> | |
29 | + | |
30 | + <div class="container-block-button-bar button-bar"> | |
31 | + <%= link_to_remote '', :url => { :controller => @controller.boxes_holder.kind_of?(Environment) ? 'container_block_plugin_admin' : 'container_block_plugin_myprofile', :action => 'saveWidths', :id => block.id }, | |
21 | 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') }, |
23 | 34 | :loading => "open_loading(DEFAULT_LOADING_MESSAGE);", |
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/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 | }); | ... | ... |
public/stylesheets/application.css
1 | +/* browser fixes */ | |
2 | + | |
3 | +img:-moz-broken { | |
4 | + -moz-force-broken-image-icon:1; | |
5 | +} | |
6 | + | |
7 | +/* general styles */ | |
8 | + | |
1 | 9 | body { |
2 | 10 | padding: 0px; |
3 | 11 | margin: 0px; |
... | ... | @@ -1727,8 +1735,8 @@ a.button.disabled, input.disabled { |
1727 | 1735 | display: none; |
1728 | 1736 | } |
1729 | 1737 | |
1730 | -#box-organizer .block:focus .button-bar, | |
1731 | -#box-organizer .block:hover .button-bar { | |
1738 | +#box-organizer .block-outer:focus .button-bar, | |
1739 | +#box-organizer .block-outer:hover .button-bar { | |
1732 | 1740 | display: block; |
1733 | 1741 | } |
1734 | 1742 | |
... | ... | @@ -1834,8 +1842,13 @@ a.button.disabled, input.disabled { |
1834 | 1842 | } |
1835 | 1843 | /* ==> blocks/link-list-block.css <<= */ |
1836 | 1844 | |
1845 | +#edit-link-list-block { | |
1846 | + width: 820px; | |
1847 | +} | |
1848 | + | |
1837 | 1849 | #edit-link-list-block table { |
1838 | - width: 100%; | |
1850 | + width: auto; | |
1851 | + margin-bottom: 10px; | |
1839 | 1852 | } |
1840 | 1853 | #edit-link-list-block table .cel-address { |
1841 | 1854 | width: 220px; | ... | ... |
script/install-dependencies/debian-squeeze.sh
... | ... | @@ -5,7 +5,7 @@ run sudo apt-get -y install $runtime_dependencies |
5 | 5 | sudo apt-get -y install iceweasel || sudo apt-get -y install firefox |
6 | 6 | |
7 | 7 | # needed for development |
8 | -run sudo apt-get -y install libtidy-ruby libhpricot-ruby libnokogiri-ruby libmocha-ruby imagemagick po4a xvfb libxml2-dev libxslt-dev postgresql openjdk-6-jre | |
8 | +run sudo apt-get -y install libtidy-ruby libhpricot-ruby libmocha-ruby imagemagick po4a xvfb libxml2-dev libxslt-dev postgresql openjdk-6-jre | |
9 | 9 | gem which bundler >/dev/null 2>&1 || gem_install bundler |
10 | 10 | setup_rubygems_path |
11 | 11 | run bundle install | ... | ... |
test/functional/profile_themes_controller_test.rb
... | ... | @@ -310,4 +310,23 @@ class ProfileThemesControllerTest < ActionController::TestCase |
310 | 310 | assert_no_tag :content => "Select theme" |
311 | 311 | end |
312 | 312 | |
313 | + should 'not duplicate themes that are included by the user and by the environment' do | |
314 | + t1 = Theme.create('theme1') | |
315 | + t2 = Theme.create('theme2') | |
316 | + Environment.any_instance.stubs('themes').returns([t1,t2]) | |
317 | + Theme.stubs(:approved_themes).returns([t2]) | |
318 | + | |
319 | + get :index, :profile => "testinguser" | |
320 | + assert_equivalent [t1, t2], assigns(:themes) | |
321 | + end | |
322 | + | |
323 | + should 'sort themes by name' do | |
324 | + t1 = Theme.create('bill-theme') | |
325 | + t2 = Theme.create('ana-theme') | |
326 | + Theme.stubs(:approved_themes).returns([t1,t2]) | |
327 | + | |
328 | + get :index, :profile => "testinguser" | |
329 | + assert_equal [t2, t1], assigns(:themes) | |
330 | + end | |
331 | + | |
313 | 332 | end | ... | ... |
test/functional/users_controller_test.rb
... | ... | @@ -107,6 +107,21 @@ class UsersControllerTest < ActionController::TestCase |
107 | 107 | assert_equal false, u.activated? |
108 | 108 | end |
109 | 109 | |
110 | + should 'order users by name' do | |
111 | + create_user('jeremy') | |
112 | + create_user('bill') | |
113 | + create_user('ana') | |
114 | + create_user('creed') | |
115 | + get :index | |
116 | + | |
117 | + assert_order ['ana', 'bill', 'creed', 'jeremy'], assigns(:collection).map(&:name) | |
118 | + end | |
119 | + | |
120 | + should 'set filter to all_users by default' do | |
121 | + get :index | |
122 | + assert_equal 'all_users', assigns(:filter) | |
123 | + end | |
124 | + | |
110 | 125 | should 'response as XML to export users' do |
111 | 126 | get :download, :format => 'xml' |
112 | 127 | assert_equal 'text/xml', @response.content_type | ... | ... |
test/test_helper.rb
... | ... | @@ -178,6 +178,19 @@ class ActiveSupport::TestCase |
178 | 178 | assert !tag, "expected no tag #{options.inspect}, but tag found in #{text.inspect}" |
179 | 179 | end |
180 | 180 | |
181 | + def assert_order(reference, original) | |
182 | + original.each do |value| | |
183 | + if reference.include?(value) | |
184 | + if reference.first == value | |
185 | + reference.shift | |
186 | + else | |
187 | + assert false, "'#{value}' was found before it should be on: #{original.inspect}" | |
188 | + end | |
189 | + end | |
190 | + end | |
191 | + assert reference.blank?, "The following elements are not in the collection: #{reference.inspect}" | |
192 | + end | |
193 | + | |
181 | 194 | # For models that render views (blocks, articles, ...) |
182 | 195 | def render(*args) |
183 | 196 | view_paths = @explicit_view_paths || ActionController::Base.view_paths | ... | ... |
... | ... | @@ -0,0 +1,11 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | + | |
3 | +# tests for Array core extension. See lib/noosfero/core_ext/array.rb | |
4 | +class StringCoreExtTest < ActiveSupport::TestCase | |
5 | + | |
6 | + should 'allow uniq by a block' do | |
7 | + array = [0,1,2,3,4,5,6] | |
8 | + assert_equal [0,1], array.uniq_by {|number| number%2 } | |
9 | + end | |
10 | + | |
11 | +end | ... | ... |
test/unit/box_test.rb
... | ... | @@ -140,4 +140,11 @@ class BoxTest < ActiveSupport::TestCase |
140 | 140 | assert !blocks.include?('box-test_plugin-block') |
141 | 141 | end |
142 | 142 | |
143 | + should 'list only boxes with a postion greater than zero' do | |
144 | + profile = fast_create(Profile) | |
145 | + box = fast_create(Box, :owner_id => profile.id, :owner_type => 'Profile', :position => 0) | |
146 | + box2 = fast_create(Box, :owner_id => profile.id, :owner_type => 'Profile', :position => 1) | |
147 | + assert_equal [box2], profile.boxes.with_position | |
148 | + end | |
149 | + | |
143 | 150 | end | ... | ... |
test/unit/boxes_helper_test.rb
... | ... | @@ -12,7 +12,8 @@ class BoxesHelperTest < ActionView::TestCase |
12 | 12 | |
13 | 13 | should 'include profile-specific header' do |
14 | 14 | holder = mock |
15 | - holder.stubs(:boxes).returns([]) | |
15 | + holder.stubs(:boxes).returns(boxes = []) | |
16 | + boxes.stubs(:with_position).returns([]) | |
16 | 17 | holder.stubs(:boxes_limit).returns(0) |
17 | 18 | holder.stubs(:custom_header_expanded).returns('my custom header') |
18 | 19 | @controller.stubs(:boxes_holder).returns(holder) |
... | ... | @@ -22,7 +23,8 @@ class BoxesHelperTest < ActionView::TestCase |
22 | 23 | |
23 | 24 | should 'include profile-specific footer' do |
24 | 25 | holder = mock |
25 | - holder.stubs(:boxes).returns([]) | |
26 | + holder.stubs(:boxes).returns(boxes = []) | |
27 | + boxes.stubs(:with_position).returns([]) | |
26 | 28 | holder.stubs(:boxes_limit).returns(0) |
27 | 29 | holder.stubs(:custom_footer_expanded).returns('my custom footer') |
28 | 30 | @controller.stubs(:boxes_holder).returns(holder) | ... | ... |
test/unit/comment_test.rb
... | ... | @@ -285,6 +285,37 @@ class CommentTest < ActiveSupport::TestCase |
285 | 285 | assert_equal [c1,c3], c.reload.children |
286 | 286 | end |
287 | 287 | |
288 | + should "return activities comments as a thread" do | |
289 | + person = fast_create(Person) | |
290 | + a = TextileArticle.create!(:profile => person, :name => 'My article', :body => 'Article body') | |
291 | + c0 = Comment.create!(:source => a, :body => 'My comment', :author => person) | |
292 | + c1 = Comment.create!(:reply_of_id => c0.id, :source => a, :body => 'bla', :author => person) | |
293 | + c2 = Comment.create!(:reply_of_id => c1.id, :source => a, :body => 'bla', :author => person) | |
294 | + c3 = Comment.create!(:reply_of_id => c0.id, :source => a, :body => 'bla', :author => person) | |
295 | + c4 = Comment.create!(:source => a, :body => 'My comment', :author => person) | |
296 | + result = a.activity.comments | |
297 | + assert_equal c0, result[0] | |
298 | + assert_equal [c1, c3], result[0].replies | |
299 | + assert_equal [c2], result[0].replies[0].replies | |
300 | + assert_equal c4, result[1] | |
301 | + assert result[1].replies.empty? | |
302 | + end | |
303 | + | |
304 | + should "return activities comments when some comment on thread is spam and not display its replies" do | |
305 | + person = fast_create(Person) | |
306 | + a = TextileArticle.create!(:profile => person, :name => 'My article', :body => 'Article body') | |
307 | + c0 = Comment.create(:source => a, :body => 'Root comment', :author => person) | |
308 | + c1 = Comment.create(:reply_of_id => c0.id, :source => a, :body => 'c1', :author => person) | |
309 | + c2 = Comment.create(:source => a, :body => 'c2', :author => person) | |
310 | + spam = Comment.create(:spam => true, :reply_of_id => c2.id, :source => a, :body => 'spam', :author => person) | |
311 | + spam_reply = Comment.create(:reply_of_id => spam.id, :source => a, :body => 'spam reply', :author => person) | |
312 | + result = a.activity.comments | |
313 | + assert_equal c0, result[0] | |
314 | + assert_equal [c1], result[0].replies.without_spam | |
315 | + assert_equal c2, result[1] | |
316 | + assert_equal [], result[1].replies.without_spam | |
317 | + end | |
318 | + | |
288 | 319 | should 'provide author url for authenticated user' do |
289 | 320 | author = Person.new |
290 | 321 | author.expects(:url).returns('http://blabla.net/author') |
... | ... | @@ -389,6 +420,7 @@ class CommentTest < ActiveSupport::TestCase |
389 | 420 | end |
390 | 421 | |
391 | 422 | should 'be able to select non-spam comments' do |
423 | + Comment.destroy_all | |
392 | 424 | c1 = fast_create(Comment) |
393 | 425 | c2 = fast_create(Comment, :spam => false) |
394 | 426 | c3 = fast_create(Comment, :spam => true) |
... | ... | @@ -660,6 +692,7 @@ class CommentTest < ActiveSupport::TestCase |
660 | 692 | end |
661 | 693 | |
662 | 694 | should 'be able to select non-reply comments' do |
695 | + Comment.destroy_all | |
663 | 696 | c1 = fast_create(Comment) |
664 | 697 | c2 = fast_create(Comment, :reply_of_id => c1.id) |
665 | 698 | c3 = fast_create(Comment, :reply_of_id => c2.id) | ... | ... |
test/unit/environment_test.rb
... | ... | @@ -783,6 +783,18 @@ class EnvironmentTest < ActiveSupport::TestCase |
783 | 783 | assert role2.valid? |
784 | 784 | end |
785 | 785 | |
786 | + should 'destroy roles when its environment is destroyed' do | |
787 | + e1 = fast_create(Environment) | |
788 | + role1 = Role.create!(:name => 'test_role', :environment => e1, :key => 'a_member') | |
789 | + e2 = fast_create(Environment) | |
790 | + role2 = Role.create!(:name => 'test_role', :environment => e2, :key => 'a_member') | |
791 | + | |
792 | + e2.destroy | |
793 | + | |
794 | + assert_nothing_raised {Role.find(role1.id)} | |
795 | + assert_raise(ActiveRecord::RecordNotFound) {Role.find(role2.id)} | |
796 | + end | |
797 | + | |
786 | 798 | should 'have a help_message_to_add_enterprise attribute' do |
787 | 799 | env = Environment.new |
788 | 800 | ... | ... |
test/unit/link_list_block_test.rb
... | ... | @@ -88,4 +88,9 @@ class LinkListBlockTest < ActiveSupport::TestCase |
88 | 88 | assert_equivalent LinkListBlock::TARGET_OPTIONS.map {|t|t[1]}, ['_self', '_blank', '_new'] |
89 | 89 | end |
90 | 90 | |
91 | + should 'link with title' do | |
92 | + l = LinkListBlock.new | |
93 | + assert_match /title="mytitle"/, l.link_html({:name => 'mylink', :address => '/myaddress', :title => 'mytitle'}) | |
94 | + end | |
95 | + | |
91 | 96 | end | ... | ... |
test/unit/macro_test.rb
... | ... | @@ -15,7 +15,7 @@ class MacroTest < ActiveSupport::TestCase |
15 | 15 | |
16 | 16 | def setup |
17 | 17 | @macro = Plugin1::Macro.new |
18 | - @macro_element = Nokogiri::HTML(MACRO).css('.macro').first | |
18 | + @macro_element = Hpricot(MACRO).search('.macro').first | |
19 | 19 | end |
20 | 20 | |
21 | 21 | attr_reader :macro, :macro_element | ... | ... |
test/unit/profile_test.rb
... | ... | @@ -1462,7 +1462,7 @@ class ProfileTest < ActiveSupport::TestCase |
1462 | 1462 | should 'list events by month' do |
1463 | 1463 | profile = fast_create(Profile) |
1464 | 1464 | |
1465 | - today = Date.today | |
1465 | + today = Date.new(2014, 03, 2) | |
1466 | 1466 | yesterday_event = Event.new(:name => 'Joao Birthday', :start_date => today - 1.day) |
1467 | 1467 | today_event = Event.new(:name => 'Ze Birthday', :start_date => today) |
1468 | 1468 | tomorrow_event = Event.new(:name => 'Mane Birthday', :start_date => today + 1.day) |
... | ... | @@ -1693,6 +1693,28 @@ class ProfileTest < ActiveSupport::TestCase |
1693 | 1693 | assert_equal 1, community.members_count |
1694 | 1694 | end |
1695 | 1695 | |
1696 | + should 'order members by name alphabetically considering special characters' do | |
1697 | + community = fast_create(Community) | |
1698 | + | |
1699 | + community.add_member(create_user('José').person) | |
1700 | + community.add_member(create_user('João').person) | |
1701 | + community.add_member(create_user('Mariana').person) | |
1702 | + members = community.members_by_name | |
1703 | + | |
1704 | + assert_equal ["João", "José", "Mariana"], members.map(&:name) | |
1705 | + end | |
1706 | + | |
1707 | + should 'order members by name alphabetically considering upper and lower cases' do | |
1708 | + community = fast_create(Community) | |
1709 | + | |
1710 | + community.add_member(create_user('mariana').person) | |
1711 | + community.add_member(create_user('João').person) | |
1712 | + community.add_member(create_user('guest').person) | |
1713 | + members = community.members_by_name | |
1714 | + | |
1715 | + assert_equal ["guest", "João", "mariana"], members.map(&:name) | |
1716 | + end | |
1717 | + | |
1696 | 1718 | should 'know if url is the profile homepage' do |
1697 | 1719 | profile = fast_create(Profile) |
1698 | 1720 | ... | ... |
vendor/plugins/action_tracker_has_comments/init.rb
... | ... | @@ -11,5 +11,6 @@ Rails.configuration.to_prepare do |
11 | 11 | type, id = (self.target_type == 'Article' ? ['Article', self.target_id] : [self.class.to_s, self.id]) |
12 | 12 | "source_type = '#{type}' AND source_id = '#{id}' AND spam IS NOT TRUE AND reply_of_id IS NULL" |
13 | 13 | end |
14 | + | |
14 | 15 | end |
15 | 16 | end | ... | ... |