From 7bc0a2a47ef46bb986e48f5afc321cdcae81fb3c Mon Sep 17 00:00:00 2001 From: Daniel Bucher Date: Tue, 8 Oct 2013 00:05:43 +0400 Subject: [PATCH] sub_organizations_plugin: Add related organizations block --- app/models/person.rb | 7 ++++++- features/step_definitions/sub_organizations_block_steps.rb | 6 ++++++ features/support/paths.rb | 7 +++++++ lib/noosfero/plugin.rb | 7 +++++++ plugins/sub_organizations/controllers/sub_organizations_plugin_profile_controller.rb | 25 +++++++++++++++++++++++++ plugins/sub_organizations/features/sub_organizations_block.feature | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ plugins/sub_organizations/lib/related_organizations_block.rb | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ plugins/sub_organizations/lib/sub_organizations_plugin.rb | 12 ++++++++++++ plugins/sub_organizations/lib/sub_organizations_plugin/relation.rb | 4 ++-- plugins/sub_organizations/public/images/arrow-right-p.png | 1 + plugins/sub_organizations/public/style.css | 16 ++++++++++++++++ plugins/sub_organizations/test/functional/sub_organizations_plugin_profile_controller_test.rb | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ plugins/sub_organizations/test/unit/related_organizations_block_test.rb | 30 ++++++++++++++++++++++++++++++ plugins/sub_organizations/test/unit/sub_organizations_plugin_test.rb | 29 +++++++++++++++++++++++++++++ plugins/sub_organizations/views/box_organizer/_related_organizations_block.rhtml | 7 +++++++ plugins/sub_organizations/views/profile_design | 1 + plugins/sub_organizations/views/sub_organizations_plugin_profile/_related_organizations.rhtml | 16 ++++++++++++++++ plugins/sub_organizations/views/sub_organizations_plugin_profile/related_organizations.rhtml | 7 +++++++ test/unit/person_test.rb | 33 +++++++++++++++++++++++++++++++++ 19 files changed, 386 insertions(+), 3 deletions(-) create mode 100644 features/step_definitions/sub_organizations_block_steps.rb create mode 100644 plugins/sub_organizations/controllers/sub_organizations_plugin_profile_controller.rb create mode 100644 plugins/sub_organizations/features/sub_organizations_block.feature create mode 100644 plugins/sub_organizations/lib/related_organizations_block.rb create mode 120000 plugins/sub_organizations/public/images/arrow-right-p.png create mode 100644 plugins/sub_organizations/test/functional/sub_organizations_plugin_profile_controller_test.rb create mode 100644 plugins/sub_organizations/test/unit/related_organizations_block_test.rb create mode 100644 plugins/sub_organizations/views/box_organizer/_related_organizations_block.rhtml create mode 120000 plugins/sub_organizations/views/profile_design create mode 100644 plugins/sub_organizations/views/sub_organizations_plugin_profile/_related_organizations.rhtml create mode 100644 plugins/sub_organizations/views/sub_organizations_plugin_profile/related_organizations.rhtml diff --git a/app/models/person.rb b/app/models/person.rb index d6cb455..26f717d 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -43,7 +43,12 @@ class Person < Profile alias_method_chain :has_permission?, :plugins def memberships - Profile.memberships_of(self) + scopes = [] + plugins_scopes = plugins.dispatch_scopes(:person_memberships, self) + scopes = plugins_scopes unless plugins_scopes.first.blank? + scopes << Profile.memberships_of(self) + return scopes.first if scopes.size == 1 + ScopeTool.union *scopes end def memberships_by_role(role) diff --git a/features/step_definitions/sub_organizations_block_steps.rb b/features/step_definitions/sub_organizations_block_steps.rb new file mode 100644 index 0000000..2ebcf54 --- /dev/null +++ b/features/step_definitions/sub_organizations_block_steps.rb @@ -0,0 +1,6 @@ +Given /^"([^\"]*)" is a sub organization of "([^\"]*)"$/ do |child, parent| + child = Organization.find_by_name(child) || Organization[child] + parent = Organization.find_by_name(parent) || Organization[parent] + + SubOrganizationsPlugin::Relation.add_children(parent, child) +end diff --git a/features/support/paths.rb b/features/support/paths.rb index 34bc165..b11c075 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -114,6 +114,13 @@ module NavigationHelpers when /^(.+)'s members page/ '/profile/%s/members' % profile_identifier($1) + when /^(.+)'s "(.+)" page from "(.*)" of "(.*)" plugin/ + profile = $1 + action = $2 + plugin_name = $4.underscore + controller_type = $3.constantize.superclass.to_s.underscore.gsub(/_controller/, "") + "/#{controller_type}/#{profile}/plugin/#{plugin_name}/#{action}" + else begin page_name =~ /the (.*) page/ diff --git a/lib/noosfero/plugin.rb b/lib/noosfero/plugin.rb index e923e1f..ef9062f 100644 --- a/lib/noosfero/plugin.rb +++ b/lib/noosfero/plugin.rb @@ -372,6 +372,13 @@ class Noosfero::Plugin nil end + # -> Extends person memberships list + # returns = An instance of ActiveRecord::NamedScope::Scope retrived through + # Person.memberships_of method. + def person_memberships(person) + nil + end + # -> Extends person permission access # returns = boolean def has_permission?(person, permission, target) diff --git a/plugins/sub_organizations/controllers/sub_organizations_plugin_profile_controller.rb b/plugins/sub_organizations/controllers/sub_organizations_plugin_profile_controller.rb new file mode 100644 index 0000000..97ded24 --- /dev/null +++ b/plugins/sub_organizations/controllers/sub_organizations_plugin_profile_controller.rb @@ -0,0 +1,25 @@ +class SubOrganizationsPluginProfileController < ProfileController + append_view_path File.join(File.dirname(__FILE__) + '/../views') + + before_filter :organizations_only + + def children + @organizations = SubOrganizationsPlugin::Relation.children(profile) + + render 'related_organizations' + end + + def parents + @organizations = SubOrganizationsPlugin::Relation.parents(profile) + + render 'related_organizations' + end + + + private + + def organizations_only + render_not_found if !profile.organization? + end + +end diff --git a/plugins/sub_organizations/features/sub_organizations_block.feature b/plugins/sub_organizations/features/sub_organizations_block.feature new file mode 100644 index 0000000..32938eb --- /dev/null +++ b/plugins/sub_organizations/features/sub_organizations_block.feature @@ -0,0 +1,62 @@ +Feature: related_organizations_block + As a user + I want my organizations to have blocks that lists it's related-organizations + In order to have quick access to it's related-organizations + + Background: + Given "SubOrganizations" plugin is enabled + And the following users + | login | name | + | homer | Homer | + And the following community + | identifier | name | owner | + | springfield | Springfield | homer | + | moe | Moe's | homer | + And the following enterprise + | identifier | name | owner | + | duff | Duff | homer | + And "moe" is a sub organization of "springfield" + And "duff" is a sub organization of "springfield" + And I am logged in as "homer" + And I go to springfield's control panel + + Scenario: display sub organizations block add option + When I follow "Edit sideboxes" + And I follow "Add a block" + Then I should see "Related Organizations" + + Scenario: display both sub types on block + When I follow "Edit sideboxes" + And I follow "Add a block" + And I choose "Related Organizations" + And I press "Add" + Then I should see "Moe's" within ".related-organizations-block" + And I should see "Duff" within ".related-organizations-block" + + Scenario: display only sub-communities + Given the following blocks + | owner | type | + | springfield | RelatedOrganizationsBlock | + When I follow "Edit sideboxes" + And I follow "Edit" within ".related-organizations-block" + And I select "Community" from "block_organization_type" + And I press "Save" + Then I should see "Moe's" within ".related-organizations-block" + And I should not see "Duff" within ".related-organizations-block" + + Scenario: display both sub types on sub-organizations page + When I go to springfield's "children" page from "SubOrganizationsPluginProfileController" of "SubOrganizations" plugin + Then I should see "Moe's" + And I should see "Duff" + + Scenario: display only sub-communities on sub-organizations page + Given the following blocks + | owner | type | + | springfield | RelatedOrganizationsBlock | + When I follow "Edit sideboxes" + And I follow "Edit" within ".related-organizations-block" + And I select "Community" from "block_organization_type" + And I press "Save" + And I follow "View all" within ".related-organizations-block" + Then I should see "Moe's" within ".profile-list" + And I should not see "Duff" within ".profile-list" diff --git a/plugins/sub_organizations/lib/related_organizations_block.rb b/plugins/sub_organizations/lib/related_organizations_block.rb new file mode 100644 index 0000000..6f2123b --- /dev/null +++ b/plugins/sub_organizations/lib/related_organizations_block.rb @@ -0,0 +1,60 @@ +class RelatedOrganizationsBlock < ProfileListBlock + + settings_items :organization_type, :type => :string, :default => 'both' + + @display_type = {:title => 'related', :action => 'children' } + + def self.description + __("#{@display_type[:title].capitalize} Organizations") + end + + def default_title + case organization_type + when 'enterprise' + n__("{#} #{@display_type[:title]} enterprise", "{#} #{@display_type[:title]} enterprises", profile_count) + when 'community' + n__("{#} #{@display_type[:title]} community", "{#} #{@display_type[:title]} communities", profile_count) + else + n__("{#} #{@display_type[:title]} organization", "{#} #{@display_type[:title]} organizations", profile_count) + end + end + + def help + _("This block displays #{@display_type[:title]} organizations of this organization") + end + + def profiles + organizations = related_organizations + case organization_type + when 'enterprise' + organizations.enterprises + when 'community' + organizations.communities + else + organizations + end + end + + def footer + profile = self.owner + type = self.organization_type + params = {:profile => profile.identifier, :controller => 'sub_organizations_plugin_profile', :action => @display_type[:action]} + params[:type] = type if type == 'enterprise' || type == 'community' + lambda do + link_to _('View all'), params.merge(params) + end + end + + def related_organizations + profile = self.owner + organizations = SubOrganizationsPlugin::Relation.parents(profile) + + if organizations.blank? + @display_type = {:title => 'sub', :action => 'children'} + organizations = SubOrganizationsPlugin::Relation.children(profile) + else + @display_type = {:title => 'parent', :action => 'parents' } + organizations + end + end +end diff --git a/plugins/sub_organizations/lib/sub_organizations_plugin.rb b/plugins/sub_organizations/lib/sub_organizations_plugin.rb index e0e5a24..496ac15 100644 --- a/plugins/sub_organizations/lib/sub_organizations_plugin.rb +++ b/plugins/sub_organizations/lib/sub_organizations_plugin.rb @@ -1,3 +1,5 @@ +require_dependency File.dirname(__FILE__) + '/related_organizations_block' + class SubOrganizationsPlugin < Noosfero::Plugin def self.plugin_name @@ -23,6 +25,10 @@ class SubOrganizationsPlugin < Noosfero::Plugin Person.members_of(children) if children.present? end + def person_memberships(person) + SubOrganizationsPlugin::Relation.parents(*Profile.memberships_of(person)) + end + def has_permission?(person, permission, target) if !target.kind_of?(Environment) && target.organization? SubOrganizationsPlugin::Relation.parents(target).map do |parent| @@ -40,4 +46,10 @@ class SubOrganizationsPlugin < Noosfero::Plugin parent_to_be = context.params[:sub_organizations_plugin_parent_to_be] {'sub_organizations_plugin_parent_to_be' => parent_to_be} if parent_to_be.present? end + + def self.extra_blocks + { + RelatedOrganizationsBlock => {:type => [Enterprise, Community], :position => ['1', '2', '3']} + } + end end diff --git a/plugins/sub_organizations/lib/sub_organizations_plugin/relation.rb b/plugins/sub_organizations/lib/sub_organizations_plugin/relation.rb index b173108..08e00ed 100644 --- a/plugins/sub_organizations/lib/sub_organizations_plugin/relation.rb +++ b/plugins/sub_organizations/lib/sub_organizations_plugin/relation.rb @@ -33,11 +33,11 @@ class SubOrganizationsPlugin::Relation < Noosfero::Plugin::ActiveRecord ActiveRecord::NamedScope::Scope.new(Organization, options) end - def parents(child) + def parents(*children) options = { :select => "profiles.*", :joins => "inner join sub_organizations_plugin_relations as relations on profiles.id=relations.parent_id", - :conditions => ["relations.child_id = ?", child.id] + :conditions => ["relations.child_id in (?)", children.map(&:id)] } ActiveRecord::NamedScope::Scope.new(Organization, options) end diff --git a/plugins/sub_organizations/public/images/arrow-right-p.png b/plugins/sub_organizations/public/images/arrow-right-p.png new file mode 120000 index 0000000..cf96cd5 --- /dev/null +++ b/plugins/sub_organizations/public/images/arrow-right-p.png @@ -0,0 +1 @@ +../../../../public/designs/themes/base/imgs/arrow-right-p.png \ No newline at end of file diff --git a/plugins/sub_organizations/public/style.css b/plugins/sub_organizations/public/style.css index 2a2444d..ff13e0e 100644 --- a/plugins/sub_organizations/public/style.css +++ b/plugins/sub_organizations/public/style.css @@ -1,3 +1,19 @@ #content .token-input-list { margin-bottom: 30px; } + +.related-organizations-button-bar { + padding-top: 40px; + clear: both; +} + +.related-organizations-block .block-footer-content a { + position: absolute; + top: 2px; + right: 0px; + font-size: 11px; + color: #000; + text-decoration: none; + padding-right: 15px; + background: url(images/arrow-right-p.png) 100% 50% no-repeat; +} diff --git a/plugins/sub_organizations/test/functional/sub_organizations_plugin_profile_controller_test.rb b/plugins/sub_organizations/test/functional/sub_organizations_plugin_profile_controller_test.rb new file mode 100644 index 0000000..eb0e3c8 --- /dev/null +++ b/plugins/sub_organizations/test/functional/sub_organizations_plugin_profile_controller_test.rb @@ -0,0 +1,59 @@ +require File.dirname(__FILE__) + '/../../../../test/test_helper' +require File.dirname(__FILE__) + '/../../controllers/sub_organizations_plugin_profile_controller' + +# Re-raise errors caught by the controller. +class SubOrganizationsPluginProfileController; def rescue_action(e) raise e end; end + +class SubOrganizationsPluginProfileControllerTest < ActionController::TestCase + + def setup + @controller = SubOrganizationsPluginProfileController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + @organization = Organization.create!(:name => 'My Organization', :identifier => 'my-organization') + @person = create_user('person').person + @organization.add_admin(@person) + login_as(@person.user.login) + e = Environment.default + e.enable_plugin('SubOrganizationsPlugin') + e.save! + @o1 = fast_create(Organization, :name => 'sample child organization 1') + @o2 = fast_create(Community, :name => 'sample child community 1') + @o3 = fast_create(Enterprise, :name => 'sample child enterprise 1') + + SubOrganizationsPlugin::Relation.add_children(@organization, @o2, @o3) + end + + attr_accessor :person, :organization + + should 'display all children organizations' do + get :children, :profile => @organization.identifier + + assert_no_match /#{@o1.name}/, @response.body + assert_match /#{@o2.name}/, @response.body + assert_match /#{@o3.name}/, @response.body + end + + should 'display only communities' do + get :children, :profile => @organization.identifier, :type => 'community' + + assert_no_match /#{@o1.name}/, @response.body + assert_match /#{@o2.name}/, @response.body + assert_no_match /#{@o3.name}/, @response.body + end + + should 'display only enterprises' do + get :children, :profile => @organization.identifier, :type => 'enterprise' + + assert_no_match /#{@o1.name}/, @response.body + assert_no_match /#{@o2.name}/, @response.body + assert_match /#{@o3.name}/, @response.body + end + + should 'not respond to person profiles' do + get :children, :profile => fast_create(Person, :name => 'Ze').identifier + + assert_response :missing + end + +end diff --git a/plugins/sub_organizations/test/unit/related_organizations_block_test.rb b/plugins/sub_organizations/test/unit/related_organizations_block_test.rb new file mode 100644 index 0000000..b333a72 --- /dev/null +++ b/plugins/sub_organizations/test/unit/related_organizations_block_test.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../../../test/test_helper' +require File.dirname(__FILE__) + '/../../lib/related_organizations_block' + +class RelatedOrganizationsBlockTest < ActiveSupport::TestCase + + def setup + @block = RelatedOrganizationsBlock.new + end + + attr_reader :block + + should 'have both as default organization_type' do + assert_equal "both", block.organization_type + end + + should 'return only children when the organization is a parent' do + parent = fast_create(Organization, :name => 'I am your father', :identifier => 'i-am-your-father') + child1 = fast_create(Organization, :name => 'Rebel Alliance') + child2 = fast_create(Organization, :name => 'The Empire') + org1 = fast_create(Organization, :name => 'Jedi Council') + box = fast_create(Box, :owner_id => parent.id, :owner_type => 'Organization') + @block.box = box + @block.save! + SubOrganizationsPlugin::Relation.add_children(parent, child1, child2) + + assert @block.related_organizations.include?(child1) + assert @block.related_organizations.include?(child2) + assert !@block.related_organizations.include?(org1) + end +end diff --git a/plugins/sub_organizations/test/unit/sub_organizations_plugin_test.rb b/plugins/sub_organizations/test/unit/sub_organizations_plugin_test.rb index 2d3b3c5..a1b45ff 100644 --- a/plugins/sub_organizations/test/unit/sub_organizations_plugin_test.rb +++ b/plugins/sub_organizations/test/unit/sub_organizations_plugin_test.rb @@ -45,6 +45,35 @@ class SubOrganizationsTest < ActiveSupport::TestCase assert org3_members.blank? end + should 'include parent-organizations in persons memberships' do + org1 = fast_create(Organization) + org2 = fast_create(Organization) + org3 = fast_create(Organization) + person1 = fast_create(Person) + person2 = fast_create(Person) + org1.add_member(person2) + org2.add_member(person1) + SubOrganizationsPlugin::Relation.create!(:parent => org1, :child => org2) + SubOrganizationsPlugin::Relation.create!(:parent => org1, :child => org3) + + person1_memberships = plugin.person_memberships(person1) + person2_memberships = plugin.person_memberships(person2) + + assert_equal ActiveRecord::NamedScope::Scope, person1_memberships.class + assert_includes person1_memberships, org1 + assert_not_includes person1_memberships, org2 + assert_not_includes person1_memberships, org3 + assert person2_memberships.blank? + end + + should 'return blank for person memberships with no organization ' do + person1 = fast_create(Person) + + person1_memberships = plugin.person_memberships(person1) + + assert person1_memberships.blank? + end + should 'grant permission that user has on parent organizations over children orgnaizations' do person = create_user('admin-user').person org1 = fast_create(Organization) diff --git a/plugins/sub_organizations/views/box_organizer/_related_organizations_block.rhtml b/plugins/sub_organizations/views/box_organizer/_related_organizations_block.rhtml new file mode 100644 index 0000000..2f68f5b --- /dev/null +++ b/plugins/sub_organizations/views/box_organizer/_related_organizations_block.rhtml @@ -0,0 +1,7 @@ + diff --git a/plugins/sub_organizations/views/profile_design b/plugins/sub_organizations/views/profile_design new file mode 120000 index 0000000..1b8d625 --- /dev/null +++ b/plugins/sub_organizations/views/profile_design @@ -0,0 +1 @@ +box_organizer/ \ No newline at end of file diff --git a/plugins/sub_organizations/views/sub_organizations_plugin_profile/_related_organizations.rhtml b/plugins/sub_organizations/views/sub_organizations_plugin_profile/_related_organizations.rhtml new file mode 100644 index 0000000..c706ff8 --- /dev/null +++ b/plugins/sub_organizations/views/sub_organizations_plugin_profile/_related_organizations.rhtml @@ -0,0 +1,16 @@ +
+ +

<%= __("#{profile.name}'s sub-#{organization_type.pluralize}") %>

+ + + +<% button_bar(:class => "related-organizations-button-bar") do %> + <%= button :back, _('Go back'), { :controller => 'profile' } %> + <%= button :add, __("Add a new #{organization_type}"), :controller => 'sub_organizations_plugin_myprofile', :action => 'index' if logged_in? && user.has_permission?(:edit_profile, profile) && !environment.enabled?("disable_asset_#{organization_type.pluralize}") %> +<% end %> + +
diff --git a/plugins/sub_organizations/views/sub_organizations_plugin_profile/related_organizations.rhtml b/plugins/sub_organizations/views/sub_organizations_plugin_profile/related_organizations.rhtml new file mode 100644 index 0000000..ac613c3 --- /dev/null +++ b/plugins/sub_organizations/views/sub_organizations_plugin_profile/related_organizations.rhtml @@ -0,0 +1,7 @@ +<% if params[:type] != 'enterprise' %> + <%= render :partial => 'sub_organizations_plugin_profile/related_organizations', :locals => {:organizations => @organizations.communities, :organization_type => 'community'} %> +<% end %> + +<% if params[:type] != 'community' %> + <%= render :partial => 'sub_organizations_plugin_profile/related_organizations', :locals => {:organizations => @organizations.enterprises, :organization_type => 'enterprise'} %> +<% end %> diff --git a/test/unit/person_test.rb b/test/unit/person_test.rb index 49f2826..f8190c0 100644 --- a/test/unit/person_test.rb +++ b/test/unit/person_test.rb @@ -1413,4 +1413,37 @@ class PersonTest < ActiveSupport::TestCase person.reload assert_equal person.activities, [] end + + should 'merge memberships of plugins to original memberships' do + class Plugin1 < Noosfero::Plugin + def person_memberships(person) + Profile.memberships_of(Person.find_by_identifier('person1')) + end + end + + class Plugin2 < Noosfero::Plugin + def person_memberships(person) + Profile.memberships_of(Person.find_by_identifier('person2')) + end + end + + Environment.default.enable_plugin(Plugin1) + Environment.default.enable_plugin(Plugin2) + + original_person = fast_create(Person) + person1 = fast_create(Person, :identifier => 'person1') + person2 = fast_create(Person, :identifier => 'person2') + original_cmm = fast_create(Community) + plugin1_cmm = fast_create(Community) + plugin2_cmm = fast_create(Community) + original_cmm.add_member(original_person) + plugin1_cmm.add_member(person1) + plugin2_cmm.add_member(person2) + + assert_includes original_person.memberships, original_cmm + assert_includes original_person.memberships, plugin1_cmm + assert_includes original_person.memberships, plugin2_cmm + assert 3, original_person.memberships.count + end + end -- libgit2 0.21.2