diff --git a/app/models/person.rb b/app/models/person.rb index 3ddeadc..5d3da0e 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -3,9 +3,19 @@ class Person < Profile acts_as_trackable :after_add => Proc.new {|p,t| notify_activity(t)} acts_as_accessor + acts_as_having_hotspots 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 ] } } + def has_permission_with_plugins?(permission, profile) + permissions = [has_permission_without_plugins?(permission, profile)] + permissions += enabled_plugins.map do |plugin| + plugin.has_permission?(self, permission, profile) + end + permissions.include?(true) + end + alias_method_chain :has_permission?, :plugins + def memberships Profile.memberships_of(self) end diff --git a/app/models/profile.rb b/app/models/profile.rb index ac5591d..4685fe5 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -54,6 +54,7 @@ class Profile < ActiveRecord::Base } acts_as_accessible + acts_as_having_hotspots 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 ] } } #FIXME: these will work only if the subclass is already loaded @@ -61,13 +62,24 @@ class Profile < ActiveRecord::Base named_scope :communities, lambda { {:conditions => (Community.send(:subclasses).map(&:name) << 'Community').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} } def members - Person.members_of(self) + scopes = dispatch_scopes(:organization_members, self) + scopes << Person.members_of(self) + scopes.size == 1 ? scopes.first : Person.or_scope(scopes) end def members_count - members.count('DISTINCT(profiles.id)') + members.count end + class << self + def count_with_distinct(*args) + options = args.last || {} + count_without_distinct(:id, {:distinct => true}.merge(options)) + end + alias_method_chain :count, :distinct + end + + def members_by_role(role) Person.members_of(self).all(:conditions => ['role_assignments.role_id = ?', role.id]) end diff --git a/app/models/profile_list_block.rb b/app/models/profile_list_block.rb index 102e249..75fa66c 100644 --- a/app/models/profile_list_block.rb +++ b/app/models/profile_list_block.rb @@ -25,7 +25,7 @@ class ProfileListBlock < Block end def profile_count - profiles.visible.count('DISTINCT(profiles.id)') + profiles.visible.count end # the title of the block. Probably will be overriden in subclasses. diff --git a/app/views/enterprise_registration/basic_information.rhtml b/app/views/enterprise_registration/basic_information.rhtml index 7600470..48b74b3 100644 --- a/app/views/enterprise_registration/basic_information.rhtml +++ b/app/views/enterprise_registration/basic_information.rhtml @@ -28,6 +28,12 @@ <%= hidden_field_tag 'create_enterprise[target_id]', environment.id %> <% end %> + <% @plugins.dispatch(:enterprise_registration_hidden_fields).each do |field| %> + <% field.each do |key, value| %> + <%= f.hidden_field(key, :value => value) %> + <% end %> + <% end %> + <% button_bar do %> <%= submit_button('next', _('Next'), :cancel => {:profile => current_user.person.identifier, :action=>"enterprises", :controller=>"profile"}) %> <% end %> diff --git a/app/views/memberships/new_community.rhtml b/app/views/memberships/new_community.rhtml index 6f6329c..8ebf47c 100644 --- a/app/views/memberships/new_community.rhtml +++ b/app/views/memberships/new_community.rhtml @@ -16,6 +16,12 @@ <%= required f.text_field(:name) %> + <% @plugins.dispatch(:new_community_hidden_fields).each do |field| %> + <% field.each do |key, value| %> + <%= f.hidden_field(key, :value => value) %> + <% end %> + <% end %> + <%= render :partial => 'shared/organization_custom_fields', :locals => { :f => f, :object_name => 'community', :profile => @community } %> <% f.fields_for :image_builder, @community.image do |i| %> diff --git a/lib/noosfero/plugin.rb b/lib/noosfero/plugin.rb index e2c06e5..d9e47a6 100644 --- a/lib/noosfero/plugin.rb +++ b/lib/noosfero/plugin.rb @@ -238,4 +238,29 @@ class Noosfero::Plugin def comment_saved(comment) end + # -> Extends organization list of members + # returns = An instance of ActiveRecord::NamedScope::Scope retrieved through + # Person.members_of method. + def organization_members(organization) + nil + end + + # -> Extends person permission access + # returns = boolean + def has_permission?(person, permission, target) + nil + end + + # -> Adds hidden_fields to the new community view + # returns = {key => value} + def new_community_hidden_fields + nil + end + + # -> Adds hidden_fields to the enterprise registration view + # returns = {key => value} + def enterprise_registration_hidden_fields + nil + end + end diff --git a/test/functional/enterprise_registration_controller_test.rb b/test/functional/enterprise_registration_controller_test.rb index fc875e4..6430fe6 100644 --- a/test/functional/enterprise_registration_controller_test.rb +++ b/test/functional/enterprise_registration_controller_test.rb @@ -178,4 +178,27 @@ all_fixtures get :index assert_equal assigns(:create_enterprise).target, environment end + + should 'include hidden fields supplied by plugins on enterprise registration' do + class Plugin1 < Noosfero::Plugin + def enterprise_registration_hidden_fields + {'plugin1' => 'Plugin 1'} + end + end + + class Plugin2 < Noosfero::Plugin + def enterprise_registration_hidden_fields + {'plugin2' => 'Plugin 2'} + end + end + + environment = Environment.default + environment.enable_plugin(Plugin1.name) + environment.enable_plugin(Plugin2.name) + + get :index + + assert_tag :tag => 'input', :attributes => {:id => 'create_enterprise_plugin1', :type => 'hidden', :value => 'Plugin 1'} + assert_tag :tag => 'input', :attributes => {:id => 'create_enterprise_plugin2', :type => 'hidden', :value => 'Plugin 2'} + end end diff --git a/test/functional/memberships_controller_test.rb b/test/functional/memberships_controller_test.rb index 040b2f6..8535e19 100644 --- a/test/functional/memberships_controller_test.rb +++ b/test/functional/memberships_controller_test.rb @@ -213,4 +213,27 @@ class MembershipsControllerTest < ActionController::TestCase assert_no_tag :tag => 'textarea', :attributes => {:name => 'community[description]'} end + should 'include hidden fields supplied by plugins on new community' do + class Plugin1 < Noosfero::Plugin + def new_community_hidden_fields + {'plugin1' => 'Plugin 1'} + end + end + + class Plugin2 < Noosfero::Plugin + def new_community_hidden_fields + {'plugin2' => 'Plugin 2'} + end + end + + environment = Environment.default + environment.enable_plugin(Plugin1.name) + environment.enable_plugin(Plugin2.name) + + get :new_community, :profile => profile.identifier + + assert_tag :tag => 'input', :attributes => {:id => 'community_plugin1', :type => 'hidden', :value => 'Plugin 1'} + assert_tag :tag => 'input', :attributes => {:id => 'community_plugin2', :type => 'hidden', :value => 'Plugin 2'} + end + end diff --git a/test/unit/person_test.rb b/test/unit/person_test.rb index c203f35..b2923d9 100644 --- a/test/unit/person_test.rb +++ b/test/unit/person_test.rb @@ -1247,4 +1247,26 @@ class PersonTest < ActiveSupport::TestCase assert !person.visible assert_not_equal password, person.user.password end + + should 'allow plugins to extend person\'s permission access' do + person = create_user('some-user').person + class Plugin1 < Noosfero::Plugin + def has_permission?(person, permission, target) + true + end + end + + class Plugin2 < Noosfero::Plugin + def has_permission?(person, permission, target) + false + end + end + + e = Environment.default + e.enable_plugin(Plugin1.name) + e.enable_plugin(Plugin2.name) + person.stubs('has_permission_without_plugins?').returns(false) + + assert person.has_permission?('bli', Profile.new) + end end diff --git a/test/unit/profile_test.rb b/test/unit/profile_test.rb index d53b2fc..f86a642 100644 --- a/test/unit/profile_test.rb +++ b/test/unit/profile_test.rb @@ -1768,6 +1768,37 @@ class ProfileTest < ActiveSupport::TestCase end end + should 'merge members of plugins to original members' do + original_community = fast_create(Community) + community1 = fast_create(Community, :identifier => 'community1') + community2 = fast_create(Community, :identifier => 'community2') + original_member = fast_create(Person) + plugin1_member = fast_create(Person) + plugin2_member = fast_create(Person) + original_community.add_member(original_member) + community1.add_member(plugin1_member) + community2.add_member(plugin2_member) + + class Plugin1 < Noosfero::Plugin + def organization_members(profile) + Person.members_of(Community.find_by_identifier('community1')) + end + end + + class Plugin2 < Noosfero::Plugin + def organization_members(profile) + Person.members_of(Community.find_by_identifier('community2')) + end + end + + original_community.stubs(:enabled_plugins).returns([Plugin1.new, Plugin2.new]) + + assert_includes original_community.members, original_member + assert_includes original_community.members, plugin1_member + assert_includes original_community.members, plugin2_member + assert 3, original_community.members.count + end + private def assert_invalid_identifier(id) diff --git a/vendor/plugins/monkey_patches/methods_from_fake_arel/init.rb b/vendor/plugins/monkey_patches/methods_from_fake_arel/init.rb new file mode 100644 index 0000000..817f52b --- /dev/null +++ b/vendor/plugins/monkey_patches/methods_from_fake_arel/init.rb @@ -0,0 +1,71 @@ +# monkey patch to add fake_arel select, or_scope and where methods +# this gem requires activesupport-2.3.14 and activerecord-2.3.14 +# +# https://github.com/gammons/fake_arel + +module Rails3Finder + def self.included(base) + base.class_eval do + + # the default named scopes + named_scope :offset, lambda {|offset| {:offset => offset}} + named_scope :limit, lambda {|limit| {:limit => limit}} + named_scope :includes, lambda { |*includes| { :include => includes }} + named_scope :order, lambda {|*order| {:order => order.join(',') }} + named_scope :joins, lambda {|*join| {:joins => join } if join[0]} + named_scope :from, lambda {|*from| {:from => from }} + named_scope :having, lambda {|*having| {:having => having }} + named_scope :group, lambda {|*group| {:group => group.join(',') }} + named_scope :readonly, lambda {|readonly| {:readonly => readonly }} + named_scope :lock, lambda {|lock| {:lock => lock }} + + def self.select(value = Proc.new) + if block_given? + all.select {|*block_args| value.call(*block_args) } + else + self.scoped(:select => Array.wrap(value).join(',')) + end + end + + __where_fn = lambda do |*where| + if where.is_a?(Array) and where.size == 1 + {:conditions => where.first} + else + {:conditions => where} + end + end + + named_scope :where, __where_fn + + # Use carefully this method! It might get lost with different classes + # scopes or different types of joins. + def self.or_scope(*scopes) + where = [] + joins = [] + includes = [] + + # for some reason, flatten is actually executing the scope + scopes = scopes[0] if scopes.size == 1 + scopes.each do |s| + s = s.proxy_options + begin + where << merge_conditions(s[:conditions]) + rescue NoMethodError + # I am ActiveRecord::Base. Only my subclasses define merge_conditions: + where << subclasses.first.merge_conditions(s[:conditions]) + end + #where << merge_conditions(s[:conditions]) + joins << s[:joins] unless s[:joins].nil? + includes << s[:include] unless s[:include].nil? + end + scoped = self + scoped = scoped.select("DISTINCT #{self.table_name}.*") + scoped = scoped.includes(includes.uniq.flatten) unless includes.blank? + scoped = scoped.joins(joins.uniq.flatten) unless joins.blank? + scoped.where(where.join(" OR ")) + end + end + end +end + +ActiveRecord::Base.send :include, Rails3Finder -- libgit2 0.21.2