Commit d323bd53b09f3a1f8f81a612dfaf0299142670de
Exists in
master
and in
29 other branches
Merge commit 'refs/merge-requests/181' of git://gitorious.org/noosfero/noosfero …
…into merge-requests/181 Conflicts: app/controllers/application_controller.rb app/helpers/application_helper.rb app/models/person.rb app/views/enterprise_registration/basic_information.rhtml lib/noosfero/plugin.rb public/stylesheets/application.css test/unit/person_test.rb test/unit/profile_test.rb
Showing
39 changed files
with
1096 additions
and
70 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 < 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 < 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 < 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 < 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
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| %> | ... | ... |
... | ... | @@ -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
lib/noosfero/plugin.rb
... | ... | @@ -256,4 +256,29 @@ class Noosfero::Plugin |
256 | 256 | nil |
257 | 257 | end |
258 | 258 | |
259 | + # -> Extends organization list of members | |
260 | + # returns = An instance of ActiveRecord::NamedScope::Scope retrieved through | |
261 | + # Person.members_of method. | |
262 | + def organization_members(organization) | |
263 | + nil | |
264 | + end | |
265 | + | |
266 | + # -> Extends person permission access | |
267 | + # returns = boolean | |
268 | + def has_permission?(person, permission, target) | |
269 | + nil | |
270 | + end | |
271 | + | |
272 | + # -> Adds hidden_fields to the new community view | |
273 | + # returns = {key => value} | |
274 | + def new_community_hidden_fields | |
275 | + nil | |
276 | + end | |
277 | + | |
278 | + # -> Adds hidden_fields to the enterprise registration view | |
279 | + # returns = {key => value} | |
280 | + def enterprise_registration_hidden_fields | |
281 | + nil | |
282 | + end | |
283 | + | |
259 | 284 | end | ... | ... |
... | ... | @@ -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/context.rb
lib/noosfero/plugin/manager.rb
1 | 1 | class Noosfero::Plugin::Manager |
2 | 2 | |
3 | - attr_reader :context | |
3 | + extend ActsAsHavingHotspots::ClassMethods | |
4 | + acts_as_having_hotspots | |
4 | 5 | |
5 | - def initialize(controller) | |
6 | - @context = Noosfero::Plugin::Context.new(controller) | |
7 | - end | |
6 | + attr_reader :context | |
8 | 7 | |
8 | + delegate :environment, :to => :context | |
9 | 9 | delegate :each, :to => :enabled_plugins |
10 | 10 | include Enumerable |
11 | 11 | |
12 | - # Dispatches +event+ to each enabled plugin and collect the results. | |
13 | - # | |
14 | - # Returns an Array containing the objects returned by the event method in | |
15 | - # each plugin. This array is compacted (i.e. nils are removed) and flattened | |
16 | - # (i.e. elements of arrays are added to the resulting array). For example, if | |
17 | - # the enabled plugins return 1, 0, nil, and [1,2,3], then this method will | |
18 | - # return [1,0,1,2,3] | |
19 | - # | |
20 | - def dispatch(event, *args) | |
21 | - map { |plugin| plugin.send(event, *args) }.compact.flatten | |
22 | - end | |
23 | - | |
24 | - def enabled_plugins | |
25 | - @enabled_plugins ||= (Noosfero::Plugin.all & context.environment.enabled_plugins).map do |plugin| | |
26 | - p = plugin.constantize.new | |
27 | - p.context = context | |
28 | - p | |
12 | + def initialize(controller) | |
13 | + @context = Noosfero::Plugin::Context.new(controller) | |
14 | + Thread.current[:enabled_plugins] = (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin_name| | |
15 | + plugin = plugin_name.constantize.new | |
16 | + plugin.context = context | |
17 | + plugin | |
29 | 18 | end |
30 | 19 | end |
31 | 20 | ... | ... |
plugins/sub_organizations/controllers/sub_organizations_plugin_myprofile_controller.rb
0 → 100644
... | ... | @@ -0,0 +1,53 @@ |
1 | +class SubOrganizationsPluginMyprofileController < MyProfileController | |
2 | + append_view_path File.join(File.dirname(__FILE__) + '/../views') | |
3 | + | |
4 | + before_filter :organizations_only | |
5 | + | |
6 | + def index | |
7 | + @children = SubOrganizationsPlugin::Relation.children(profile) | |
8 | + @tokenized_children = prepare_to_token_input(@children) | |
9 | + @pending_children = SubOrganizationsPlugin::ApprovePaternityRelation.pending_children(profile) | |
10 | + if request.post? | |
11 | + begin | |
12 | + original = SubOrganizationsPlugin::Relation.children(profile) | |
13 | + requested = Organization.find(params[:q].split(',')) | |
14 | + added = requested - original | |
15 | + removed = original - requested | |
16 | + added.each do |organization| | |
17 | + if current_person.has_permission?('perform_task',organization) | |
18 | + SubOrganizationsPlugin::Relation.add_children(profile, organization) | |
19 | + else | |
20 | + SubOrganizationsPlugin::ApprovePaternity.create!(:requestor => user, :temp_parent_type => profile.class.name, :temp_parent_id => profile.id, :target => organization) | |
21 | + end | |
22 | + end | |
23 | + SubOrganizationsPlugin::Relation.remove_children(profile,removed) | |
24 | + session[:notice] = _('Sub-organizations updated') | |
25 | + rescue Exception => exception | |
26 | + logger.error(exception.to_s) | |
27 | + session[:notice] = _('Sub-organizations could not be updated') | |
28 | + end | |
29 | + redirect_to :action => :index | |
30 | + end | |
31 | + end | |
32 | + | |
33 | + def search_organization | |
34 | + render :text => prepare_to_token_input(environment.organizations.find(:all, :conditions => | |
35 | + ["(LOWER(name) LIKE ? OR LOWER(identifier) LIKE ?) | |
36 | + AND (identifier NOT LIKE ?) AND (id != ?)", | |
37 | + "%#{params[:q]}%", "%#{params[:q]}%", "%_template", profile.id]). | |
38 | + select { |organization| | |
39 | + SubOrganizationsPlugin::Relation.children(organization).blank? && | |
40 | + !SubOrganizationsPlugin::ApprovePaternityRelation.pending_children(profile).include?(organization) | |
41 | + }).to_json | |
42 | + end | |
43 | + | |
44 | + private | |
45 | + | |
46 | + def organizations_only | |
47 | + render_not_found if !profile.organization? | |
48 | + end | |
49 | + | |
50 | + def prepare_to_token_input(array) | |
51 | + array.map { |object| {:id => object.id, :name => object.name} } | |
52 | + end | |
53 | +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
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/test/functional/sub_organizations_plugin_myprofile_controller_test.rb
0 → 100644
... | ... | @@ -0,0 +1,89 @@ |
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 | +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,31 @@ |
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 | + <%= token_input_field_tag(:q, 'search-organization', {:action => 'search_organization'}, | |
19 | + { :focus => true, | |
20 | + :hint_text => _('Type in a search term for a group'), | |
21 | + :pre_populate => @tokenized_children}) %> | |
22 | + | |
23 | + <% button_bar do %> | |
24 | + <%= submit_button('save', _('Save'))%> | |
25 | + <%= button('cancel', _('Cancel'), {:controller => 'profile_editor'})%> | |
26 | + <% end %> | |
27 | +<% end %> | |
28 | + | |
29 | +<br style='clear: both'/> | |
30 | + | |
31 | +<%= render :partial => 'shared/list_groups', :locals => {:profile => user, :groups => @children} %> | ... | ... |
public/stylesheets/application.css
... | ... | @@ -3602,46 +3602,50 @@ h1#agenda-title { |
3602 | 3602 | /* ==> public/stylesheets/controller_memberships.css <== */ |
3603 | 3603 | /* @import url(profile-list-block.css); ==> BROKEN REFERENCE, OH MY! */ |
3604 | 3604 | |
3605 | -.controller-memberships #memberships-index ul { | |
3605 | +#groups-list { | |
3606 | 3606 | width: 100%; |
3607 | 3607 | padding: 0px; |
3608 | 3608 | margin: 0px; |
3609 | 3609 | display: block; |
3610 | 3610 | } |
3611 | -.controller-memberships #memberships-index li { | |
3611 | + | |
3612 | +#groups-list li { | |
3612 | 3613 | display: block; |
3613 | 3614 | list-style: none; |
3614 | 3615 | margin-bottom: 20px background-color: #B8CFE7; |
3615 | 3616 | } |
3616 | -.controller-memberships #memberships-index li .vcard { | |
3617 | + | |
3618 | +#groups-list li .vcard { | |
3617 | 3619 | float: right; |
3618 | 3620 | padding: 5px; |
3619 | 3621 | margin-bottom: 5px; |
3620 | 3622 | margin-left: 10px; |
3621 | 3623 | } |
3622 | -.controller-memberships #memberships-index li .may-clear { | |
3624 | +#groups-list li .may-clear { | |
3623 | 3625 | clear: right; |
3624 | 3626 | } |
3625 | -.controller-memberships #memberships-index li .profile-details { | |
3627 | + | |
3628 | +#groups-list li .profile-details { | |
3626 | 3629 | display: block; |
3627 | 3630 | padding: 3% 0px 0px 30px; |
3628 | 3631 | } |
3629 | -.controller-memberships .action_memberships_destroy_community .main-block u { | |
3630 | - text-decoration: none; | |
3631 | - border-bottom: 1px dotted red; | |
3632 | -} | |
3633 | -#memberships-index .menu-submenu { | |
3632 | + | |
3633 | +#groups-list .menu-submenu { | |
3634 | 3634 | bottom: 127px; |
3635 | 3635 | right: -20px; |
3636 | 3636 | } |
3637 | -#memberships-index .menu-submenu li { | |
3637 | + | |
3638 | +#groups-list .menu-submenu li { | |
3638 | 3639 | border: 0; |
3639 | 3640 | background: transparent; |
3640 | 3641 | } |
3641 | -.controller-memberships .button-bar { | |
3642 | + | |
3643 | +#groups-list .button-bar { | |
3642 | 3644 | clear: both; |
3643 | 3645 | } |
3644 | -.controller-memberships #memberships-index li .vcard a.profile_link.url, .controller-memberships #memberships-index li .vcard a.profile_link.url:hover { | |
3646 | + | |
3647 | +#groups-list li .vcard a.profile_link.url, | |
3648 | +#groups-list li .vcard a.profile_link.url:hover { | |
3645 | 3649 | background: transparent; |
3646 | 3650 | border: 0; |
3647 | 3651 | text-decoration: none; | ... | ... |
test/functional/enterprise_registration_controller_test.rb
... | ... | @@ -180,4 +180,27 @@ class EnterpriseRegistrationControllerTest < 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 < 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__) + '/../test_helper' |
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 < 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 < 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
... | ... | @@ -10,10 +10,8 @@ class PluginManagerTest < ActiveSupport::TestCase |
10 | 10 | @controller.stubs(:response).returns() |
11 | 11 | @controller.stubs(:environment).returns(@environment) |
12 | 12 | @controller.stubs(:params).returns() |
13 | - @manager = Noosfero::Plugin::Manager.new(@controller) | |
14 | 13 | end |
15 | 14 | attr_reader :environment |
16 | - attr_reader :manager | |
17 | 15 | |
18 | 16 | should 'return the intersection between environment\'s enabled plugins and system available plugins' do |
19 | 17 | class Plugin1 < Noosfero::Plugin; end; |
... | ... | @@ -22,6 +20,7 @@ class PluginManagerTest < ActiveSupport::TestCase |
22 | 20 | class Plugin4 < Noosfero::Plugin; end; |
23 | 21 | environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s, Plugin4.to_s]) |
24 | 22 | Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin3.to_s, Plugin4.to_s]) |
23 | + manager = Noosfero::Plugin::Manager.new(@controller) | |
25 | 24 | plugins = manager.enabled_plugins.map { |instance| instance.class.to_s } |
26 | 25 | assert_equal [Plugin1.to_s, Plugin4.to_s], plugins |
27 | 26 | end |
... | ... | @@ -50,6 +49,7 @@ class PluginManagerTest < ActiveSupport::TestCase |
50 | 49 | |
51 | 50 | p1 = Plugin1.new |
52 | 51 | p2 = Plugin2.new |
52 | + manager = Noosfero::Plugin::Manager.new(@controller) | |
53 | 53 | |
54 | 54 | assert_equal [p1.random_event, p2.random_event], manager.dispatch(:random_event) |
55 | 55 | end | ... | ... |
test/unit/profile_test.rb
... | ... | @@ -3,8 +3,8 @@ require File.dirname(__FILE__) + '/../test_helper' |
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 < 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 | ... | ... |