Commit 77d6fa0d4dbace32bc2ab87ac88e8bb657859c25
Committed by
Antonio Terceiro
1 parent
445b9833
Exists in
master
and in
27 other branches
Add Profile Members Headlines plugin
Showing
15 changed files
with
387 additions
and
2 deletions
Show diff stats
app/models/person.rb
... | ... | @@ -21,6 +21,12 @@ class Person < Profile |
21 | 21 | { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => [conditions] } |
22 | 22 | } |
23 | 23 | |
24 | + scope :by_role, lambda { |roles| | |
25 | + roles = [roles] unless roles.kind_of?(Array) | |
26 | + { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ['role_assignments.role_id IN (?)', | |
27 | +roles] } | |
28 | + } | |
29 | + | |
24 | 30 | def has_permission_with_plugins?(permission, profile) |
25 | 31 | permissions = [has_permission_without_plugins?(permission, profile)] |
26 | 32 | permissions += plugins.map do |plugin| | ... | ... |
app/models/profile.rb
... | ... | @@ -108,8 +108,8 @@ class Profile < ActiveRecord::Base |
108 | 108 | alias_method_chain :count, :distinct |
109 | 109 | end |
110 | 110 | |
111 | - def members_by_role(role) | |
112 | - Person.members_of(self).all(:conditions => ['role_assignments.role_id = ?', role.id]) | |
111 | + def members_by_role(roles) | |
112 | + Person.members_of(self).by_role(roles) | |
113 | 113 | end |
114 | 114 | |
115 | 115 | acts_as_having_boxes | ... | ... |
... | ... | @@ -0,0 +1,38 @@ |
1 | +README - Profile Members Headlines (ProfileMembersHeadlines Plugin) | |
2 | +=================================================================== | |
3 | + | |
4 | +ProfileMembersHeadlines is a plugin that allow users to add a block that | |
5 | +displays the most recent post from members with the defined roles. | |
6 | + | |
7 | +The user also can configure the limit of headlines. | |
8 | + | |
9 | +This block will be available for all layout columns of communities and enterprises. | |
10 | + | |
11 | +INSTALL | |
12 | +======= | |
13 | + | |
14 | +Enable Plugin | |
15 | +------------- | |
16 | + | |
17 | +Also, you need to enable ProfileMembersHeadlines Plugin at you Noosfero: | |
18 | + | |
19 | +cd <your_noosfero_dir> | |
20 | +./script/noosfero-plugins enable profile_members_headlines | |
21 | + | |
22 | +Active Plugin | |
23 | +------------- | |
24 | + | |
25 | +As a Noosfero administrator user, go to administrator panel: | |
26 | + | |
27 | +- Click on "Enable/disable plugins" option | |
28 | +- Click on "Profile Members Headlines Plugin" checkbox | |
29 | + | |
30 | +Running DisplayContent tests | |
31 | +-------------------- | |
32 | + | |
33 | +$ rake test:noosfero_plugins:profile_members_headlines_plugin | |
34 | + | |
35 | +LICENSE | |
36 | +======= | |
37 | + | |
38 | +See Noosfero license. | ... | ... |
plugins/profile_members_headlines/lib/profile_members_headlines_block.rb
0 → 100644
... | ... | @@ -0,0 +1,43 @@ |
1 | +class ProfileMembersHeadlinesBlock < Block | |
2 | + | |
3 | + settings_items :interval, :type => 'integer', :default => 10 | |
4 | + settings_items :limit, :type => 'integer', :default => 10 | |
5 | + settings_items :navigation, :type => 'boolean', :default => true | |
6 | + settings_items :filtered_roles, :type => Array, :default => [] | |
7 | + | |
8 | + attr_accessible :interval, :limit, :navigation, :filtered_roles | |
9 | + | |
10 | + def self.description | |
11 | + _('Display headlines from members of a community') | |
12 | + end | |
13 | + | |
14 | + def help | |
15 | + _('This block displays one post from members of a community.') | |
16 | + end | |
17 | + | |
18 | + include Noosfero::Plugin::HotSpot | |
19 | + | |
20 | + def default_title | |
21 | + _('Profile members headlines') | |
22 | + end | |
23 | + | |
24 | + def filtered_roles=(array) | |
25 | + self.settings[:filtered_roles] = array.map(&:to_i).select { |r| !r.to_i.zero? } | |
26 | + end | |
27 | + | |
28 | + def authors_list | |
29 | + result = owner.members_by_role(filtered_roles).public.includes([:image,:domains,:preferred_domain,:environment]).order('updated_at DESC') | |
30 | + | |
31 | + result.all(:limit => limit * 5).select { |p| p.has_headline? | |
32 | +}.slice(0..limit-1) | |
33 | + end | |
34 | + | |
35 | + def content(args={}) | |
36 | + block = self | |
37 | + members = authors_list | |
38 | + proc do | |
39 | + render :file => 'blocks/headlines', :locals => { :block => block, :members => members } | |
40 | + end | |
41 | + end | |
42 | + | |
43 | +end | ... | ... |
plugins/profile_members_headlines/lib/profile_members_headlines_plugin.rb
0 → 100644
... | ... | @@ -0,0 +1,23 @@ |
1 | +require_dependency File.dirname(__FILE__) + '/profile_members_headlines_block' | |
2 | +require 'ext/person' | |
3 | + | |
4 | +class ProfileMembersHeadlinesPlugin < Noosfero::Plugin | |
5 | + | |
6 | + def self.plugin_name | |
7 | + "Profile Members Headlines Plugin" | |
8 | + end | |
9 | + | |
10 | + def self.plugin_description | |
11 | + _("A plugin that adds a block where you can display posts from members.") | |
12 | + end | |
13 | + | |
14 | + def self.extra_blocks | |
15 | + { ProfileMembersHeadlinesBlock => { :type => [Community], :position => | |
16 | +['1'] }} | |
17 | + end | |
18 | + | |
19 | + def stylesheet? | |
20 | + true | |
21 | + end | |
22 | + | |
23 | +end | ... | ... |
379 Bytes
... | ... | @@ -0,0 +1,59 @@ |
1 | +.profile-members-headlines-block { | |
2 | + width: 100%; | |
3 | +} | |
4 | + | |
5 | +.profile-members-headlines-block .headlines-container { | |
6 | + height: 180px; | |
7 | +} | |
8 | + | |
9 | +.profile-members-headlines-block .headlines-container .author, | |
10 | +.profile-members-headlines-block .headlines-container .post { | |
11 | + vertical-align: top; | |
12 | + min-width: 150px; | |
13 | +} | |
14 | + | |
15 | +.profile-members-headlines-block .headlines-container .author { | |
16 | + position: absolute; | |
17 | +} | |
18 | + | |
19 | +.profile-members-headlines-block .headlines-container .author p { | |
20 | + text-align: center; | |
21 | +} | |
22 | + | |
23 | +.profile-members-headlines-block .headlines-container .post { | |
24 | + margin-left: 160px; | |
25 | +} | |
26 | + | |
27 | +.profile-members-headlines-block #content .headlines-container h4 { | |
28 | + margin-top: 15px; | |
29 | + font-weight: bold; | |
30 | +} | |
31 | + | |
32 | +.profile-members-headlines-block .headlines-container a { | |
33 | + text-decoration: none; | |
34 | +} | |
35 | + | |
36 | +.profile-members-headlines-block .headlines-container a:hover { | |
37 | + text-decoration: underline; | |
38 | +} | |
39 | + | |
40 | +.profile-members-headlines-block .headlines-container .post .date { | |
41 | + margin-top: 15px; | |
42 | +} | |
43 | + | |
44 | +.profile-members-headlines-block .headlines-block-pager { | |
45 | + text-align: center; | |
46 | +} | |
47 | + | |
48 | +.profile-members-headlines-block .headlines-block-pager a { | |
49 | + padding: 0px 5px; | |
50 | +} | |
51 | + | |
52 | +.profile-members-headlines-block .headlines-block-pager a.activeSlide { | |
53 | + text-decoration: none; | |
54 | +} | |
55 | + | |
56 | +.profile-members-headlines-block .headlines-block-pager a.activeSlide:visited, | |
57 | +.profile-members-headlines-block .headlines-block-pager a.activeSlide { | |
58 | + color: #000; | |
59 | +} | ... | ... |
... | ... | @@ -0,0 +1 @@ |
1 | +require File.dirname(__FILE__) + '/../../../test/test_helper' | ... | ... |
plugins/profile_members_headlines/test/unit/profile_members_headlines_block_test.rb
0 → 100644
... | ... | @@ -0,0 +1,81 @@ |
1 | +require 'test_helper' | |
2 | + | |
3 | +class ProfileMembersHeadlinesBlockTest < ActiveSupport::TestCase | |
4 | + | |
5 | + include Noosfero::Plugin::HotSpot | |
6 | + | |
7 | + def setup | |
8 | + @environment = fast_create(Environment) | |
9 | + @environment.enable_plugin(ProfileMembersHeadlinesPlugin) | |
10 | + | |
11 | + @member1 = fast_create(Person) | |
12 | + @member2 = fast_create(Person) | |
13 | + @community = fast_create(Community) | |
14 | + community.add_member member1 | |
15 | + community.add_member member2 | |
16 | + end | |
17 | + attr_accessor :environment, :community, :member1, :member2 | |
18 | + | |
19 | + should 'inherit from Block' do | |
20 | + assert_kind_of Block, ProfileMembersHeadlinesBlock.new | |
21 | + end | |
22 | + | |
23 | + should 'describe itself' do | |
24 | + assert_not_equal Block.description, ProfileMembersHeadlinesBlock.description | |
25 | + end | |
26 | + | |
27 | + should 'provide a default title' do | |
28 | + assert_not_equal Block.new.default_title, ProfileMembersHeadlinesBlock.new.default_title | |
29 | + end | |
30 | + | |
31 | + should 'not have authors if they have no blog' do | |
32 | + block = ProfileMembersHeadlinesBlock.create | |
33 | + block.stubs(:owner).returns(community) | |
34 | + | |
35 | + self.expects(:render).with(:file => 'blocks/headlines', :locals => { :block => block, :members => []}).returns('file-without-authors-and-headlines') | |
36 | + assert_equal 'file-without-authors-and-headlines', instance_eval(&block.content) | |
37 | + end | |
38 | + | |
39 | + should 'display headlines file' do | |
40 | + block = ProfileMembersHeadlinesBlock.create | |
41 | + block.stubs(:owner).returns(community) | |
42 | + blog = fast_create(Blog, :profile_id => member1.id) | |
43 | + post = fast_create(TinyMceArticle, :name => 'headlines', :profile_id => member1.id, :parent_id => blog.id) | |
44 | + self.expects(:render).with(:file => 'blocks/headlines', :locals => { :block => block, :members => []}).returns('file-with-authors-and-headlines') | |
45 | + assert_equal 'file-with-authors-and-headlines', instance_eval(&block.content) | |
46 | + end | |
47 | + | |
48 | + should 'select only authors with articles and selected roles to display' do | |
49 | + role = Role.create!(:name => 'role1') | |
50 | + community.affiliate(member1, role) | |
51 | + block = ProfileMembersHeadlinesBlock.new(:limit => 1, :filtered_roles => [role.id]) | |
52 | + block.expects(:owner).returns(community) | |
53 | + blog = fast_create(Blog, :profile_id => member1.id) | |
54 | + post = fast_create(TinyMceArticle, :name => 'headlines', :profile_id => member1.id, :parent_id => blog.id) | |
55 | + assert_equal [member1], block.authors_list | |
56 | + end | |
57 | + | |
58 | + should 'not select private authors to display' do | |
59 | + block = ProfileMembersHeadlinesBlock.new(:limit => 1) | |
60 | + block.expects(:owner).returns(community) | |
61 | + private_author = fast_create(Person, :public_profile => false) | |
62 | + blog = fast_create(Blog, :profile_id => private_author.id) | |
63 | + post = fast_create(TinyMceArticle, :name => 'headlines', :profile_id => private_author.id, :parent_id => blog.id) | |
64 | + assert_equal [], block.authors_list | |
65 | + end | |
66 | + | |
67 | + should 'filter authors by roles to display' do | |
68 | + role = Role.create!(:name => 'role1') | |
69 | + author = fast_create(Person) | |
70 | + community.affiliate(author, role) | |
71 | + | |
72 | + block = ProfileMembersHeadlinesBlock.new(:limit => 3, :filtered_roles => | |
73 | +[role.id]) | |
74 | + block.stubs(:owner).returns(community) | |
75 | + community.members.each do |member| | |
76 | + blog = fast_create(Blog, :profile_id => member.id) | |
77 | + post = fast_create(TinyMceArticle, :name => 'headlines', :profile_id => member.id, :parent_id => blog.id) | |
78 | + end | |
79 | + assert_equal [author], block.authors_list | |
80 | + end | |
81 | +end | ... | ... |
plugins/profile_members_headlines/test/unit/profile_members_headlines_plugin_test.rb
0 → 100644
... | ... | @@ -0,0 +1,41 @@ |
1 | +require 'test_helper' | |
2 | + | |
3 | +class ProfileMembersHeadlinesPluginTest < ActiveSupport::TestCase | |
4 | + | |
5 | + include Noosfero::Plugin::HotSpot | |
6 | + | |
7 | + def setup | |
8 | + @environment = fast_create(Environment) | |
9 | + @environment.enable_plugin(ProfileMembersHeadlinesPlugin) | |
10 | + end | |
11 | + attr_accessor :environment | |
12 | + | |
13 | + should 'has a name' do | |
14 | + assert_not_equal Noosfero::Plugin.plugin_name, ProfileMembersHeadlinesPlugin.plugin_name | |
15 | + end | |
16 | + | |
17 | + should 'describe itself' do | |
18 | + assert_not_equal Noosfero::Plugin.plugin_description, ProfileMembersHeadlinesPlugin.plugin_description | |
19 | + end | |
20 | + | |
21 | + should 'return ProfileMembersHeadlinesBlock in extra_blocks class method' do | |
22 | + assert ProfileMembersHeadlinesPlugin.extra_blocks.keys.include?(ProfileMembersHeadlinesBlock) | |
23 | + end | |
24 | + | |
25 | + should 'ProfileMembersHeadlinesBlock not available for environment' do | |
26 | + assert_not_includes plugins.dispatch(:extra_blocks, :type => Environment), ProfileMembersHeadlinesBlock | |
27 | + end | |
28 | + | |
29 | + should 'ProfileMembersHeadlinesBlock not available for people' do | |
30 | + assert_not_includes plugins.dispatch(:extra_blocks, :type => Person), ProfileMembersHeadlinesBlock | |
31 | + end | |
32 | + | |
33 | + should "ProfileMembersHeadlinesBlock be available for community" do | |
34 | + assert_includes plugins.dispatch(:extra_blocks, :type => Community), ProfileMembersHeadlinesBlock | |
35 | + end | |
36 | + | |
37 | + should 'has stylesheet' do | |
38 | + assert ProfileMembersHeadlinesPlugin.new.stylesheet? | |
39 | + end | |
40 | + | |
41 | +end | ... | ... |
plugins/profile_members_headlines/views/blocks/headlines.html.erb
0 → 100644
... | ... | @@ -0,0 +1,39 @@ |
1 | +<%= block_title(block.title) %> | |
2 | + | |
3 | +<% unless members.empty? %> | |
4 | + <div class='headlines-container'> | |
5 | + <% members.each do |member| %> | |
6 | + <div> | |
7 | + <% headline = member.headline %> | |
8 | + <%= link_to_profile(profile_image(member, :big) + content_tag(:p, member.short_name), member.identifier, {:class => 'author'}) %> | |
9 | + <div class='post'> | |
10 | + <h4><%= link_to(headline.title, headline.url, :class => 'title') %></h4> | |
11 | + <div class='lead'> | |
12 | + <%= headline.short_lead %> | |
13 | + </div> | |
14 | + <div class='date'> | |
15 | + <%= show_date(headline.published_at) %> | |
16 | + </div> | |
17 | + <div class='tags'> | |
18 | + <%= headline.tags.map { |t| link_to(t, :controller => 'profile', :profile => member.identifier, :action => 'tags', :id => t.name ) }.join("\n") %> | |
19 | + </div> | |
20 | + </div> | |
21 | + </div> | |
22 | + <% end %> | |
23 | + </div> | |
24 | + <% if block.navigation %> | |
25 | + <div class='headlines-block-pager'> | |
26 | + </div> | |
27 | + <% end %> | |
28 | + | |
29 | + <script> | |
30 | + (function($) { | |
31 | + var options = {fx: 'fade', pause: 1, fastOnEvent: 1, timeout: <%= block.interval * 1000 %>}; | |
32 | + options.pager = '#block-<%= block.id %> .headlines-block-pager'; | |
33 | + $('#block-<%= block.id %> .headlines-container').cycle(options); | |
34 | + })(jQuery); | |
35 | + </script> | |
36 | +<% else %> | |
37 | + <em><%= _('No headlines to be shown.') %></em> | |
38 | +<% end %> | |
39 | + | ... | ... |
plugins/profile_members_headlines/views/box_organizer/_profile_members_headlines_block.html.erb
0 → 100644
... | ... | @@ -0,0 +1,13 @@ |
1 | +<div id="profile_members_headlines_plugin"> | |
2 | + | |
3 | + <%= labelled_form_field _('Headlines transition:'), select('block', 'interval', [[_('No automatic transition'), 0]] + [1, 2, 3, 4, 5, 10, 20, 30, 60].map {|item| [n_('Every 1 second', 'Every %d seconds', item) % item, item]}) %> | |
4 | + | |
5 | + <%= labelled_form_field check_box(:block, :navigation) + _('Display navigation buttons'), '' %> | |
6 | + <%= labelled_form_field _('Limit of headlines'), text_field(:block, :limit, :size => 3) %> | |
7 | + | |
8 | + <%= label :block, :filtered_roles, _('Choose which roles should be displayed:'), :class => 'formlabel' %> | |
9 | + | |
10 | + <% Profile::Roles.organization_member_roles(environment).each do |role| %> | |
11 | + <%= labelled_check_box(role.name, 'block[filtered_roles][]', role.id, @block.filtered_roles.include?(role.id)) %> | |
12 | + <% end %> | |
13 | +</div> | ... | ... |
test/unit/organization_test.rb
... | ... | @@ -383,6 +383,33 @@ class OrganizationTest < ActiveSupport::TestCase |
383 | 383 | assert !organization.errors[:cnpj.to_s].present? |
384 | 384 | end |
385 | 385 | |
386 | + should 'get members by role' do | |
387 | + community = fast_create(Community) | |
388 | + role1 = Role.create!(:name => 'role1') | |
389 | + person1 = fast_create(Person) | |
390 | + community.affiliate(person1, role1) | |
391 | + role2 = Role.create!(:name => 'role2') | |
392 | + person2 = fast_create(Person) | |
393 | + community.affiliate(person2, role2) | |
394 | + | |
395 | + assert_equal [person1], community.members_by_role([role1]) | |
396 | + end | |
397 | + | |
398 | + should 'get members by more than one role' do | |
399 | + community = fast_create(Community) | |
400 | + role1 = Role.create!(:name => 'role1') | |
401 | + person1 = fast_create(Person) | |
402 | + community.affiliate(person1, role1) | |
403 | + role2 = Role.create!(:name => 'role2') | |
404 | + person2 = fast_create(Person) | |
405 | + community.affiliate(person2, role2) | |
406 | + role3 = Role.create!(:name => 'role3') | |
407 | + person3 = fast_create(Person) | |
408 | + community.affiliate(person3, role3) | |
409 | + | |
410 | + assert_equal [person2, person3], community.members_by_role([role2, role3]) | |
411 | + end | |
412 | + | |
386 | 413 | should 'return members by role in a json format' do |
387 | 414 | organization = fast_create(Organization) |
388 | 415 | p1 = create_user('person-1').person | ... | ... |