Commit 7bc0a2a47ef46bb986e48f5afc321cdcae81fb3c

Authored by Daniel
1 parent 609e37e4

sub_organizations_plugin: Add related organizations block

The following improvements have been made:
  - Created action that displays sub-organization and
  super organizations of a given organization.
  - Created a block that display related organizations.
  - List mother organizations to person's membership if
  he/she is member of a sub-organization.

(ActionItem2499)
(ActionItem2825)

Signed-off-by: Arthur Del Esposte <athurmde@yahoo.com.br>
Signed-off-by: Aurélio A. Heckert <aurelio@colivre.coop.br>
Signed-off-by: Daniel Bucher <daniel.bucher88@gmail.com>
Signed-off-by: Gabriela Navarro <navarro1703@gmail.com>
Signed-off-by: Marcos Ramos <ms.ramos@outlook.com>
app/models/person.rb
... ... @@ -43,7 +43,12 @@ class Person &lt; Profile
43 43 alias_method_chain :has_permission?, :plugins
44 44  
45 45 def memberships
46   - Profile.memberships_of(self)
  46 + scopes = []
  47 + plugins_scopes = plugins.dispatch_scopes(:person_memberships, self)
  48 + scopes = plugins_scopes unless plugins_scopes.first.blank?
  49 + scopes << Profile.memberships_of(self)
  50 + return scopes.first if scopes.size == 1
  51 + ScopeTool.union *scopes
47 52 end
48 53  
49 54 def memberships_by_role(role)
... ...
features/step_definitions/sub_organizations_block_steps.rb 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +Given /^"([^\"]*)" is a sub organization of "([^\"]*)"$/ do |child, parent|
  2 + child = Organization.find_by_name(child) || Organization[child]
  3 + parent = Organization.find_by_name(parent) || Organization[parent]
  4 +
  5 + SubOrganizationsPlugin::Relation.add_children(parent, child)
  6 +end
... ...
features/support/paths.rb
... ... @@ -114,6 +114,13 @@ module NavigationHelpers
114 114 when /^(.+)'s members page/
115 115 '/profile/%s/members' % profile_identifier($1)
116 116  
  117 + when /^(.+)'s "(.+)" page from "(.*)" of "(.*)" plugin/
  118 + profile = $1
  119 + action = $2
  120 + plugin_name = $4.underscore
  121 + controller_type = $3.constantize.superclass.to_s.underscore.gsub(/_controller/, "")
  122 + "/#{controller_type}/#{profile}/plugin/#{plugin_name}/#{action}"
  123 +
117 124 else
118 125 begin
119 126 page_name =~ /the (.*) page/
... ...
lib/noosfero/plugin.rb
... ... @@ -372,6 +372,13 @@ class Noosfero::Plugin
372 372 nil
373 373 end
374 374  
  375 + # -> Extends person memberships list
  376 + # returns = An instance of ActiveRecord::NamedScope::Scope retrived through
  377 + # Person.memberships_of method.
  378 + def person_memberships(person)
  379 + nil
  380 + end
  381 +
375 382 # -> Extends person permission access
376 383 # returns = boolean
377 384 def has_permission?(person, permission, target)
... ...
plugins/sub_organizations/controllers/sub_organizations_plugin_profile_controller.rb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +class SubOrganizationsPluginProfileController < ProfileController
  2 + append_view_path File.join(File.dirname(__FILE__) + '/../views')
  3 +
  4 + before_filter :organizations_only
  5 +
  6 + def children
  7 + @organizations = SubOrganizationsPlugin::Relation.children(profile)
  8 +
  9 + render 'related_organizations'
  10 + end
  11 +
  12 + def parents
  13 + @organizations = SubOrganizationsPlugin::Relation.parents(profile)
  14 +
  15 + render 'related_organizations'
  16 + end
  17 +
  18 +
  19 + private
  20 +
  21 + def organizations_only
  22 + render_not_found if !profile.organization?
  23 + end
  24 +
  25 +end
... ...
plugins/sub_organizations/features/sub_organizations_block.feature 0 → 100644
... ... @@ -0,0 +1,62 @@
  1 +Feature: related_organizations_block
  2 + As a user
  3 + I want my organizations to have blocks that lists it's related-organizations
  4 + In order to have quick access to it's related-organizations
  5 +
  6 + Background:
  7 + Given "SubOrganizations" plugin is enabled
  8 + And the following users
  9 + | login | name |
  10 + | homer | Homer |
  11 + And the following community
  12 + | identifier | name | owner |
  13 + | springfield | Springfield | homer |
  14 + | moe | Moe's | homer |
  15 + And the following enterprise
  16 + | identifier | name | owner |
  17 + | duff | Duff | homer |
  18 + And "moe" is a sub organization of "springfield"
  19 + And "duff" is a sub organization of "springfield"
  20 + And I am logged in as "homer"
  21 + And I go to springfield's control panel
  22 +
  23 + Scenario: display sub organizations block add option
  24 + When I follow "Edit sideboxes"
  25 + And I follow "Add a block"
  26 + Then I should see "Related Organizations"
  27 +
  28 + Scenario: display both sub types on block
  29 + When I follow "Edit sideboxes"
  30 + And I follow "Add a block"
  31 + And I choose "Related Organizations"
  32 + And I press "Add"
  33 + Then I should see "Moe's" within ".related-organizations-block"
  34 + And I should see "Duff" within ".related-organizations-block"
  35 +
  36 + Scenario: display only sub-communities
  37 + Given the following blocks
  38 + | owner | type |
  39 + | springfield | RelatedOrganizationsBlock |
  40 + When I follow "Edit sideboxes"
  41 + And I follow "Edit" within ".related-organizations-block"
  42 + And I select "Community" from "block_organization_type"
  43 + And I press "Save"
  44 + Then I should see "Moe's" within ".related-organizations-block"
  45 + And I should not see "Duff" within ".related-organizations-block"
  46 +
  47 + Scenario: display both sub types on sub-organizations page
  48 + When I go to springfield's "children" page from "SubOrganizationsPluginProfileController" of "SubOrganizations" plugin
  49 + Then I should see "Moe's"
  50 + And I should see "Duff"
  51 +
  52 + Scenario: display only sub-communities on sub-organizations page
  53 + Given the following blocks
  54 + | owner | type |
  55 + | springfield | RelatedOrganizationsBlock |
  56 + When I follow "Edit sideboxes"
  57 + And I follow "Edit" within ".related-organizations-block"
  58 + And I select "Community" from "block_organization_type"
  59 + And I press "Save"
  60 + And I follow "View all" within ".related-organizations-block"
  61 + Then I should see "Moe's" within ".profile-list"
  62 + And I should not see "Duff" within ".profile-list"
... ...
plugins/sub_organizations/lib/related_organizations_block.rb 0 → 100644
... ... @@ -0,0 +1,60 @@
  1 +class RelatedOrganizationsBlock < ProfileListBlock
  2 +
  3 + settings_items :organization_type, :type => :string, :default => 'both'
  4 +
  5 + @display_type = {:title => 'related', :action => 'children' }
  6 +
  7 + def self.description
  8 + __("#{@display_type[:title].capitalize} Organizations")
  9 + end
  10 +
  11 + def default_title
  12 + case organization_type
  13 + when 'enterprise'
  14 + n__("{#} #{@display_type[:title]} enterprise", "{#} #{@display_type[:title]} enterprises", profile_count)
  15 + when 'community'
  16 + n__("{#} #{@display_type[:title]} community", "{#} #{@display_type[:title]} communities", profile_count)
  17 + else
  18 + n__("{#} #{@display_type[:title]} organization", "{#} #{@display_type[:title]} organizations", profile_count)
  19 + end
  20 + end
  21 +
  22 + def help
  23 + _("This block displays #{@display_type[:title]} organizations of this organization")
  24 + end
  25 +
  26 + def profiles
  27 + organizations = related_organizations
  28 + case organization_type
  29 + when 'enterprise'
  30 + organizations.enterprises
  31 + when 'community'
  32 + organizations.communities
  33 + else
  34 + organizations
  35 + end
  36 + end
  37 +
  38 + def footer
  39 + profile = self.owner
  40 + type = self.organization_type
  41 + params = {:profile => profile.identifier, :controller => 'sub_organizations_plugin_profile', :action => @display_type[:action]}
  42 + params[:type] = type if type == 'enterprise' || type == 'community'
  43 + lambda do
  44 + link_to _('View all'), params.merge(params)
  45 + end
  46 + end
  47 +
  48 + def related_organizations
  49 + profile = self.owner
  50 + organizations = SubOrganizationsPlugin::Relation.parents(profile)
  51 +
  52 + if organizations.blank?
  53 + @display_type = {:title => 'sub', :action => 'children'}
  54 + organizations = SubOrganizationsPlugin::Relation.children(profile)
  55 + else
  56 + @display_type = {:title => 'parent', :action => 'parents' }
  57 + organizations
  58 + end
  59 + end
  60 +end
... ...
plugins/sub_organizations/lib/sub_organizations_plugin.rb
  1 +require_dependency File.dirname(__FILE__) + '/related_organizations_block'
  2 +
1 3 class SubOrganizationsPlugin < Noosfero::Plugin
2 4  
3 5 def self.plugin_name
... ... @@ -23,6 +25,10 @@ class SubOrganizationsPlugin &lt; Noosfero::Plugin
23 25 Person.members_of(children) if children.present?
24 26 end
25 27  
  28 + def person_memberships(person)
  29 + SubOrganizationsPlugin::Relation.parents(*Profile.memberships_of(person))
  30 + end
  31 +
26 32 def has_permission?(person, permission, target)
27 33 if !target.kind_of?(Environment) && target.organization?
28 34 SubOrganizationsPlugin::Relation.parents(target).map do |parent|
... ... @@ -40,4 +46,10 @@ class SubOrganizationsPlugin &lt; Noosfero::Plugin
40 46 parent_to_be = context.params[:sub_organizations_plugin_parent_to_be]
41 47 {'sub_organizations_plugin_parent_to_be' => parent_to_be} if parent_to_be.present?
42 48 end
  49 +
  50 + def self.extra_blocks
  51 + {
  52 + RelatedOrganizationsBlock => {:type => [Enterprise, Community], :position => ['1', '2', '3']}
  53 + }
  54 + end
43 55 end
... ...
plugins/sub_organizations/lib/sub_organizations_plugin/relation.rb
... ... @@ -33,11 +33,11 @@ class SubOrganizationsPlugin::Relation &lt; Noosfero::Plugin::ActiveRecord
33 33 ActiveRecord::NamedScope::Scope.new(Organization, options)
34 34 end
35 35  
36   - def parents(child)
  36 + def parents(*children)
37 37 options = {
38 38 :select => "profiles.*",
39 39 :joins => "inner join sub_organizations_plugin_relations as relations on profiles.id=relations.parent_id",
40   - :conditions => ["relations.child_id = ?", child.id]
  40 + :conditions => ["relations.child_id in (?)", children.map(&:id)]
41 41 }
42 42 ActiveRecord::NamedScope::Scope.new(Organization, options)
43 43 end
... ...
plugins/sub_organizations/public/images/arrow-right-p.png 0 → 120000
... ... @@ -0,0 +1 @@
  1 +../../../../public/designs/themes/base/imgs/arrow-right-p.png
0 2 \ No newline at end of file
... ...
plugins/sub_organizations/public/style.css
1 1 #content .token-input-list {
2 2 margin-bottom: 30px;
3 3 }
  4 +
  5 +.related-organizations-button-bar {
  6 + padding-top: 40px;
  7 + clear: both;
  8 +}
  9 +
  10 +.related-organizations-block .block-footer-content a {
  11 + position: absolute;
  12 + top: 2px;
  13 + right: 0px;
  14 + font-size: 11px;
  15 + color: #000;
  16 + text-decoration: none;
  17 + padding-right: 15px;
  18 + background: url(images/arrow-right-p.png) 100% 50% no-repeat;
  19 +}
... ...
plugins/sub_organizations/test/functional/sub_organizations_plugin_profile_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,59 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +require File.dirname(__FILE__) + '/../../controllers/sub_organizations_plugin_profile_controller'
  3 +
  4 +# Re-raise errors caught by the controller.
  5 +class SubOrganizationsPluginProfileController; def rescue_action(e) raise e end; end
  6 +
  7 +class SubOrganizationsPluginProfileControllerTest < ActionController::TestCase
  8 +
  9 + def setup
  10 + @controller = SubOrganizationsPluginProfileController.new
  11 + @request = ActionController::TestRequest.new
  12 + @response = ActionController::TestResponse.new
  13 + @organization = Organization.create!(:name => 'My Organization', :identifier => 'my-organization')
  14 + @person = create_user('person').person
  15 + @organization.add_admin(@person)
  16 + login_as(@person.user.login)
  17 + e = Environment.default
  18 + e.enable_plugin('SubOrganizationsPlugin')
  19 + e.save!
  20 + @o1 = fast_create(Organization, :name => 'sample child organization 1')
  21 + @o2 = fast_create(Community, :name => 'sample child community 1')
  22 + @o3 = fast_create(Enterprise, :name => 'sample child enterprise 1')
  23 +
  24 + SubOrganizationsPlugin::Relation.add_children(@organization, @o2, @o3)
  25 + end
  26 +
  27 + attr_accessor :person, :organization
  28 +
  29 + should 'display all children organizations' do
  30 + get :children, :profile => @organization.identifier
  31 +
  32 + assert_no_match /#{@o1.name}/, @response.body
  33 + assert_match /#{@o2.name}/, @response.body
  34 + assert_match /#{@o3.name}/, @response.body
  35 + end
  36 +
  37 + should 'display only communities' do
  38 + get :children, :profile => @organization.identifier, :type => 'community'
  39 +
  40 + assert_no_match /#{@o1.name}/, @response.body
  41 + assert_match /#{@o2.name}/, @response.body
  42 + assert_no_match /#{@o3.name}/, @response.body
  43 + end
  44 +
  45 + should 'display only enterprises' do
  46 + get :children, :profile => @organization.identifier, :type => 'enterprise'
  47 +
  48 + assert_no_match /#{@o1.name}/, @response.body
  49 + assert_no_match /#{@o2.name}/, @response.body
  50 + assert_match /#{@o3.name}/, @response.body
  51 + end
  52 +
  53 + should 'not respond to person profiles' do
  54 + get :children, :profile => fast_create(Person, :name => 'Ze').identifier
  55 +
  56 + assert_response :missing
  57 + end
  58 +
  59 +end
... ...
plugins/sub_organizations/test/unit/related_organizations_block_test.rb 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +require File.dirname(__FILE__) + '/../../lib/related_organizations_block'
  3 +
  4 +class RelatedOrganizationsBlockTest < ActiveSupport::TestCase
  5 +
  6 + def setup
  7 + @block = RelatedOrganizationsBlock.new
  8 + end
  9 +
  10 + attr_reader :block
  11 +
  12 + should 'have both as default organization_type' do
  13 + assert_equal "both", block.organization_type
  14 + end
  15 +
  16 + should 'return only children when the organization is a parent' do
  17 + parent = fast_create(Organization, :name => 'I am your father', :identifier => 'i-am-your-father')
  18 + child1 = fast_create(Organization, :name => 'Rebel Alliance')
  19 + child2 = fast_create(Organization, :name => 'The Empire')
  20 + org1 = fast_create(Organization, :name => 'Jedi Council')
  21 + box = fast_create(Box, :owner_id => parent.id, :owner_type => 'Organization')
  22 + @block.box = box
  23 + @block.save!
  24 + SubOrganizationsPlugin::Relation.add_children(parent, child1, child2)
  25 +
  26 + assert @block.related_organizations.include?(child1)
  27 + assert @block.related_organizations.include?(child2)
  28 + assert !@block.related_organizations.include?(org1)
  29 + end
  30 +end
... ...
plugins/sub_organizations/test/unit/sub_organizations_plugin_test.rb
... ... @@ -45,6 +45,35 @@ class SubOrganizationsTest &lt; ActiveSupport::TestCase
45 45 assert org3_members.blank?
46 46 end
47 47  
  48 + should 'include parent-organizations in persons memberships' do
  49 + org1 = fast_create(Organization)
  50 + org2 = fast_create(Organization)
  51 + org3 = fast_create(Organization)
  52 + person1 = fast_create(Person)
  53 + person2 = fast_create(Person)
  54 + org1.add_member(person2)
  55 + org2.add_member(person1)
  56 + SubOrganizationsPlugin::Relation.create!(:parent => org1, :child => org2)
  57 + SubOrganizationsPlugin::Relation.create!(:parent => org1, :child => org3)
  58 +
  59 + person1_memberships = plugin.person_memberships(person1)
  60 + person2_memberships = plugin.person_memberships(person2)
  61 +
  62 + assert_equal ActiveRecord::NamedScope::Scope, person1_memberships.class
  63 + assert_includes person1_memberships, org1
  64 + assert_not_includes person1_memberships, org2
  65 + assert_not_includes person1_memberships, org3
  66 + assert person2_memberships.blank?
  67 + end
  68 +
  69 + should 'return blank for person memberships with no organization ' do
  70 + person1 = fast_create(Person)
  71 +
  72 + person1_memberships = plugin.person_memberships(person1)
  73 +
  74 + assert person1_memberships.blank?
  75 + end
  76 +
48 77 should 'grant permission that user has on parent organizations over children orgnaizations' do
49 78 person = create_user('admin-user').person
50 79 org1 = fast_create(Organization)
... ...
plugins/sub_organizations/views/box_organizer/_related_organizations_block.rhtml 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +<div id='edit-related-organizations-block'>
  2 + <label for="block_organization_type"><%= _('Type of organizations to be displayed') %></label><br/>
  3 + <%= select_tag('block[organization_type]', options_for_select([[_('Both'), 'both'], [_('Community'), 'community'], [_('Enterprise'), 'enterprise']], @block.organization_type)) %>
  4 + <%= labelled_form_field _('Limit of items'), text_field(:block, :limit, :size => 3) %>
  5 + <%= check_box(:block, :prioritize_profiles_with_image) %>
  6 + <label for="block_prioritize_profiles_with_image"><%= _('Prioritize profiles with image') %></label>
  7 +</div>
... ...
plugins/sub_organizations/views/profile_design 0 → 120000
... ... @@ -0,0 +1 @@
  1 +box_organizer/
0 2 \ No newline at end of file
... ...
plugins/sub_organizations/views/sub_organizations_plugin_profile/_related_organizations.rhtml 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +<div class="common-profile-list-block">
  2 +
  3 + <h1><%= __("#{profile.name}'s sub-#{organization_type.pluralize}") %></h1>
  4 +
  5 +<ul class='profile-list'>
  6 +<% organizations.each do |organization| %>
  7 + <%= profile_image_link(organization)%>
  8 +<% end %>
  9 +</ul>
  10 +
  11 +<% button_bar(:class => "related-organizations-button-bar") do %>
  12 + <%= button :back, _('Go back'), { :controller => 'profile' } %>
  13 + <%= 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}") %>
  14 +<% end %>
  15 +
  16 +</div><!-- fim class="common-profile-list-block" -->
... ...
plugins/sub_organizations/views/sub_organizations_plugin_profile/related_organizations.rhtml 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +<% if params[:type] != 'enterprise' %>
  2 + <%= render :partial => 'sub_organizations_plugin_profile/related_organizations', :locals => {:organizations => @organizations.communities, :organization_type => 'community'} %>
  3 +<% end %>
  4 +
  5 +<% if params[:type] != 'community' %>
  6 + <%= render :partial => 'sub_organizations_plugin_profile/related_organizations', :locals => {:organizations => @organizations.enterprises, :organization_type => 'enterprise'} %>
  7 +<% end %>
... ...
test/unit/person_test.rb
... ... @@ -1413,4 +1413,37 @@ class PersonTest &lt; ActiveSupport::TestCase
1413 1413 person.reload
1414 1414 assert_equal person.activities, []
1415 1415 end
  1416 +
  1417 + should 'merge memberships of plugins to original memberships' do
  1418 + class Plugin1 < Noosfero::Plugin
  1419 + def person_memberships(person)
  1420 + Profile.memberships_of(Person.find_by_identifier('person1'))
  1421 + end
  1422 + end
  1423 +
  1424 + class Plugin2 < Noosfero::Plugin
  1425 + def person_memberships(person)
  1426 + Profile.memberships_of(Person.find_by_identifier('person2'))
  1427 + end
  1428 + end
  1429 +
  1430 + Environment.default.enable_plugin(Plugin1)
  1431 + Environment.default.enable_plugin(Plugin2)
  1432 +
  1433 + original_person = fast_create(Person)
  1434 + person1 = fast_create(Person, :identifier => 'person1')
  1435 + person2 = fast_create(Person, :identifier => 'person2')
  1436 + original_cmm = fast_create(Community)
  1437 + plugin1_cmm = fast_create(Community)
  1438 + plugin2_cmm = fast_create(Community)
  1439 + original_cmm.add_member(original_person)
  1440 + plugin1_cmm.add_member(person1)
  1441 + plugin2_cmm.add_member(person2)
  1442 +
  1443 + assert_includes original_person.memberships, original_cmm
  1444 + assert_includes original_person.memberships, plugin1_cmm
  1445 + assert_includes original_person.memberships, plugin2_cmm
  1446 + assert 3, original_person.memberships.count
  1447 + end
  1448 +
1416 1449 end
... ...