Commit a6151343194e4273a3828152d7a1664e304ccaba

Authored by Antonio Terceiro
2 parents 45964060 b3068b11

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
app/helpers/article_helper.rb
... ... @@ -77,12 +77,59 @@ module ArticleHelper
77 77 content_tag('div',
78 78 radio_button(:article, :published, false) +
79 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 133 end
87 134  
88 135 def prepare_to_token_input(array)
... ...
app/models/article.rb
... ... @@ -2,7 +2,14 @@ require 'hpricot'
2 2  
3 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 14 acts_as_having_image
8 15  
... ... @@ -333,7 +340,7 @@ class Article &lt; ActiveRecord::Base
333 340 def belongs_to_blog?
334 341 self.parent and self.parent.blog?
335 342 end
336   -
  343 +
337 344 def belongs_to_forum?
338 345 self.parent and self.parent.forum?
339 346 end
... ... @@ -445,6 +452,7 @@ class Article &lt; ActiveRecord::Base
445 452 if self.parent && !self.parent.published?
446 453 return false
447 454 end
  455 +
448 456 true
449 457 else
450 458 false
... ... @@ -476,14 +484,17 @@ class Article &lt; ActiveRecord::Base
476 484 {:conditions => [" articles.published = ? OR
477 485 articles.last_changed_by_id = ? OR
478 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 490 end
482 491  
  492 +
483 493 def display_unpublished_article_to?(user)
484 494 user == author || allow_view_private_content?(user) || user == profile ||
485 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 498 end
488 499  
489 500 def display_to?(user = nil)
... ...
db/migrate/20150113131617_add_show_to_followers_for_article.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddShowToFollowersForArticle < ActiveRecord::Migration
  2 + def up
  3 + add_column :articles, :show_to_followers, :boolean, :default => false
  4 + end
  5 +
  6 + def down
  7 + remove_column :articles, :show_to_followers
  8 + end
  9 +end
... ...
features/edit_article.feature
... ... @@ -47,6 +47,28 @@ Feature: edit article
47 47 Then I should see "Access denied"
48 48  
49 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 72 Scenario: show exception users field when you choose the private option
51 73 Given the following communities
52 74 | name | identifier | owner |
... ...
public/javascripts/article.js
... ... @@ -136,7 +136,7 @@ jQuery(function($) {
136 136 if (data.length && data.length > 0) {
137 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 141 return false;
142 142 });
... ... @@ -144,20 +144,20 @@ jQuery(function($) {
144 144 $('#media-upload-form form').ajaxForm({
145 145 resetForm: true,
146 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 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 163 $('#media-upload-more-files').click(function() {
... ... @@ -166,19 +166,45 @@ jQuery(function($) {
166 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 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 196 if( $("#token-input-search-article-privacy-exceptions").length == 1 ) {
  197 + show_hide_privacy_options();
177 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 &lt; ActionController::TestCase
661 661 get :view_page, :profile => owner.identifier, :page => folder.path
662 662 assert_response :success
663 663 assert_select '.image-gallery-item', 0
664   - end
665   -
  664 + end
  665 +
666 666  
667 667 should 'display default image in the slideshow if thumbnails were not processed' do
668 668 @controller.stubs(:per_page).returns(1)
... ... @@ -1296,14 +1296,14 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
1296 1296 def comment_form_extra_contents(args)
1297 1297 proc {
1298 1298 hidden_field_tag('comment[some_field_id]', 1)
1299   - }
  1299 + }
1300 1300 end
1301 1301 end
1302 1302 class Plugin2 < Noosfero::Plugin
1303 1303 def comment_form_extra_contents(args)
1304 1304 proc {
1305 1305 hidden_field_tag('comment[another_field_id]', 1)
1306   - }
  1306 + }
1307 1307 end
1308 1308 end
1309 1309 Noosfero::Plugin.stubs(:all).returns([Plugin1.name, Plugin2.name])
... ... @@ -1373,20 +1373,20 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
1373 1373 get :view_page, :profile => profile.identifier, :page => [blog.path]
1374 1374 assert_tag :tag => 'strong', :content => /bold/
1375 1375 end
1376   -
  1376 +
1377 1377 should 'add extra content on article header from plugins' do
1378 1378 class Plugin1 < Noosfero::Plugin
1379 1379 def article_header_extra_contents(args)
1380 1380 proc {
1381 1381 content_tag('div', '', :class => 'plugin1')
1382   - }
  1382 + }
1383 1383 end
1384 1384 end
1385 1385 class Plugin2 < Noosfero::Plugin
1386 1386 def article_header_extra_contents(args)
1387 1387 proc {
1388 1388 content_tag('div', '', :class => 'plugin2')
1389   - }
  1389 + }
1390 1390 end
1391 1391 end
1392 1392 Noosfero::Plugin.stubs(:all).returns([Plugin1.name, Plugin2.name])
... ... @@ -1447,4 +1447,35 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
1447 1447 assert_tag :tag => 'meta', :attributes => { :property => 'og:image', :content => /\/images\/x.png/ }
1448 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 1481 end
... ...