Commit a6151343194e4273a3828152d7a1664e304ccaba
Exists in
master
and in
29 other branches
Merge branch 'article_privacity_to_followers' into 'master'
Article privacity to followers https://gitlab.com/participa/noosfero/issues/324 Feitos para amigos de perfis de pessoas também! See merge request !422
Showing
6 changed files
with
185 additions
and
39 deletions
Show diff stats
app/helpers/article_helper.rb
@@ -77,12 +77,59 @@ module ArticleHelper | @@ -77,12 +77,59 @@ module ArticleHelper | ||
77 | content_tag('div', | 77 | content_tag('div', |
78 | radio_button(:article, :published, false) + | 78 | radio_button(:article, :published, false) + |
79 | content_tag('label', _('Private'), :for => 'article_published_false', :id => "label_private") | 79 | content_tag('label', _('Private'), :for => 'article_published_false', :id => "label_private") |
80 | - ) + | ||
81 | - (article.profile.community? ? content_tag('div', | ||
82 | - content_tag('label', _('Fill in the search field to add the exception users to see this content'), :id => "text-input-search-exception-users") + | ||
83 | - token_input_field_tag(:q, 'search-article-privacy-exceptions', {:action => 'search_article_privacy_exceptions'}, | ||
84 | - {:focus => false, :hint_text => _('Type in a search term for a user'), :pre_populate => tokenized_children})) : | ||
85 | - '')) | 80 | + ) + |
81 | + privacity_exceptions(article, tokenized_children) | ||
82 | + ) | ||
83 | + end | ||
84 | + | ||
85 | + def privacity_exceptions(article, tokenized_children) | ||
86 | + content_tag('div', | ||
87 | + content_tag('div', | ||
88 | + ( | ||
89 | + if article.profile | ||
90 | + add_option_to_followers(article, tokenized_children) | ||
91 | + else | ||
92 | + '' | ||
93 | + end | ||
94 | + ) | ||
95 | + ), | ||
96 | + :style => "margin-left:10px" | ||
97 | + ) | ||
98 | + end | ||
99 | + | ||
100 | + def add_option_to_followers(article, tokenized_children) | ||
101 | + label_message = article.profile.organization? ? _('For all community members') : _('For all your friends') | ||
102 | + | ||
103 | + check_box( | ||
104 | + :article, | ||
105 | + :show_to_followers, | ||
106 | + {:class => "custom_privacy_option"} | ||
107 | + ) + | ||
108 | + content_tag( | ||
109 | + 'label', | ||
110 | + label_message, | ||
111 | + :for => 'article_show_to_followers', | ||
112 | + :id => 'label_show_to_followers' | ||
113 | + ) + | ||
114 | + (article.profile.community? ? | ||
115 | + content_tag( | ||
116 | + 'div', | ||
117 | + content_tag( | ||
118 | + 'label', | ||
119 | + _('Fill in the search field to add the exception users to see this content'), | ||
120 | + :id => "text-input-search-exception-users" | ||
121 | + ) + | ||
122 | + token_input_field_tag( | ||
123 | + :q, | ||
124 | + 'search-article-privacy-exceptions', | ||
125 | + {:action => 'search_article_privacy_exceptions'}, | ||
126 | + { | ||
127 | + :focus => false, | ||
128 | + :hint_text => _('Type in a search term for a user'), | ||
129 | + :pre_populate => tokenized_children | ||
130 | + } | ||
131 | + ) | ||
132 | + ) : '') | ||
86 | end | 133 | end |
87 | 134 | ||
88 | def prepare_to_token_input(array) | 135 | def prepare_to_token_input(array) |
app/models/article.rb
@@ -2,7 +2,14 @@ require 'hpricot' | @@ -2,7 +2,14 @@ require 'hpricot' | ||
2 | 2 | ||
3 | class Article < ActiveRecord::Base | 3 | class Article < ActiveRecord::Base |
4 | 4 | ||
5 | - attr_accessible :name, :body, :abstract, :profile, :tag_list, :parent, :allow_members_to_edit, :translation_of_id, :language, :license_id, :parent_id, :display_posts_in_current_language, :category_ids, :posts_per_page, :moderate_comments, :accept_comments, :feed, :published, :source, :highlighted, :notify_comments, :display_hits, :slug, :external_feed_builder, :display_versions, :external_link, :image_builder | 5 | + attr_accessible :name, :body, :abstract, :profile, :tag_list, :parent, |
6 | + :allow_members_to_edit, :translation_of_id, :language, | ||
7 | + :license_id, :parent_id, :display_posts_in_current_language, | ||
8 | + :category_ids, :posts_per_page, :moderate_comments, | ||
9 | + :accept_comments, :feed, :published, :source, | ||
10 | + :highlighted, :notify_comments, :display_hits, :slug, | ||
11 | + :external_feed_builder, :display_versions, :external_link, | ||
12 | + :image_builder, :show_to_followers | ||
6 | 13 | ||
7 | acts_as_having_image | 14 | acts_as_having_image |
8 | 15 | ||
@@ -333,7 +340,7 @@ class Article < ActiveRecord::Base | @@ -333,7 +340,7 @@ class Article < ActiveRecord::Base | ||
333 | def belongs_to_blog? | 340 | def belongs_to_blog? |
334 | self.parent and self.parent.blog? | 341 | self.parent and self.parent.blog? |
335 | end | 342 | end |
336 | - | 343 | + |
337 | def belongs_to_forum? | 344 | def belongs_to_forum? |
338 | self.parent and self.parent.forum? | 345 | self.parent and self.parent.forum? |
339 | end | 346 | end |
@@ -445,6 +452,7 @@ class Article < ActiveRecord::Base | @@ -445,6 +452,7 @@ class Article < ActiveRecord::Base | ||
445 | if self.parent && !self.parent.published? | 452 | if self.parent && !self.parent.published? |
446 | return false | 453 | return false |
447 | end | 454 | end |
455 | + | ||
448 | true | 456 | true |
449 | else | 457 | else |
450 | false | 458 | false |
@@ -476,14 +484,17 @@ class Article < ActiveRecord::Base | @@ -476,14 +484,17 @@ class Article < ActiveRecord::Base | ||
476 | {:conditions => [" articles.published = ? OR | 484 | {:conditions => [" articles.published = ? OR |
477 | articles.last_changed_by_id = ? OR | 485 | articles.last_changed_by_id = ? OR |
478 | articles.profile_id = ? OR | 486 | articles.profile_id = ? OR |
479 | - ?", | ||
480 | - true, user.id, user.id, user.has_permission?(:view_private_content, profile)] } | 487 | + ? OR articles.show_to_followers = ? AND ?", |
488 | + true, user.id, user.id, user.has_permission?(:view_private_content, profile), | ||
489 | + true, user.follows?(profile)]} | ||
481 | end | 490 | end |
482 | 491 | ||
492 | + | ||
483 | def display_unpublished_article_to?(user) | 493 | def display_unpublished_article_to?(user) |
484 | user == author || allow_view_private_content?(user) || user == profile || | 494 | user == author || allow_view_private_content?(user) || user == profile || |
485 | user.is_admin?(profile.environment) || user.is_admin?(profile) || | 495 | user.is_admin?(profile.environment) || user.is_admin?(profile) || |
486 | - article_privacy_exceptions.include?(user) | 496 | + article_privacy_exceptions.include?(user) || |
497 | + (self.show_to_followers && user.follows?(profile)) | ||
487 | end | 498 | end |
488 | 499 | ||
489 | def display_to?(user = nil) | 500 | def display_to?(user = nil) |
db/migrate/20150113131617_add_show_to_followers_for_article.rb
0 → 100644
features/edit_article.feature
@@ -47,6 +47,28 @@ Feature: edit article | @@ -47,6 +47,28 @@ Feature: edit article | ||
47 | Then I should see "Access denied" | 47 | Then I should see "Access denied" |
48 | 48 | ||
49 | @selenium | 49 | @selenium |
50 | + Scenario: Hide token field when show to members is activated | ||
51 | + Given the following communities | ||
52 | + | name | identifier | owner | | ||
53 | + | Free Software | freesoftware | joaosilva | | ||
54 | + And the following users | ||
55 | + | login | name | | ||
56 | + | mario | Mario Souto | | ||
57 | + | maria | Maria Silva | | ||
58 | + And "Mario Souto" is a member of "Free Software" | ||
59 | + And "Maria Silva" is a member of "Free Software" | ||
60 | + And I am on freesoftware's control panel | ||
61 | + And I follow "Manage Content" | ||
62 | + And I should see "New content" | ||
63 | + And I follow "New content" | ||
64 | + And I should see "Folder" | ||
65 | + When I follow "Folder" | ||
66 | + And I fill in "Title" with "My Folder" | ||
67 | + And I choose "article_published_false" | ||
68 | + And I check "article_show_to_followers" | ||
69 | + Then I should not see "Fill in the search" | ||
70 | + | ||
71 | + @selenium | ||
50 | Scenario: show exception users field when you choose the private option | 72 | Scenario: show exception users field when you choose the private option |
51 | Given the following communities | 73 | Given the following communities |
52 | | name | identifier | owner | | 74 | | name | identifier | owner | |
public/javascripts/article.js
@@ -136,7 +136,7 @@ jQuery(function($) { | @@ -136,7 +136,7 @@ jQuery(function($) { | ||
136 | if (data.length && data.length > 0) { | 136 | if (data.length && data.length > 0) { |
137 | $('#media-search-results').slideDown(); | 137 | $('#media-search-results').slideDown(); |
138 | } | 138 | } |
139 | - $('#media-search-box .header').toggleClass('icon-loading'); | 139 | + $('#media-search-box .header').toggleClass('icon-loading'); |
140 | }); | 140 | }); |
141 | return false; | 141 | return false; |
142 | }); | 142 | }); |
@@ -144,20 +144,20 @@ jQuery(function($) { | @@ -144,20 +144,20 @@ jQuery(function($) { | ||
144 | $('#media-upload-form form').ajaxForm({ | 144 | $('#media-upload-form form').ajaxForm({ |
145 | resetForm: true, | 145 | resetForm: true, |
146 | beforeSubmit: | 146 | beforeSubmit: |
147 | - function() { | ||
148 | - $('#media-upload-form').slideUp(); | ||
149 | - $('#media-upload-box .header').toggleClass('icon-loading'); | ||
150 | - }, | 147 | + function() { |
148 | + $('#media-upload-form').slideUp(); | ||
149 | + $('#media-upload-box .header').toggleClass('icon-loading'); | ||
150 | + }, | ||
151 | success: | 151 | success: |
152 | - function(text) { | ||
153 | - text = text.replace('<pre>', '').replace('</pre>', ''); // old firefox | ||
154 | - var data = $.parseJSON(text); | ||
155 | - list_items(data, '#media-upload-results .items', true); | ||
156 | - if (data.length && data.length > 0) { | ||
157 | - $('#media-upload-results').slideDown(); | ||
158 | - } | ||
159 | - $('#media-upload-box .header').toggleClass('icon-loading'); | 152 | + function(text) { |
153 | + text = text.replace('<pre>', '').replace('</pre>', ''); // old firefox | ||
154 | + var data = $.parseJSON(text); | ||
155 | + list_items(data, '#media-upload-results .items', true); | ||
156 | + if (data.length && data.length > 0) { | ||
157 | + $('#media-upload-results').slideDown(); | ||
160 | } | 158 | } |
159 | + $('#media-upload-box .header').toggleClass('icon-loading'); | ||
160 | + } | ||
161 | }); | 161 | }); |
162 | 162 | ||
163 | $('#media-upload-more-files').click(function() { | 163 | $('#media-upload-more-files').click(function() { |
@@ -166,19 +166,45 @@ jQuery(function($) { | @@ -166,19 +166,45 @@ jQuery(function($) { | ||
166 | return false; | 166 | return false; |
167 | }); | 167 | }); |
168 | 168 | ||
169 | + function is_public_article() { | ||
170 | + return $("#article_published_true").attr('checked'); | ||
171 | + } | ||
172 | + | ||
173 | + function show_hide_privacy_options() { | ||
174 | + var show_privacy_options = $("#article_published_false").attr('checked'); | ||
175 | + var custom_privacy_option = $(".custom_privacy_option").parent("div"); | ||
176 | + | ||
177 | + if( show_privacy_options ) { | ||
178 | + custom_privacy_option.show(); | ||
179 | + } else { | ||
180 | + custom_privacy_option.hide(); | ||
181 | + } | ||
182 | + show_hide_token_input(); | ||
183 | + } | ||
184 | + | ||
169 | function show_hide_token_input() { | 185 | function show_hide_token_input() { |
170 | - if($("#article_published_false").attr('checked')) | ||
171 | - $("#text-input-search-exception-users").parent("div").css('display', 'block'); | ||
172 | - else | ||
173 | - $("#text-input-search-exception-users").parent("div").css('display', 'none'); | 186 | + var display_token = $(".custom_privacy_option:checked").length == 0; |
187 | + var token_field = $("#text-input-search-exception-users").parent("div"); | ||
188 | + | ||
189 | + if( display_token && !is_public_article() ) { | ||
190 | + token_field.css('display', 'block'); | ||
191 | + } else { | ||
192 | + token_field.css('display', 'none'); | ||
193 | + } | ||
174 | } | 194 | } |
175 | 195 | ||
176 | if( $("#token-input-search-article-privacy-exceptions").length == 1 ) { | 196 | if( $("#token-input-search-article-privacy-exceptions").length == 1 ) { |
197 | + show_hide_privacy_options(); | ||
177 | show_hide_token_input(); | 198 | show_hide_token_input(); |
178 | - | ||
179 | - //Hide / Show the text area | ||
180 | - $("#article_published_false").click(show_hide_token_input); | ||
181 | - $("#article_published_true").click(show_hide_token_input); | ||
182 | } | 199 | } |
183 | 200 | ||
201 | + $(document).ready(function(){ | ||
202 | + show_hide_privacy_options(); | ||
203 | + }); | ||
204 | + | ||
205 | + //Hide / Show the text area | ||
206 | + $("#article_published_false").click(show_hide_privacy_options); | ||
207 | + $("#article_published_true").click(show_hide_privacy_options); | ||
208 | + $(".custom_privacy_option").click(show_hide_token_input); | ||
209 | + | ||
184 | }); | 210 | }); |
test/functional/content_viewer_controller_test.rb
@@ -661,8 +661,8 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -661,8 +661,8 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
661 | get :view_page, :profile => owner.identifier, :page => folder.path | 661 | get :view_page, :profile => owner.identifier, :page => folder.path |
662 | assert_response :success | 662 | assert_response :success |
663 | assert_select '.image-gallery-item', 0 | 663 | assert_select '.image-gallery-item', 0 |
664 | - end | ||
665 | - | 664 | + end |
665 | + | ||
666 | 666 | ||
667 | should 'display default image in the slideshow if thumbnails were not processed' do | 667 | should 'display default image in the slideshow if thumbnails were not processed' do |
668 | @controller.stubs(:per_page).returns(1) | 668 | @controller.stubs(:per_page).returns(1) |
@@ -1296,14 +1296,14 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -1296,14 +1296,14 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
1296 | def comment_form_extra_contents(args) | 1296 | def comment_form_extra_contents(args) |
1297 | proc { | 1297 | proc { |
1298 | hidden_field_tag('comment[some_field_id]', 1) | 1298 | hidden_field_tag('comment[some_field_id]', 1) |
1299 | - } | 1299 | + } |
1300 | end | 1300 | end |
1301 | end | 1301 | end |
1302 | class Plugin2 < Noosfero::Plugin | 1302 | class Plugin2 < Noosfero::Plugin |
1303 | def comment_form_extra_contents(args) | 1303 | def comment_form_extra_contents(args) |
1304 | proc { | 1304 | proc { |
1305 | hidden_field_tag('comment[another_field_id]', 1) | 1305 | hidden_field_tag('comment[another_field_id]', 1) |
1306 | - } | 1306 | + } |
1307 | end | 1307 | end |
1308 | end | 1308 | end |
1309 | Noosfero::Plugin.stubs(:all).returns([Plugin1.name, Plugin2.name]) | 1309 | Noosfero::Plugin.stubs(:all).returns([Plugin1.name, Plugin2.name]) |
@@ -1373,20 +1373,20 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -1373,20 +1373,20 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
1373 | get :view_page, :profile => profile.identifier, :page => [blog.path] | 1373 | get :view_page, :profile => profile.identifier, :page => [blog.path] |
1374 | assert_tag :tag => 'strong', :content => /bold/ | 1374 | assert_tag :tag => 'strong', :content => /bold/ |
1375 | end | 1375 | end |
1376 | - | 1376 | + |
1377 | should 'add extra content on article header from plugins' do | 1377 | should 'add extra content on article header from plugins' do |
1378 | class Plugin1 < Noosfero::Plugin | 1378 | class Plugin1 < Noosfero::Plugin |
1379 | def article_header_extra_contents(args) | 1379 | def article_header_extra_contents(args) |
1380 | proc { | 1380 | proc { |
1381 | content_tag('div', '', :class => 'plugin1') | 1381 | content_tag('div', '', :class => 'plugin1') |
1382 | - } | 1382 | + } |
1383 | end | 1383 | end |
1384 | end | 1384 | end |
1385 | class Plugin2 < Noosfero::Plugin | 1385 | class Plugin2 < Noosfero::Plugin |
1386 | def article_header_extra_contents(args) | 1386 | def article_header_extra_contents(args) |
1387 | proc { | 1387 | proc { |
1388 | content_tag('div', '', :class => 'plugin2') | 1388 | content_tag('div', '', :class => 'plugin2') |
1389 | - } | 1389 | + } |
1390 | end | 1390 | end |
1391 | end | 1391 | end |
1392 | Noosfero::Plugin.stubs(:all).returns([Plugin1.name, Plugin2.name]) | 1392 | Noosfero::Plugin.stubs(:all).returns([Plugin1.name, Plugin2.name]) |
@@ -1447,4 +1447,35 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -1447,4 +1447,35 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
1447 | assert_tag :tag => 'meta', :attributes => { :property => 'og:image', :content => /\/images\/x.png/ } | 1447 | assert_tag :tag => 'meta', :attributes => { :property => 'og:image', :content => /\/images\/x.png/ } |
1448 | end | 1448 | end |
1449 | 1449 | ||
1450 | + should 'manage private article visualization' do | ||
1451 | + community = Community.create(:name => 'test-community') | ||
1452 | + community.add_member(@profile) | ||
1453 | + community.save! | ||
1454 | + | ||
1455 | + blog = community.articles.find_by_name("Blog") | ||
1456 | + | ||
1457 | + article = TinyMceArticle.create(:name => 'Article to be shared with images', | ||
1458 | + :body => 'This article should be shared with all social networks', | ||
1459 | + :profile => @profile, | ||
1460 | + :published => false, | ||
1461 | + :show_to_followers => true) | ||
1462 | + article.parent = blog | ||
1463 | + article.save! | ||
1464 | + | ||
1465 | + otheruser = create_user('otheruser').person | ||
1466 | + community.add_member(otheruser) | ||
1467 | + login_as(otheruser.identifier) | ||
1468 | + | ||
1469 | + get :view_page, :profile => community.identifier, "page" => 'blog' | ||
1470 | + | ||
1471 | + assert_response :success | ||
1472 | + assert_tag :tag => 'h1', :attributes => { :class => /title/ }, :content => article.name | ||
1473 | + | ||
1474 | + article.show_to_followers = false | ||
1475 | + article.save! | ||
1476 | + | ||
1477 | + get :view_page, :profile => community.identifier, "page" => 'blog' | ||
1478 | + | ||
1479 | + assert_no_tag :tag => 'h1', :attributes => { :class => /title/ }, :content => article.name | ||
1480 | + end | ||
1450 | end | 1481 | end |