Commit cbac61f7f0457ee547bb321989013a25b973efe2

Authored by Antonio Terceiro
2 parents dff781c5 b5d67b0a

Merge branch 'master' into antispam

Conflicts:
	lib/noosfero/plugin/context.rb
	lib/noosfero/plugin/manager.rb
	test/unit/plugin_manager_test.rb
Showing 38 changed files with 1112 additions and 47 deletions   Show diff stats
app/controllers/application_controller.rb
1 1 class ApplicationController < ActionController::Base
2 2  
3 3 before_filter :setup_multitenancy
  4 + before_filter :detect_stuff_by_domain
  5 + before_filter :init_noosfero_plugins
4 6  
5 7 include ApplicationHelper
6 8 layout :get_layout
... ... @@ -51,8 +53,6 @@ class ApplicationController &lt; ActionController::Base
51 53  
52 54 include NeedsProfile
53 55  
54   - before_filter :detect_stuff_by_domain
55   - before_filter :init_noosfero_plugins
56 56 attr_reader :environment
57 57  
58 58 before_filter :load_terminology
... ...
app/helpers/application_helper.rb
... ... @@ -1352,4 +1352,53 @@ module ApplicationHelper
1352 1352 :style => 'margin-top: 1em'
1353 1353 )
1354 1354 end
  1355 +
  1356 + def token_input_field_tag(name, element_id, search_action, options = {}, text_field_options = {}, html_options = {})
  1357 + options[:min_chars] ||= 3
  1358 + options[:hint_text] ||= _("Type in a search term")
  1359 + options[:no_results_text] ||= _("No results")
  1360 + options[:searching_text] ||= _("Searching...")
  1361 + options[:search_delay] ||= 1000
  1362 + options[:prevent_duplicates] ||= true
  1363 + options[:backspace_delete_item] ||= false
  1364 + options[:focus] ||= false
  1365 + options[:avoid_enter] ||= true
  1366 + options[:on_result] ||= 'null'
  1367 + options[:on_add] ||= 'null'
  1368 + options[:on_delete] ||= 'null'
  1369 + options[:on_ready] ||= 'null'
  1370 +
  1371 + result = text_field_tag(name, nil, text_field_options.merge(html_options.merge({:id => element_id})))
  1372 + result +=
  1373 + "
  1374 + <script type='text/javascript'>
  1375 + jQuery('##{element_id}')
  1376 + .tokenInput('#{url_for(search_action)}', {
  1377 + minChars: #{options[:min_chars].to_json},
  1378 + prePopulate: #{options[:pre_populate].to_json},
  1379 + hintText: #{options[:hint_text].to_json},
  1380 + noResultsText: #{options[:no_results_text].to_json},
  1381 + searchingText: #{options[:searching_text].to_json},
  1382 + searchDelay: #{options[:serach_delay].to_json},
  1383 + preventDuplicates: #{options[:prevent_duplicates].to_json},
  1384 + backspaceDeleteItem: #{options[:backspace_delete_item].to_json},
  1385 + queryParam: #{name.to_json},
  1386 + tokenLimit: #{options[:token_limit].to_json},
  1387 + onResult: #{options[:on_result]},
  1388 + onAdd: #{options[:on_add]},
  1389 + onDelete: #{options[:on_delete]},
  1390 + onReady: #{options[:on_ready]},
  1391 + })
  1392 + "
  1393 + result += options[:focus] ? ".focus();" : ";"
  1394 + if options[:avoid_enter]
  1395 + result += "jQuery('#token-input-#{element_id}')
  1396 + .live('keydown', function(event){
  1397 + if(event.keyCode == '13') return false;
  1398 + });"
  1399 + end
  1400 + result += "</script>"
  1401 + result
  1402 + end
  1403 +
1355 1404 end
... ...
app/models/person.rb
... ... @@ -22,7 +22,22 @@ class Person &lt; Profile
22 22 super
23 23 end
24 24  
25   - named_scope :members_of, lambda { |resource| { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ['role_assignments.resource_type = ? AND role_assignments.resource_id = ?', resource.class.base_class.name, resource.id ] } }
  25 + acts_as_having_hotspots
  26 +
  27 + named_scope :members_of, lambda { |resources|
  28 + resources = [resources] if !resources.kind_of?(Array)
  29 + conditions = resources.map {|resource| "role_assignments.resource_type = '#{resource.class.base_class.name}' AND role_assignments.resource_id = #{resource.id || -1}"}.join(' OR ')
  30 + { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => [conditions] }
  31 + }
  32 +
  33 + def has_permission_with_plugins?(permission, profile)
  34 + permissions = [has_permission_without_plugins?(permission, profile)]
  35 + permissions += enabled_plugins.map do |plugin|
  36 + plugin.has_permission?(self, permission, profile)
  37 + end
  38 + permissions.include?(true)
  39 + end
  40 + alias_method_chain :has_permission?, :plugins
26 41  
27 42 def memberships
28 43 Profile.memberships_of(self)
... ...
app/models/profile.rb
... ... @@ -60,6 +60,7 @@ class Profile &lt; ActiveRecord::Base
60 60 }
61 61  
62 62 acts_as_accessible
  63 + acts_as_having_hotspots
63 64  
64 65 named_scope :memberships_of, lambda { |person| { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ['role_assignments.accessor_type = ? AND role_assignments.accessor_id = ?', person.class.base_class.name, person.id ] } }
65 66 #FIXME: these will work only if the subclass is already loaded
... ... @@ -68,13 +69,24 @@ class Profile &lt; ActiveRecord::Base
68 69 named_scope :templates, :conditions => {:is_template => true}
69 70  
70 71 def members
71   - Person.members_of(self)
  72 + scopes = dispatch_scopes(:organization_members, self)
  73 + scopes << Person.members_of(self)
  74 + scopes.size == 1 ? scopes.first : Person.or_scope(scopes)
72 75 end
73 76  
74 77 def members_count
75   - members.count('DISTINCT(profiles.id)')
  78 + members.count
76 79 end
77 80  
  81 + class << self
  82 + def count_with_distinct(*args)
  83 + options = args.last || {}
  84 + count_without_distinct(:id, {:distinct => true}.merge(options))
  85 + end
  86 + alias_method_chain :count, :distinct
  87 + end
  88 +
  89 +
78 90 def members_by_role(role)
79 91 Person.members_of(self).all(:conditions => ['role_assignments.role_id = ?', role.id])
80 92 end
... ...
app/models/profile_list_block.rb
... ... @@ -25,7 +25,7 @@ class ProfileListBlock &lt; Block
25 25 end
26 26  
27 27 def profile_count
28   - profiles.visible.count('DISTINCT(profiles.id)')
  28 + profiles.visible.count
29 29 end
30 30  
31 31 # the title of the block. Probably will be overriden in subclasses.
... ...
app/views/enterprise_registration/basic_information.rhtml
... ... @@ -28,6 +28,12 @@
28 28 <%= hidden_field_tag 'create_enterprise[target_id]', environment.id %>
29 29 <% end %>
30 30  
  31 + <% @plugins.dispatch(:enterprise_registration_hidden_fields).each do |field| %>
  32 + <% field.each do |key, value| %>
  33 + <%= f.hidden_field(key, :value => value) %>
  34 + <% end %>
  35 + <% end %>
  36 +
31 37 <%= template_options(Enterprise, 'create_enterprise')%>
32 38  
33 39 <% button_bar do %>
... ...
app/views/memberships/index.rhtml
... ... @@ -8,30 +8,6 @@
8 8 <%= button :back, _('Go back'), :controller => 'profile_editor' %>
9 9 <% end %>
10 10  
11   -<ul>
12   -<% for membership in @memberships %>
13   - <li>
14   - <div class='common-profile-list-block'>
15   - <%= profile_image_link(membership, :portrait, 'div') %>
16   - </div>
17   - <span class='profile-details'>
18   - <strong><%= membership.name %></strong><br/>
19   - <%= _('Role: %s') % rolename_for(profile, membership) %> <br/>
20   - <%= _('Type: %s') % getterm(membership.class.identification) %> <br/>
21   - <%= _('Description: %s') % membership.description + '<br/>' if membership.community? %>
22   - <%= _('Members: %s') % membership.members_count.to_s %> <br/>
23   - <%= _('Created at: %s') % show_date(membership.created_at) unless membership.enterprise? %> <br/>
24   - <% button_bar do %>
25   - <%= button 'menu-ctrl-panel', _('Control panel of this group'), membership.admin_url %>
26   - <%= button 'menu-logout', _('Leave community'), membership.leave_url(true), :class => 'leave-community' %>
27   - <% if (membership.community? && user.has_permission?(:destroy_profile, membership)) %>
28   - <%= button 'delete', _('Remove'), { :controller => 'profile_editor', :action => 'destroy_profile', :profile => membership.identifier } %>
29   - <% end %>
30   - <% end %>
31   - </span>
32   - <br class="may-clear" />
33   - </li>
34   -<% end %>
35   -</ul>
  11 +<%= render :partial => 'shared/list_groups', :locals => {:groups => @memberships} %>
36 12  
37 13 </div>
... ...
app/views/memberships/new_community.rhtml
... ... @@ -16,6 +16,12 @@
16 16  
17 17 <%= required f.text_field(:name) %>
18 18  
  19 + <% @plugins.dispatch(:new_community_hidden_fields).each do |field| %>
  20 + <% field.each do |key, value| %>
  21 + <%= f.hidden_field(key, :value => value) %>
  22 + <% end %>
  23 + <% end %>
  24 +
19 25 <%= render :partial => 'shared/organization_custom_fields', :locals => { :f => f, :object_name => 'community', :profile => @community } %>
20 26  
21 27 <% f.fields_for :image_builder, @community.image do |i| %>
... ...
app/views/shared/_list_groups.html.erb 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +<ul id="groups-list">
  2 +<% for group in groups %>
  3 + <li>
  4 + <div class='common-profile-list-block'>
  5 + <%= profile_image_link(group, :portrait, 'div') %>
  6 + </div>
  7 + <span class='profile-details'>
  8 + <strong><%= group.name %></strong><br/>
  9 + <%= _('Role: %s') % rolename_for(profile, group) + '<br/>' if profile.role_assignments.find_by_resource_id(group.id) %>
  10 + <%= _('Type: %s') % getterm(group.class.identification) %> <br/>
  11 + <%= _('Description: %s') % group.description + '<br/>' if group.community? %>
  12 + <%= _('Members: %s') % group.members_count.to_s %> <br/>
  13 + <%= _('Created at: %s') % show_date(group.created_at) unless group.enterprise? %> <br/>
  14 + <% button_bar do %>
  15 + <%= button 'menu-ctrl-panel', _('Control panel of this group'), group.admin_url %>
  16 + <%= button 'menu-logout', _('Leave community'), group.leave_url(true), :class => 'leave-community' %>
  17 + <% if (group.community? && user.has_permission?(:destroy_profile, group)) %>
  18 + <%= button 'delete', _('Remove'), { :controller => 'profile_editor', :action => 'destroy_profile', :profile => group.identifier } %>
  19 + <% end %>
  20 + <% end %>
  21 + </span>
  22 + <br class="may-clear" />
  23 + </li>
  24 +<% end %>
  25 +</ul>
  26 +
... ...
config/initializers/plugins.rb
1 1 require 'noosfero/plugin'
  2 +require 'noosfero/plugin/acts_as_having_hotspots'
2 3 require 'noosfero/plugin/manager'
3 4 require 'noosfero/plugin/active_record'
4 5 require 'noosfero/plugin/mailer_base'
... ...
lib/noosfero/plugin.rb
... ... @@ -293,4 +293,29 @@ class Noosfero::Plugin
293 293 nil
294 294 end
295 295  
  296 + # -> Extends organization list of members
  297 + # returns = An instance of ActiveRecord::NamedScope::Scope retrieved through
  298 + # Person.members_of method.
  299 + def organization_members(organization)
  300 + nil
  301 + end
  302 +
  303 + # -> Extends person permission access
  304 + # returns = boolean
  305 + def has_permission?(person, permission, target)
  306 + nil
  307 + end
  308 +
  309 + # -> Adds hidden_fields to the new community view
  310 + # returns = {key => value}
  311 + def new_community_hidden_fields
  312 + nil
  313 + end
  314 +
  315 + # -> Adds hidden_fields to the enterprise registration view
  316 + # returns = {key => value}
  317 + def enterprise_registration_hidden_fields
  318 + nil
  319 + end
  320 +
296 321 end
... ...
lib/noosfero/plugin/acts_as_having_hotspots.rb 0 → 100644
... ... @@ -0,0 +1,44 @@
  1 +module ActsAsHavingHotspots
  2 + module ClassMethods
  3 + # Adding this feature to a class demands that it defines an instance method
  4 + # 'environment' that returns the environment associated with the instance.
  5 + def acts_as_having_hotspots
  6 + send :include, InstanceMethods
  7 + end
  8 +
  9 + module InstanceMethods
  10 + # Dispatches +event+ to each enabled plugin and collect the results.
  11 + #
  12 + # Returns an Array containing the objects returned by the event method in
  13 + # each plugin. This array is compacted (i.e. nils are removed) and flattened
  14 + # (i.e. elements of arrays are added to the resulting array). For example, if
  15 + # the enabled plugins return 1, 0, nil, and [1,2,3], then this method will
  16 + # return [1,0,1,2,3]
  17 + #
  18 + def dispatch(event, *args)
  19 + enabled_plugins.map { |plugin| plugin.send(event, *args) }.compact.flatten
  20 + end
  21 +
  22 + # Dispatch without flatten since scopes are executed if you run flatten on them
  23 + def dispatch_scopes(event, *args)
  24 + enabled_plugins.map { |plugin| plugin.send(event, *args) }.compact
  25 + end
  26 +
  27 + def enabled_plugins
  28 + Thread.current[:enabled_plugins] ||= (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin_name|
  29 + plugin = plugin_name.constantize.new
  30 + plugin.context = context
  31 + plugin
  32 + end
  33 + end
  34 +
  35 + if !method_defined?(:context)
  36 + define_method(:context) do
  37 + Noosfero::Plugin::Context.new
  38 + end
  39 + end
  40 + end
  41 + end
  42 +end
  43 +
  44 +ActiveRecord::Base.send(:extend, ActsAsHavingHotspots::ClassMethods)
... ...
lib/noosfero/plugin/manager.rb
... ... @@ -8,6 +8,7 @@ class Noosfero::Plugin::Manager
8 8 @constantize = context
9 9 end
10 10  
  11 + delegate :environment, :to => :context
11 12 delegate :each, :to => :enabled_plugins
12 13 include Enumerable
13 14  
... ...
plugins/sub_organizations/controllers/sub_organizations_plugin_myprofile_controller.rb 0 → 100644
... ... @@ -0,0 +1,54 @@
  1 +class SubOrganizationsPluginMyprofileController < MyProfileController
  2 + append_view_path File.join(File.dirname(__FILE__) + '/../views')
  3 +
  4 + before_filter :organizations_only
  5 + protect 'edit_profile', :profile
  6 +
  7 + def index
  8 + @children = SubOrganizationsPlugin::Relation.children(profile)
  9 + @tokenized_children = prepare_to_token_input(@children)
  10 + @pending_children = SubOrganizationsPlugin::ApprovePaternityRelation.pending_children(profile)
  11 + if request.post?
  12 + begin
  13 + original = SubOrganizationsPlugin::Relation.children(profile)
  14 + requested = Organization.find(params[:q].split(','))
  15 + added = requested - original
  16 + removed = original - requested
  17 + added.each do |organization|
  18 + if current_person.has_permission?('perform_task',organization)
  19 + SubOrganizationsPlugin::Relation.add_children(profile, organization)
  20 + else
  21 + SubOrganizationsPlugin::ApprovePaternity.create!(:requestor => user, :temp_parent_type => profile.class.name, :temp_parent_id => profile.id, :target => organization)
  22 + end
  23 + end
  24 + SubOrganizationsPlugin::Relation.remove_children(profile,removed)
  25 + session[:notice] = _('Sub-organizations updated')
  26 + rescue Exception => exception
  27 + logger.error(exception.to_s)
  28 + session[:notice] = _('Sub-organizations could not be updated')
  29 + end
  30 + redirect_to :action => :index
  31 + end
  32 + end
  33 +
  34 + def search_organization
  35 + render :text => prepare_to_token_input(environment.organizations.find(:all, :conditions =>
  36 + ["(LOWER(name) LIKE ? OR LOWER(identifier) LIKE ?)
  37 + AND (identifier NOT LIKE ?) AND (id != ?)",
  38 + "%#{params[:q]}%", "%#{params[:q]}%", "%_template", profile.id]).
  39 + select { |organization|
  40 + SubOrganizationsPlugin::Relation.children(organization).blank? &&
  41 + !SubOrganizationsPlugin::ApprovePaternityRelation.pending_children(profile).include?(organization)
  42 + }).to_json
  43 + end
  44 +
  45 + private
  46 +
  47 + def organizations_only
  48 + render_not_found if !profile.organization?
  49 + end
  50 +
  51 + def prepare_to_token_input(array)
  52 + array.map { |object| {:id => object.id, :name => object.name} }
  53 + end
  54 +end
... ...
plugins/sub_organizations/db/migrate/20120530173629_create_relation.rb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +class CreateRelation < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :sub_organizations_plugin_relations do |t|
  4 + t.references :parent, :polymorphic => true
  5 + t.references :child, :polymorphic => true
  6 + end
  7 + end
  8 +
  9 + def self.down
  10 + drop_table :sub_organizations_plugin_relations
  11 + end
  12 +end
... ...
plugins/sub_organizations/db/migrate/20120615202224_approve_paternity_relation.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +class ApprovePaternityRelation < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :sub_organizations_plugin_approve_paternity_relations do |t|
  4 + t.references :task
  5 + t.references :parent, :polymorphic => true
  6 + t.references :child, :polymorphic => true
  7 + end
  8 + end
  9 +
  10 + def self.down
  11 + drop_table :sub_organizations_plugin_approve_paternity_relations
  12 + end
  13 +end
... ...
plugins/sub_organizations/lib/sub_organizations_plugin.rb 0 → 100644
... ... @@ -0,0 +1,46 @@
  1 +require_dependency 'sub_organizations_plugin/ext/organization'
  2 +require_dependency 'sub_organizations_plugin/ext/create_enterprise'
  3 +
  4 +class SubOrganizationsPlugin < Noosfero::Plugin
  5 +
  6 + def self.plugin_name
  7 + _("Sub-groups")
  8 + end
  9 +
  10 + def self.plugin_description
  11 + _("Adds the ability for groups to have sub-groups.")
  12 + end
  13 +
  14 + def control_panel_buttons
  15 + if context.profile.organization? && SubOrganizationsPlugin::Relation.parents(context.profile).blank?
  16 + { :title => _('Manage sub-groups'), :icon => 'groups', :url => {:controller => 'sub_organizations_plugin_myprofile'} }
  17 + end
  18 + end
  19 +
  20 + def stylesheet?
  21 + true
  22 + end
  23 +
  24 + def organization_members(organization)
  25 + children = SubOrganizationsPlugin::Relation.children(organization)
  26 + Person.members_of(children) if children.present?
  27 + end
  28 +
  29 + def has_permission?(person, permission, target)
  30 + if !target.kind_of?(Environment) && target.organization?
  31 + SubOrganizationsPlugin::Relation.parents(target).map do |parent|
  32 + person.has_permission_without_plugins?(permission, parent)
  33 + end.include?(true)
  34 + end
  35 + end
  36 +
  37 + def new_community_hidden_fields
  38 + parent_to_be = context.params[:sub_organizations_plugin_parent_to_be]
  39 + {'sub_organizations_plugin_parent_to_be' => parent_to_be} if parent_to_be.present?
  40 + end
  41 +
  42 + def enterprise_registration_hidden_fields
  43 + parent_to_be = context.params[:sub_organizations_plugin_parent_to_be]
  44 + {'sub_organizations_plugin_parent_to_be' => parent_to_be} if parent_to_be.present?
  45 + end
  46 +end
... ...
plugins/sub_organizations/lib/sub_organizations_plugin/approve_paternity.rb 0 → 100644
... ... @@ -0,0 +1,57 @@
  1 +class SubOrganizationsPlugin::ApprovePaternity < Task
  2 + validates_presence_of :requestor, :target
  3 +
  4 + settings_items :temp_parent_id
  5 + settings_items :temp_parent_type
  6 +
  7 + after_create do |task|
  8 + r = SubOrganizationsPlugin::ApprovePaternityRelation.create!(:task => task, :parent => task.temp_parent, :child => task.target)
  9 + end
  10 +
  11 + def temp_parent
  12 + temp_parent_type.constantize.find(temp_parent_id)
  13 + end
  14 +
  15 + def parent
  16 + SubOrganizationsPlugin::ApprovePaternityRelation.parent(self)
  17 + end
  18 +
  19 + def title
  20 + _("Paternity request")
  21 + end
  22 +
  23 + def linked_subject
  24 + {:text => parent.name, :url => parent.url}
  25 + end
  26 +
  27 + def information
  28 + {:message => _('%{requestor} wants to add this organization as a sub-organization of %{linked_subject}.')}
  29 + end
  30 +
  31 + def reject_details
  32 + true
  33 + end
  34 +
  35 + def icon
  36 + {:type => :profile_image, :profile => parent, :url => parent.url}
  37 + end
  38 +
  39 + def task_created_message
  40 + ('%{requestor} wants to add your organization %{target} as a sub-organization of %{parent}.') % {:requestor => requestor.name, :target => target.name, :parent => temp_parent.name}
  41 + end
  42 +
  43 + def task_finished_message
  44 + ('%{target} accepted your request to add it as a sub-organization of %{parent}.') % {:target => target.name, :parent => parent.name}
  45 + end
  46 +
  47 + def task_cancelled_message
  48 + ('%{target} refused your request to add it as a sub-organization of %{parent}.') % {:target => target.name, :parent => parent.name}
  49 + end
  50 +
  51 + protected
  52 +
  53 + def perform
  54 + SubOrganizationsPlugin::Relation.add_children(parent, target)
  55 + end
  56 +
  57 +end
... ...
plugins/sub_organizations/lib/sub_organizations_plugin/approve_paternity_relation.rb 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +class SubOrganizationsPlugin::ApprovePaternityRelation < Noosfero::Plugin::ActiveRecord
  2 + belongs_to :task
  3 + belongs_to :parent, :polymorphic => true
  4 + belongs_to :child, :polymorphic => true
  5 +
  6 + validates_presence_of :task, :parent, :child
  7 +
  8 + class << self
  9 + def parent(task)
  10 + find_by_task_id(task.id).parent
  11 + end
  12 +
  13 + def pending_children(parent)
  14 + options = {
  15 + :select => "distinct profiles.*",
  16 + :joins => "inner join sub_organizations_plugin_approve_paternity_relations as relations on profiles.id=relations.child_id inner join tasks on relations.task_id=tasks.id",
  17 + :conditions => ["relations.parent_id = ? AND tasks.status = 1", parent.id]
  18 + }
  19 + ActiveRecord::NamedScope::Scope.new(Organization, options)
  20 + end
  21 + end
  22 +
  23 +end
... ...
plugins/sub_organizations/lib/sub_organizations_plugin/ext/create_enterprise.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +require_dependency 'create_enterprise'
  2 +
  3 +class CreateEnterprise
  4 + settings_items :sub_organizations_plugin_parent_to_be
  5 +end
... ...
plugins/sub_organizations/lib/sub_organizations_plugin/ext/organization.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +require_dependency 'organization'
  2 +class Organization
  3 + settings_items :sub_organizations_plugin_parent_to_be
  4 +
  5 + after_create do |organization|
  6 + if organization.sub_organizations_plugin_parent_to_be.present?
  7 + parent = Organization.find(organization.sub_organizations_plugin_parent_to_be)
  8 + SubOrganizationsPlugin::Relation.add_children(parent,organization)
  9 + end
  10 + end
  11 +
  12 + FIELDS << 'sub_organizations_plugin_parent_to_be'
  13 +end
... ...
plugins/sub_organizations/lib/sub_organizations_plugin/relation.rb 0 → 100644
... ... @@ -0,0 +1,54 @@
  1 +class SubOrganizationsPlugin::Relation < Noosfero::Plugin::ActiveRecord
  2 + belongs_to :parent, :polymorphic => true
  3 + belongs_to :child, :polymorphic => true
  4 +
  5 + validates_presence_of :parent, :child
  6 + validate :no_self_reference
  7 + validate :no_cyclical_reference, :if => 'parent.present? && child.present?'
  8 + validate :no_multi_level, :if => 'parent.present? && child.present?'
  9 +
  10 + def no_self_reference
  11 + errors.add(:child, _('self-reference is not allowed.')) if parent == child
  12 + end
  13 +
  14 + def no_cyclical_reference
  15 + if self.class.children(child).include?(parent)
  16 + errors.add(:child, _('cyclical reference is not allowed.'))
  17 + end
  18 + end
  19 +
  20 + def no_multi_level
  21 + if self.class.parents(parent).present? || self.class.children(child).present?
  22 + errors.add(:child, _('multi-level paternity is not allowed.'))
  23 + end
  24 + end
  25 +
  26 + class << self
  27 + def children(parent)
  28 + options = {
  29 + :select => "profiles.*",
  30 + :joins => "inner join sub_organizations_plugin_relations as relations on profiles.id=relations.child_id",
  31 + :conditions => ["relations.parent_id = ?", parent.id]
  32 + }
  33 + ActiveRecord::NamedScope::Scope.new(Organization, options)
  34 + end
  35 +
  36 + def parents(child)
  37 + options = {
  38 + :select => "profiles.*",
  39 + :joins => "inner join sub_organizations_plugin_relations as relations on profiles.id=relations.parent_id",
  40 + :conditions => ["relations.child_id = ?", child.id]
  41 + }
  42 + ActiveRecord::NamedScope::Scope.new(Organization, options)
  43 + end
  44 +
  45 + def add_children(parent, *children)
  46 + children.each {|child| create!(:parent => parent, :child => child)}
  47 + end
  48 +
  49 + def remove_children(parent, *children)
  50 + children.flatten.each {|child| find_by_parent_id_and_child_id(parent.id, child.id).destroy}
  51 + end
  52 + end
  53 +
  54 +end
... ...
plugins/sub_organizations/public/style.css 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +#content .token-input-list {
  2 + margin-bottom: 30px;
  3 +}
... ...
plugins/sub_organizations/test/functional/sub_organizations_plugin_myprofile_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,113 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +require File.dirname(__FILE__) + '/../../controllers/sub_organizations_plugin_myprofile_controller'
  3 +
  4 +# Re-raise errors caught by the controller.
  5 +class SubOrganizationsPluginMyprofileController; def rescue_action(e) raise e end; end
  6 +
  7 +class SubOrganizationsPluginMyprofileControllerTest < ActionController::TestCase
  8 + def setup
  9 + @controller = SubOrganizationsPluginMyprofileController.new
  10 + @request = ActionController::TestRequest.new
  11 + @response = ActionController::TestResponse.new
  12 + @organization = Organization.create!(:name => 'My Organization', :identifier => 'my-organization')
  13 + @person = create_user('person').person
  14 + @organization.add_admin(@person)
  15 + login_as(@person.user.login)
  16 + e = Environment.default
  17 + e.enable_plugin('SubOrganizationsPlugin')
  18 + e.save!
  19 + end
  20 +
  21 + attr_accessor :person, :organization
  22 +
  23 + should 'search organizations' do
  24 + # Should list if match name
  25 + o1 = fast_create(Organization, :name => 'sample organization 1')
  26 + # Should be case insensitive
  27 + o2 = fast_create(Organization, :name => 'SaMpLe OrGaNiZaTiOn 2')
  28 + # Should not list if don't match name
  29 + o3 = fast_create(Organization, :name => 'blo')
  30 + # Should not list if is has children
  31 + child = fast_create(Organization)
  32 + o4 = fast_create(Organization, :name => 'sample organization 4')
  33 + SubOrganizationsPlugin::Relation.add_children(o4, child)
  34 + # Should not list if is there is a task to add it
  35 + o5 = fast_create(Organization, :name => 'sample enterprise 5')
  36 + SubOrganizationsPlugin::ApprovePaternity.create!(:requestor => person, :target => o5, :temp_parent_id => organization.id, :temp_parent_type => organization.class.name)
  37 + # Should search by identifier
  38 + o6 = fast_create(Organization, :name => 'Bla', :identifier => 'sample-enterprise-6')
  39 + # Should not list itself
  40 + organization.name = 'Sample Organization'
  41 + organization.save!
  42 +
  43 + get :search_organization, :profile => organization.identifier, :q => 'sampl'
  44 +
  45 + assert_match /#{o1.name}/, @response.body
  46 + assert_match /#{o2.name}/, @response.body
  47 + assert_no_match /#{o3.name}/, @response.body
  48 + assert_no_match /#{o4.name}/, @response.body
  49 + assert_no_match /#{o5.name}/, @response.body
  50 + assert_match /#{o6.name}/, @response.body
  51 + assert_no_match /#{organization.name}/, @response.body
  52 + end
  53 +
  54 + should 'update sub-organizations list' do
  55 + org1 = fast_create(Organization)
  56 + org2 = fast_create(Organization)
  57 + org3 = fast_create(Organization)
  58 + org4 = fast_create(Organization)
  59 + SubOrganizationsPlugin::Relation.add_children(organization, org1, org2)
  60 +
  61 + post :index, :profile => organization.identifier, :q => [org2,org3,org4].map(&:id).join(',')
  62 +
  63 + children = SubOrganizationsPlugin::Relation.children(organization)
  64 + assert_not_includes children, org1
  65 + assert_includes children, org2
  66 + assert_not_includes children, org3
  67 + assert_not_includes children, org4
  68 +
  69 + SubOrganizationsPlugin::ApprovePaternity.all.map(&:finish)
  70 +
  71 + children = SubOrganizationsPlugin::Relation.children(organization)
  72 + assert_not_includes children, org1
  73 + assert_includes children, org2
  74 + assert_includes children, org3
  75 + assert_includes children, org4
  76 + end
  77 +
  78 + should 'establish relation right away if the user can perform tasks on the sub-organization' do
  79 + org1 = fast_create(Organization)
  80 + org2 = fast_create(Organization)
  81 + org2.add_admin(person)
  82 +
  83 + assert_difference SubOrganizationsPlugin::ApprovePaternity, :count, 1 do
  84 + post :index, :profile => organization.identifier, :q => [org1,org2].map(&:id).join(',')
  85 + end
  86 + assert_includes SubOrganizationsPlugin::Relation.children(organization), org2
  87 + end
  88 +
  89 + should 'not access index if dont have permission' do
  90 + member = create_user('member').person
  91 + organization.add_member(member)
  92 +
  93 + login_as(member.identifier)
  94 + get :index, :profile => organization.identifier
  95 +
  96 + assert_response 403
  97 + assert_template 'access_denied.rhtml'
  98 + end
  99 +
  100 + should 'not search organizations if dont have permission' do
  101 + member = create_user('member').person
  102 + organization.add_member(member)
  103 +
  104 + login_as(member.identifier)
  105 +
  106 + org1 = fast_create(Organization, :name => 'sample organization 1')
  107 + get :search_organization, :profile => organization.identifier, :q => 'sampl'
  108 +
  109 + assert_response 403
  110 + assert_template 'access_denied.rhtml'
  111 + end
  112 +
  113 +end
... ...
plugins/sub_organizations/test/unit/sub_organizations_plugin/approve_paternity_relation_test.rb 0 → 100644
... ... @@ -0,0 +1,32 @@
  1 +require File.dirname(__FILE__) + '/../../../../../test/test_helper'
  2 +
  3 +class SubOrganizationsPlugin::ApprovePaternityRelationTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @requestor = create_user('some-user').person
  7 + end
  8 +
  9 + attr_reader :requestor
  10 +
  11 + should 'return parent' do
  12 + org1 = fast_create(Organization)
  13 + org2 = fast_create(Organization)
  14 + task = SubOrganizationsPlugin::ApprovePaternity.create!(:requestor => requestor, :target => org2, :temp_parent_id => org1.id, :temp_parent_type => org1.class.name)
  15 +
  16 + assert_equal SubOrganizationsPlugin::ApprovePaternityRelation.parent(task), org1
  17 + end
  18 +
  19 + should 'list pending children' do
  20 + organization = fast_create(Organization)
  21 + org1 = fast_create(Organization)
  22 + org2 = fast_create(Organization)
  23 + org3 = fast_create(Organization)
  24 +
  25 + SubOrganizationsPlugin::ApprovePaternity.create!(:requestor => requestor, :target => org1, :temp_parent_id => organization.id, :temp_parent_type => organization.class.name)
  26 + SubOrganizationsPlugin::ApprovePaternity.create!(:requestor => requestor, :target => org2, :temp_parent_id => organization.id, :temp_parent_type => organization.class.name)
  27 +
  28 + assert_includes SubOrganizationsPlugin::ApprovePaternityRelation.pending_children(organization), org1
  29 + assert_includes SubOrganizationsPlugin::ApprovePaternityRelation.pending_children(organization), org2
  30 + assert_not_includes SubOrganizationsPlugin::ApprovePaternityRelation.pending_children(organization), org3
  31 + end
  32 +end
... ...
plugins/sub_organizations/test/unit/sub_organizations_plugin/approve_paternity_test.rb 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +require File.dirname(__FILE__) + '/../../../../../test/test_helper'
  2 +
  3 +class SubOrganizationsPlugin::ApprovePaternityTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @requestor = create_user('some-user').person
  7 + end
  8 +
  9 + attr_reader :requestor
  10 +
  11 + should 'create relation after creation' do
  12 + org1 = fast_create(Organization)
  13 + org2 = fast_create(Organization)
  14 + assert_difference SubOrganizationsPlugin::ApprovePaternityRelation, :count, 1 do
  15 + SubOrganizationsPlugin::ApprovePaternity.create!(:requestor => requestor, :temp_parent_id => org1.id, :temp_parent_type => org1.class.name, :target => org2)
  16 + end
  17 + end
  18 +
  19 + should 'add children to parent after approving' do
  20 + org1 = fast_create(Organization)
  21 + org2 = fast_create(Organization)
  22 +
  23 + task = SubOrganizationsPlugin::ApprovePaternity.create!(:requestor => requestor, :temp_parent_id => org1.id, :temp_parent_type => org1.class.name, :target => org2)
  24 + assert_not_includes SubOrganizationsPlugin::Relation.children(org1), org2
  25 +
  26 + task.finish
  27 + assert_includes SubOrganizationsPlugin::Relation.children(org1), org2
  28 + end
  29 +end
... ...
plugins/sub_organizations/test/unit/sub_organizations_plugin/ext/create_enterprise_test.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +require File.dirname(__FILE__) + '/../../../../../../test/test_helper'
  2 +
  3 +class CreateEnterpriseTest < ActiveSupport::TestCase
  4 +
  5 + should 'inlude the parent field in create enterprise' do
  6 + create_enterprise = CreateEnterprise.new
  7 + assert_nothing_raised { create_enterprise.sub_organizations_plugin_parent_to_be = '999' }
  8 + end
  9 +
  10 +end
  11 +
... ...
plugins/sub_organizations/test/unit/sub_organizations_plugin/ext/organization.rb 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +require File.dirname(__FILE__) + '/../../../../../../test/test_helper'
  2 +
  3 +class OrganizationTest < ActiveSupport::TestCase
  4 +
  5 + should 'inlude the parent field in organization' do
  6 + organization = Organization.new
  7 + assert_nothing_raised { organization.sub_organizations_plugin_parent_to_be = '999' }
  8 + end
  9 +
  10 + should 'include the parent field in the FIELDS constant' do
  11 + assert_includes Organization::FIELDS, 'sub_organizations_plugin_parent_to_be'
  12 + end
  13 +
  14 + should 'relate organization with parent if the attribute is set' do
  15 + parent = fast_create(Organization)
  16 + organization = Organization.new(:identifier => 'some-org',:name => 'Some Org', :sub_organizations_plugin_parent_to_be => parent.id)
  17 + assert_not_includes SubOrganizationsPlugin::Relation.children(parent), organization
  18 +
  19 + organization.save!
  20 + assert_includes SubOrganizationsPlugin::Relation.children(parent), organization
  21 + end
  22 +
  23 +end
... ...
plugins/sub_organizations/test/unit/sub_organizations_plugin/relation_test.rb 0 → 100644
... ... @@ -0,0 +1,110 @@
  1 +require File.dirname(__FILE__) + '/../../../../../test/test_helper'
  2 +
  3 +class SubOrganizationsPlugin::RelationTest < ActiveSupport::TestCase
  4 +
  5 + should 'validates presence of child and parent' do
  6 + org = fast_create(Organization)
  7 + relation = SubOrganizationsPlugin::Relation.new
  8 +
  9 + relation.parent = org
  10 + relation.valid?
  11 + assert relation.errors.invalid?(:child)
  12 +
  13 + relation.parent = nil
  14 + relation.child = org
  15 + relation.valid?
  16 + assert relation.errors.invalid?(:parent)
  17 + end
  18 +
  19 + should 'relate two organizations' do
  20 + org1 = fast_create(Organization)
  21 + org2 = fast_create(Organization)
  22 + relation = SubOrganizationsPlugin::Relation.create!(:parent => org1, :child => org2)
  23 +
  24 + assert_equal org1, relation.parent
  25 + assert_equal org2, relation.child
  26 + end
  27 +
  28 + should 'not allow self relation' do
  29 + org = fast_create(Organization)
  30 + relation = SubOrganizationsPlugin::Relation.new(:parent_id => org, :child_id => org)
  31 + assert !relation.valid?
  32 + assert relation.errors.invalid?(:child)
  33 + end
  34 +
  35 + should 'be able to retrieve parents of an organization' do
  36 + child = fast_create(Organization)
  37 + parent1 = fast_create(Organization)
  38 + parent2 = fast_create(Organization)
  39 + SubOrganizationsPlugin::Relation.create!(:parent => parent1, :child => child)
  40 + SubOrganizationsPlugin::Relation.create!(:parent => parent2, :child => child)
  41 +
  42 + assert_includes SubOrganizationsPlugin::Relation.parents(child), parent1
  43 + assert_includes SubOrganizationsPlugin::Relation.parents(child), parent2
  44 + end
  45 +
  46 + should 'be able to retrieve children of an organization' do
  47 + parent = fast_create(Organization)
  48 + child1 = fast_create(Organization)
  49 + child2 = fast_create(Organization)
  50 + SubOrganizationsPlugin::Relation.create!(:parent => parent, :child => child1)
  51 + SubOrganizationsPlugin::Relation.create!(:parent => parent, :child => child2)
  52 +
  53 + assert_includes SubOrganizationsPlugin::Relation.children(parent), child1
  54 + assert_includes SubOrganizationsPlugin::Relation.children(parent), child2
  55 + end
  56 +
  57 + should 'not allow cyclical reference' do
  58 + org1 = fast_create(Organization)
  59 + org2 = fast_create(Organization)
  60 + SubOrganizationsPlugin::Relation.create!(:parent => org1, :child => org2)
  61 + relation = SubOrganizationsPlugin::Relation.new(:parent => org2, :child => org1)
  62 +
  63 + assert !relation.valid?
  64 + assert relation.errors.invalid?(:child)
  65 + end
  66 +
  67 + should 'not allow multi-level paternity' do
  68 + org1 = fast_create(Organization)
  69 + org2 = fast_create(Organization)
  70 + org3 = fast_create(Organization)
  71 + SubOrganizationsPlugin::Relation.create!(:parent => org1, :child => org2)
  72 + r1 = SubOrganizationsPlugin::Relation.new(:parent => org2, :child => org3)
  73 + r2 = SubOrganizationsPlugin::Relation.new(:parent => org3, :child => org1)
  74 +
  75 + assert !r1.valid?
  76 + assert r1.errors.invalid?(:child)
  77 +
  78 + assert !r2.valid?
  79 + assert r2.errors.invalid?(:child)
  80 + end
  81 +
  82 + should 'add children' do
  83 + org1 = fast_create(Organization)
  84 + org2 = fast_create(Organization)
  85 + org3 = fast_create(Organization)
  86 + org4 = fast_create(Organization)
  87 +
  88 + SubOrganizationsPlugin::Relation.add_children(org1,org2)
  89 + assert_includes SubOrganizationsPlugin::Relation.children(org1), org2
  90 +
  91 + SubOrganizationsPlugin::Relation.add_children(org1,org3,org4)
  92 + assert_includes SubOrganizationsPlugin::Relation.children(org1), org3
  93 + assert_includes SubOrganizationsPlugin::Relation.children(org1), org4
  94 + end
  95 +
  96 + should 'remove children' do
  97 + org1 = fast_create(Organization)
  98 + org2 = fast_create(Organization)
  99 + org3 = fast_create(Organization)
  100 + org4 = fast_create(Organization)
  101 + SubOrganizationsPlugin::Relation.add_children(org1,org2,org3,org4)
  102 +
  103 + SubOrganizationsPlugin::Relation.remove_children(org1,org2)
  104 + assert_not_includes SubOrganizationsPlugin::Relation.children(org1), org2
  105 +
  106 + SubOrganizationsPlugin::Relation.remove_children(org1,org3,org4)
  107 + assert_not_includes SubOrganizationsPlugin::Relation.children(org1), org3
  108 + assert_not_includes SubOrganizationsPlugin::Relation.children(org1), org4
  109 + end
  110 +end
... ...
plugins/sub_organizations/test/unit/sub_organizations_plugin_test.rb 0 → 100644
... ... @@ -0,0 +1,83 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +
  3 +class SubOrganizationsTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @plugin = SubOrganizationsPlugin.new
  7 + end
  8 +
  9 + attr_reader :plugin
  10 +
  11 + should 'include sub-organizations members in the parent organization' do
  12 + org1 = fast_create(Organization)
  13 + org2 = fast_create(Organization)
  14 + org3 = fast_create(Organization)
  15 + member1 = fast_create(Person)
  16 + member2 = fast_create(Person)
  17 + member3 = fast_create(Person)
  18 + member4 = fast_create(Person)
  19 + member5 = fast_create(Person)
  20 + member6 = fast_create(Person)
  21 + member7 = fast_create(Person)
  22 + org1.add_member(member1)
  23 + org2.add_member(member2)
  24 + org2.add_member(member3)
  25 + org3.add_member(member4)
  26 + org3.add_member(member5)
  27 + SubOrganizationsPlugin::Relation.create!(:parent => org1, :child => org2)
  28 + SubOrganizationsPlugin::Relation.create!(:parent => org1, :child => org3)
  29 +
  30 + org1_members = plugin.organization_members(org1)
  31 +
  32 + assert_equal ActiveRecord::NamedScope::Scope, org1_members.class
  33 + assert_not_includes org1_members, member1
  34 + assert_includes org1_members, member2
  35 + assert_includes org1_members, member3
  36 + assert_includes org1_members, member4
  37 + assert_includes org1_members, member5
  38 + assert_not_includes org1_members, member6
  39 + assert_not_includes org1_members, member7
  40 +
  41 + org2_members = plugin.organization_members(org2)
  42 + org3_members = plugin.organization_members(org3)
  43 +
  44 + assert org2_members.blank?
  45 + assert org3_members.blank?
  46 + end
  47 +
  48 + should 'grant permission that user has on parent organizations over children orgnaizations' do
  49 + person = create_user('admin-user').person
  50 + org1 = fast_create(Organization)
  51 + org2 = fast_create(Organization)
  52 + SubOrganizationsPlugin::Relation.add_children(org1,org2)
  53 + person.stubs('has_permission_without_plugins?').with(:make_ice_cream, org1).returns(true)
  54 + person.stubs('has_permission_without_plugins?').with(:make_ice_cream, org2).returns(false)
  55 +
  56 + assert plugin.has_permission?(person, :make_ice_cream, org2)
  57 + end
  58 +
  59 + should 'not crash if receives an environment as target of has permission' do
  60 + assert_nothing_raised do
  61 + plugin.has_permission?(fast_create(Person), :make_ice_cream, fast_create(Environment))
  62 + end
  63 + end
  64 +
  65 + should 'display control panel button only to organizations with no parent' do
  66 + org1 = fast_create(Organization)
  67 + org2 = fast_create(Organization)
  68 + profile = fast_create(Profile)
  69 + SubOrganizationsPlugin::Relation.add_children(org1,org2)
  70 + context = mock()
  71 + SubOrganizationsPlugin.any_instance.stubs(:context).returns(context)
  72 +
  73 + context.stubs(:profile).returns(org1)
  74 + assert_not_nil plugin.control_panel_buttons
  75 +
  76 + context.stubs(:profile).returns(org2)
  77 + assert_nil plugin.control_panel_buttons
  78 +
  79 + context.stubs(:profile).returns(profile)
  80 + assert_nil plugin.control_panel_buttons
  81 + end
  82 +end
  83 +
... ...
plugins/sub_organizations/views/sub_organizations_plugin_myprofile/index.html.erb 0 → 100644
... ... @@ -0,0 +1,32 @@
  1 +<h1><%= _('Manage sub-groups') %></h1>
  2 +
  3 +<% if !@pending_children.blank? %>
  4 + <%= _('Sub-groups awaiting approval:') %>
  5 + <ul>
  6 + <% @pending_children.each do |child| %>
  7 + <li><%= link_to(child.name, child.url) %></li>
  8 + <% end %>
  9 + </ul>
  10 +<% end %>
  11 +
  12 +<% form_tag do %>
  13 + <% button_bar do %>
  14 + <%= button(:add, __('Create a new sub-community'), :controller => 'memberships', :action => 'new_community', :profile => user.identifier, :sub_organizations_plugin_parent_to_be => profile.id) %>
  15 + <%= button :add, __('Register a new sub-enterprise'), :controller => 'enterprise_registration', :sub_organizations_plugin_parent_to_be => profile.id if environment.enabled?('enterprise_registration') %>
  16 + <% end %>
  17 +
  18 + <p><%= _('Fill in the search field to find the groups that should be added as sub-group of this organization:') %></p>
  19 + <%= token_input_field_tag(:q, 'search-organization', {:action => 'search_organization'},
  20 + { :focus => true,
  21 + :hint_text => _('Type in a search term for a group'),
  22 + :pre_populate => @tokenized_children}) %>
  23 +
  24 + <% button_bar do %>
  25 + <%= submit_button('save', _('Save'))%>
  26 + <%= button('cancel', _('Cancel'), {:controller => 'profile_editor'})%>
  27 + <% end %>
  28 +<% end %>
  29 +
  30 +<br style='clear: both'/>
  31 +
  32 +<%= render :partial => 'shared/list_groups', :locals => {:profile => user, :groups => @children} %>
... ...
public/stylesheets/application.css
... ... @@ -3598,46 +3598,50 @@ h1#agenda-title {
3598 3598 /* ==> public/stylesheets/controller_memberships.css <== */
3599 3599 /* @import url(profile-list-block.css); ==> BROKEN REFERENCE, OH MY! */
3600 3600  
3601   -.controller-memberships #memberships-index ul {
  3601 +#groups-list {
3602 3602 width: 100%;
3603 3603 padding: 0px;
3604 3604 margin: 0px;
3605 3605 display: block;
3606 3606 }
3607   -.controller-memberships #memberships-index li {
  3607 +
  3608 +#groups-list li {
3608 3609 display: block;
3609 3610 list-style: none;
3610 3611 margin-bottom: 20px background-color: #B8CFE7;
3611 3612 }
3612   -.controller-memberships #memberships-index li .vcard {
  3613 +
  3614 +#groups-list li .vcard {
3613 3615 float: right;
3614 3616 padding: 5px;
3615 3617 margin-bottom: 5px;
3616 3618 margin-left: 10px;
3617 3619 }
3618   -.controller-memberships #memberships-index li .may-clear {
  3620 +#groups-list li .may-clear {
3619 3621 clear: right;
3620 3622 }
3621   -.controller-memberships #memberships-index li .profile-details {
  3623 +
  3624 +#groups-list li .profile-details {
3622 3625 display: block;
3623 3626 padding: 3% 0px 0px 30px;
3624 3627 }
3625   -.controller-memberships .action_memberships_destroy_community .main-block u {
3626   - text-decoration: none;
3627   - border-bottom: 1px dotted red;
3628   -}
3629   -#memberships-index .menu-submenu {
  3628 +
  3629 +#groups-list .menu-submenu {
3630 3630 bottom: 127px;
3631 3631 right: -20px;
3632 3632 }
3633   -#memberships-index .menu-submenu li {
  3633 +
  3634 +#groups-list .menu-submenu li {
3634 3635 border: 0;
3635 3636 background: transparent;
3636 3637 }
3637   -.controller-memberships .button-bar {
  3638 +
  3639 +#groups-list .button-bar {
3638 3640 clear: both;
3639 3641 }
3640   -.controller-memberships #memberships-index li .vcard a.profile_link.url, .controller-memberships #memberships-index li .vcard a.profile_link.url:hover {
  3642 +
  3643 +#groups-list li .vcard a.profile_link.url,
  3644 +#groups-list li .vcard a.profile_link.url:hover {
3641 3645 background: transparent;
3642 3646 border: 0;
3643 3647 text-decoration: none;
... ...
test/functional/enterprise_registration_controller_test.rb
... ... @@ -180,4 +180,27 @@ class EnterpriseRegistrationControllerTest &lt; ActionController::TestCase
180 180 get :index
181 181 assert_equal assigns(:create_enterprise).target, environment
182 182 end
  183 +
  184 + should 'include hidden fields supplied by plugins on enterprise registration' do
  185 + class Plugin1 < Noosfero::Plugin
  186 + def enterprise_registration_hidden_fields
  187 + {'plugin1' => 'Plugin 1'}
  188 + end
  189 + end
  190 +
  191 + class Plugin2 < Noosfero::Plugin
  192 + def enterprise_registration_hidden_fields
  193 + {'plugin2' => 'Plugin 2'}
  194 + end
  195 + end
  196 +
  197 + environment = Environment.default
  198 + environment.enable_plugin(Plugin1.name)
  199 + environment.enable_plugin(Plugin2.name)
  200 +
  201 + get :index
  202 +
  203 + assert_tag :tag => 'input', :attributes => {:id => 'create_enterprise_plugin1', :type => 'hidden', :value => 'Plugin 1'}
  204 + assert_tag :tag => 'input', :attributes => {:id => 'create_enterprise_plugin2', :type => 'hidden', :value => 'Plugin 2'}
  205 + end
183 206 end
... ...
test/functional/memberships_controller_test.rb
... ... @@ -206,4 +206,27 @@ class MembershipsControllerTest &lt; ActionController::TestCase
206 206 assert_no_tag :tag => 'textarea', :attributes => {:name => 'community[description]'}
207 207 end
208 208  
  209 + should 'include hidden fields supplied by plugins on new community' do
  210 + class Plugin1 < Noosfero::Plugin
  211 + def new_community_hidden_fields
  212 + {'plugin1' => 'Plugin 1'}
  213 + end
  214 + end
  215 +
  216 + class Plugin2 < Noosfero::Plugin
  217 + def new_community_hidden_fields
  218 + {'plugin2' => 'Plugin 2'}
  219 + end
  220 + end
  221 +
  222 + environment = Environment.default
  223 + environment.enable_plugin(Plugin1.name)
  224 + environment.enable_plugin(Plugin2.name)
  225 +
  226 + get :new_community, :profile => profile.identifier
  227 +
  228 + assert_tag :tag => 'input', :attributes => {:id => 'community_plugin1', :type => 'hidden', :value => 'Plugin 1'}
  229 + assert_tag :tag => 'input', :attributes => {:id => 'community_plugin2', :type => 'hidden', :value => 'Plugin 2'}
  230 + end
  231 +
209 232 end
... ...
test/unit/person_test.rb
... ... @@ -3,6 +3,10 @@ require File.dirname(__FILE__) + &#39;/../test_helper&#39;
3 3 class PersonTest < ActiveSupport::TestCase
4 4 fixtures :profiles, :users, :environments
5 5  
  6 + def teardown
  7 + Thread.current[:enabled_plugins] = nil
  8 + end
  9 +
6 10 def test_person_must_come_form_the_cration_of_an_user
7 11 p = Person.new(:environment => Environment.default, :name => 'John', :identifier => 'john')
8 12 assert !p.valid?
... ... @@ -1104,6 +1108,18 @@ class PersonTest &lt; ActiveSupport::TestCase
1104 1108 assert_equal [person], Person.members_of(community)
1105 1109 end
1106 1110  
  1111 + should 'be able to pass array to members_of' do
  1112 + person1 = fast_create(Person)
  1113 + community = fast_create(Community)
  1114 + community.add_member(person1)
  1115 + person2 = fast_create(Person)
  1116 + enterprise = fast_create(Enterprise)
  1117 + enterprise.add_member(person2)
  1118 +
  1119 + assert_includes Person.members_of([community, enterprise]), person1
  1120 + assert_includes Person.members_of([community, enterprise]), person2
  1121 + end
  1122 +
1107 1123 should 'find more active people' do
1108 1124 Person.destroy_all
1109 1125 p1 = fast_create(Person)
... ... @@ -1228,4 +1244,26 @@ class PersonTest &lt; ActiveSupport::TestCase
1228 1244  
1229 1245 assert_equivalent [person_scrap,person_activity], person.activities.map { |a| a.klass.constantize.find(a.id) }
1230 1246 end
  1247 +
  1248 + should 'allow plugins to extend person\'s permission access' do
  1249 + person = create_user('some-user').person
  1250 + class Plugin1 < Noosfero::Plugin
  1251 + def has_permission?(person, permission, target)
  1252 + true
  1253 + end
  1254 + end
  1255 +
  1256 + class Plugin2 < Noosfero::Plugin
  1257 + def has_permission?(person, permission, target)
  1258 + false
  1259 + end
  1260 + end
  1261 +
  1262 + e = Environment.default
  1263 + e.enable_plugin(Plugin1.name)
  1264 + e.enable_plugin(Plugin2.name)
  1265 + person.stubs('has_permission_without_plugins?').returns(false)
  1266 +
  1267 + assert person.has_permission?('bli', Profile.new)
  1268 + end
1231 1269 end
... ...
test/unit/plugin_manager_test.rb
... ... @@ -12,7 +12,6 @@ class PluginManagerTest &lt; ActiveSupport::TestCase
12 12 @manager = Noosfero::Plugin::Manager.new(@environment, @controller)
13 13 end
14 14 attr_reader :environment
15   - attr_reader :manager
16 15  
17 16 should 'return the intersection between environment\'s enabled plugins and system available plugins' do
18 17 class Plugin1 < Noosfero::Plugin; end;
... ... @@ -21,6 +20,7 @@ class PluginManagerTest &lt; ActiveSupport::TestCase
21 20 class Plugin4 < Noosfero::Plugin; end;
22 21 environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s, Plugin4.to_s])
23 22 Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin3.to_s, Plugin4.to_s])
  23 + manager = Noosfero::Plugin::Manager.new(@controller)
24 24 plugins = manager.enabled_plugins.map { |instance| instance.class.to_s }
25 25 assert_equal [Plugin1.to_s, Plugin4.to_s], plugins
26 26 end
... ... @@ -49,6 +49,7 @@ class PluginManagerTest &lt; ActiveSupport::TestCase
49 49  
50 50 p1 = Plugin1.new
51 51 p2 = Plugin2.new
  52 + manager = Noosfero::Plugin::Manager.new(@controller)
52 53  
53 54 assert_equal [p1.random_event, p2.random_event], manager.dispatch(:random_event)
54 55 end
... ...
test/unit/profile_test.rb
... ... @@ -3,8 +3,8 @@ require File.dirname(__FILE__) + &#39;/../test_helper&#39;
3 3 class ProfileTest < ActiveSupport::TestCase
4 4 fixtures :profiles, :environments, :users, :roles, :domains
5 5  
6   - def setup
7   - super
  6 + def teardown
  7 + Thread.current[:enabled_plugins] = nil
8 8 end
9 9  
10 10 def test_identifier_validation
... ... @@ -1833,6 +1833,37 @@ class ProfileTest &lt; ActiveSupport::TestCase
1833 1833 assert_equal [], profile.activities
1834 1834 end
1835 1835  
  1836 + should 'merge members of plugins to original members' do
  1837 + original_community = fast_create(Community)
  1838 + community1 = fast_create(Community, :identifier => 'community1')
  1839 + community2 = fast_create(Community, :identifier => 'community2')
  1840 + original_member = fast_create(Person)
  1841 + plugin1_member = fast_create(Person)
  1842 + plugin2_member = fast_create(Person)
  1843 + original_community.add_member(original_member)
  1844 + community1.add_member(plugin1_member)
  1845 + community2.add_member(plugin2_member)
  1846 +
  1847 + class Plugin1 < Noosfero::Plugin
  1848 + def organization_members(profile)
  1849 + Person.members_of(Community.find_by_identifier('community1'))
  1850 + end
  1851 + end
  1852 +
  1853 + class Plugin2 < Noosfero::Plugin
  1854 + def organization_members(profile)
  1855 + Person.members_of(Community.find_by_identifier('community2'))
  1856 + end
  1857 + end
  1858 +
  1859 + original_community.stubs(:enabled_plugins).returns([Plugin1.new, Plugin2.new])
  1860 +
  1861 + assert_includes original_community.members, original_member
  1862 + assert_includes original_community.members, plugin1_member
  1863 + assert_includes original_community.members, plugin2_member
  1864 + assert 3, original_community.members.count
  1865 + end
  1866 +
1836 1867 private
1837 1868  
1838 1869 def assert_invalid_identifier(id)
... ...
vendor/plugins/monkey_patches/methods_from_fake_arel/init.rb 0 → 100644
... ... @@ -0,0 +1,71 @@
  1 +# monkey patch to add fake_arel select, or_scope and where methods
  2 +# this gem requires activesupport-2.3.14 and activerecord-2.3.14
  3 +#
  4 +# https://github.com/gammons/fake_arel
  5 +
  6 +module Rails3Finder
  7 + def self.included(base)
  8 + base.class_eval do
  9 +
  10 + # the default named scopes
  11 + named_scope :offset, lambda {|offset| {:offset => offset}}
  12 + named_scope :limit, lambda {|limit| {:limit => limit}}
  13 + named_scope :includes, lambda { |*includes| { :include => includes }}
  14 + named_scope :order, lambda {|*order| {:order => order.join(',') }}
  15 + named_scope :joins, lambda {|*join| {:joins => join } if join[0]}
  16 + named_scope :from, lambda {|*from| {:from => from }}
  17 + named_scope :having, lambda {|*having| {:having => having }}
  18 + named_scope :group, lambda {|*group| {:group => group.join(',') }}
  19 + named_scope :readonly, lambda {|readonly| {:readonly => readonly }}
  20 + named_scope :lock, lambda {|lock| {:lock => lock }}
  21 +
  22 + def self.select(value = Proc.new)
  23 + if block_given?
  24 + all.select {|*block_args| value.call(*block_args) }
  25 + else
  26 + self.scoped(:select => Array.wrap(value).join(','))
  27 + end
  28 + end
  29 +
  30 + __where_fn = lambda do |*where|
  31 + if where.is_a?(Array) and where.size == 1
  32 + {:conditions => where.first}
  33 + else
  34 + {:conditions => where}
  35 + end
  36 + end
  37 +
  38 + named_scope :where, __where_fn
  39 +
  40 + # Use carefully this method! It might get lost with different classes
  41 + # scopes or different types of joins.
  42 + def self.or_scope(*scopes)
  43 + where = []
  44 + joins = []
  45 + includes = []
  46 +
  47 + # for some reason, flatten is actually executing the scope
  48 + scopes = scopes[0] if scopes.size == 1
  49 + scopes.each do |s|
  50 + s = s.proxy_options
  51 + begin
  52 + where << merge_conditions(s[:conditions])
  53 + rescue NoMethodError
  54 + # I am ActiveRecord::Base. Only my subclasses define merge_conditions:
  55 + where << subclasses.first.merge_conditions(s[:conditions])
  56 + end
  57 + #where << merge_conditions(s[:conditions])
  58 + joins << s[:joins] unless s[:joins].nil?
  59 + includes << s[:include] unless s[:include].nil?
  60 + end
  61 + scoped = self
  62 + scoped = scoped.select("DISTINCT #{self.table_name}.*")
  63 + scoped = scoped.includes(includes.uniq.flatten) unless includes.blank?
  64 + scoped = scoped.joins(joins.uniq.flatten) unless joins.blank?
  65 + scoped.where(where.join(" OR "))
  66 + end
  67 + end
  68 + end
  69 +end
  70 +
  71 +ActiveRecord::Base.send :include, Rails3Finder
... ...