Commit 9f616e0b9baf3bad75d3308531b824591c396aa9
Committed by
Fabio Teixeira
1 parent
c9eccb09
Exists in
master
and in
28 other branches
access_level: Custom permission for community users to access an article
- Added a field on article new/edit to specify which users can access the article - Added a relationship has_and_belongs_to_many between Article and Person - Created a new table article_privacy_exceptions for has_and_belongs_to_many - Added cucumber tests - Added a new cucumber step to add a user to the exception users list (ActionItem2852) Signed-off-by: Alex de Souza <campelo.al1@gmail.com> Signed-off-by: Athos Ribeiro <athoscribeiro@gmail.com> Signed-off-by: Andre Bedran <bedran.fleck@gmail.com> Signed-off-by: Arthur Del Esposte <arthurmde@gmail.com> Signed-off-by: Carlos Andre <carlos.andre.souza@msn.com> Signed-off-by: Fabio Teixeira <fabio1079@gmail.com> Signed-off-by: Gabriela Navarro <navarro1703@gmail.com> Signed-off-by: Gustavo Jaruga <darksshades@hotmail.com> Signed-off-by: Matheus Faria <matheus.sousa.faria@gmail.com> Signed-off-by: Tales Martins <tales.martins@gmail.com>
Showing
15 changed files
with
232 additions
and
80 deletions
Show diff stats
app/controllers/my_profile/cms_controller.rb
| ... | ... | @@ -2,6 +2,8 @@ class CmsController < MyProfileController |
| 2 | 2 | |
| 3 | 3 | protect 'edit_profile', :profile, :only => [:set_home_page] |
| 4 | 4 | |
| 5 | + include ArticleHelper | |
| 6 | + | |
| 5 | 7 | def self.protect_if(*args) |
| 6 | 8 | before_filter(*args) do |c| |
| 7 | 9 | user, profile = c.send(:user), c.send(:profile) |
| ... | ... | @@ -70,6 +72,14 @@ class CmsController < MyProfileController |
| 70 | 72 | translations if @article.translatable? |
| 71 | 73 | continue = params[:continue] |
| 72 | 74 | |
| 75 | + @article.article_privacy_exceptions = params[:q].split(/,/).map{|n| environment.people.find n.to_i} unless params[:q].nil? | |
| 76 | + | |
| 77 | + @tokenized_children = prepare_to_token_input( | |
| 78 | + profile.members.map{|m| | |
| 79 | + m if @article.article_privacy_exceptions.include?(m) | |
| 80 | + }.compact | |
| 81 | + ) | |
| 82 | + | |
| 73 | 83 | refuse_blocks |
| 74 | 84 | record_coming |
| 75 | 85 | if request.post? |
| ... | ... | @@ -130,6 +140,8 @@ class CmsController < MyProfileController |
| 130 | 140 | |
| 131 | 141 | continue = params[:continue] |
| 132 | 142 | if request.post? |
| 143 | + @article.article_privacy_exceptions = params[:q].split(/,/).map{|n| environment.people.find n.to_i} unless params[:q].nil? | |
| 144 | + | |
| 133 | 145 | if @article.save |
| 134 | 146 | if continue |
| 135 | 147 | redirect_to :action => 'edit', :id => @article |
| ... | ... | @@ -290,6 +302,12 @@ class CmsController < MyProfileController |
| 290 | 302 | render :text => article_list_to_json(results), :content_type => 'application/json' |
| 291 | 303 | end |
| 292 | 304 | |
| 305 | + def search_article_privacy_exceptions | |
| 306 | + arg = params[:q].downcase | |
| 307 | + result = profile.members.find(:all, :conditions => ['LOWER(name) LIKE ?', "%#{arg}%"]) | |
| 308 | + render :text => prepare_to_token_input(result).to_json | |
| 309 | + end | |
| 310 | + | |
| 293 | 311 | def media_upload |
| 294 | 312 | files_uploaded = [] |
| 295 | 313 | parent = check_parent(params[:parent_id]) | ... | ... |
app/helpers/application_helper.rb
| ... | ... | @@ -40,6 +40,8 @@ module ApplicationHelper |
| 40 | 40 | |
| 41 | 41 | include Noosfero::Gravatar |
| 42 | 42 | |
| 43 | + include TokenHelper | |
| 44 | + | |
| 43 | 45 | def locale |
| 44 | 46 | (@page && !@page.language.blank?) ? @page.language : FastGettext.locale |
| 45 | 47 | end |
| ... | ... | @@ -1299,10 +1301,6 @@ module ApplicationHelper |
| 1299 | 1301 | content_tag(:div, content_tag(:ul, titles) + raw(contents), :class => 'ui-tabs') |
| 1300 | 1302 | end |
| 1301 | 1303 | |
| 1302 | - def jquery_token_input_messages_json(hintText = _('Type in an keyword'), noResultsText = _('No results'), searchingText = _('Searching...')) | |
| 1303 | - "hintText: '#{hintText}', noResultsText: '#{noResultsText}', searchingText: '#{searchingText}'" | |
| 1304 | - end | |
| 1305 | - | |
| 1306 | 1304 | def delete_article_message(article) |
| 1307 | 1305 | if article.folder? |
| 1308 | 1306 | _("Are you sure that you want to remove the folder \"#{article.name}\"? Note that all the items inside it will also be removed!") |
| ... | ... | @@ -1343,50 +1341,6 @@ module ApplicationHelper |
| 1343 | 1341 | ) |
| 1344 | 1342 | end |
| 1345 | 1343 | |
| 1346 | - def token_input_field_tag(name, element_id, search_action, options = {}, text_field_options = {}, html_options = {}) | |
| 1347 | - options[:min_chars] ||= 3 | |
| 1348 | - options[:hint_text] ||= _("Type in a search term") | |
| 1349 | - options[:no_results_text] ||= _("No results") | |
| 1350 | - options[:searching_text] ||= _("Searching...") | |
| 1351 | - options[:search_delay] ||= 1000 | |
| 1352 | - options[:prevent_duplicates] ||= true | |
| 1353 | - options[:backspace_delete_item] ||= false | |
| 1354 | - options[:focus] ||= false | |
| 1355 | - options[:avoid_enter] ||= true | |
| 1356 | - options[:on_result] ||= 'null' | |
| 1357 | - options[:on_add] ||= 'null' | |
| 1358 | - options[:on_delete] ||= 'null' | |
| 1359 | - options[:on_ready] ||= 'null' | |
| 1360 | - | |
| 1361 | - result = text_field_tag(name, nil, text_field_options.merge(html_options.merge({:id => element_id}))) | |
| 1362 | - result += javascript_tag("jQuery('##{element_id}') | |
| 1363 | - .tokenInput('#{url_for(search_action)}', { | |
| 1364 | - minChars: #{options[:min_chars].to_json}, | |
| 1365 | - prePopulate: #{options[:pre_populate].to_json}, | |
| 1366 | - hintText: #{options[:hint_text].to_json}, | |
| 1367 | - noResultsText: #{options[:no_results_text].to_json}, | |
| 1368 | - searchingText: #{options[:searching_text].to_json}, | |
| 1369 | - searchDelay: #{options[:serach_delay].to_json}, | |
| 1370 | - preventDuplicates: #{options[:prevent_duplicates].to_json}, | |
| 1371 | - backspaceDeleteItem: #{options[:backspace_delete_item].to_json}, | |
| 1372 | - queryParam: #{name.to_json}, | |
| 1373 | - tokenLimit: #{options[:token_limit].to_json}, | |
| 1374 | - onResult: #{options[:on_result]}, | |
| 1375 | - onAdd: #{options[:on_add]}, | |
| 1376 | - onDelete: #{options[:on_delete]}, | |
| 1377 | - onReady: #{options[:on_ready]}, | |
| 1378 | - }); | |
| 1379 | - ") | |
| 1380 | - result += javascript_tag("jQuery('##{element_id}').focus();") if options[:focus] | |
| 1381 | - if options[:avoid_enter] | |
| 1382 | - result += javascript_tag("jQuery('#token-input-#{element_id}') | |
| 1383 | - .live('keydown', function(event){ | |
| 1384 | - if(event.keyCode == '13') return false; | |
| 1385 | - });") | |
| 1386 | - end | |
| 1387 | - result | |
| 1388 | - end | |
| 1389 | - | |
| 1390 | 1344 | def expirable_content_reference(content, action, text, url, options = {}) |
| 1391 | 1345 | reason = @plugins.dispatch("content_expire_#{action.to_s}", content).first |
| 1392 | 1346 | options[:title] = reason | ... | ... |
app/helpers/article_helper.rb
| 1 | 1 | module ArticleHelper |
| 2 | 2 | |
| 3 | - def custom_options_for_article(article) | |
| 3 | + include TokenHelper | |
| 4 | + | |
| 5 | + def custom_options_for_article(article, tokenized_children) | |
| 4 | 6 | @article = article |
| 5 | - content_tag('h4', _('Visibility')) + | |
| 6 | - content_tag('div', | |
| 7 | - content_tag('div', | |
| 8 | - radio_button(:article, :published, true) + | |
| 9 | - content_tag('label', _('Public (visible to other people)'), :for => 'article_published_true') | |
| 10 | - ) + | |
| 11 | - content_tag('div', | |
| 12 | - radio_button(:article, :published, false) + | |
| 13 | - content_tag('label', _('Private'), :for => 'article_published_false') | |
| 14 | - ) | |
| 15 | - ) + | |
| 7 | + | |
| 8 | + visibility_options(@article, tokenized_children) + | |
| 16 | 9 | content_tag('h4', _('Options')) + |
| 17 | 10 | content_tag('div', |
| 18 | 11 | (article.profile.has_members? ? |
| ... | ... | @@ -53,6 +46,28 @@ module ArticleHelper |
| 53 | 46 | ) |
| 54 | 47 | end |
| 55 | 48 | |
| 49 | + def visibility_options(article, tokenized_children) | |
| 50 | + content_tag('h4', _('Visibility')) + | |
| 51 | + content_tag('div', | |
| 52 | + content_tag('div', | |
| 53 | + radio_button(:article, :published, true) + | |
| 54 | + content_tag('label', _('Public (visible to other people)'), :for => 'article_published_true') | |
| 55 | + ) + | |
| 56 | + content_tag('div', | |
| 57 | + radio_button(:article, :published, false) + | |
| 58 | + content_tag('label', _('Private'), :for => 'article_published_false', :id => "label_private") | |
| 59 | + ) + | |
| 60 | + (article.profile.class == Community ? content_tag('div', | |
| 61 | + content_tag('label', _('Fill in the search field to add the exception users to see this content'), :id => "text-input-search-exception-users") + | |
| 62 | + token_input_field_tag(:q, 'search-article-privacy-exceptions', {:action => 'search_article_privacy_exceptions'}, | |
| 63 | + {:focus => false, :hint_text => _('Type in a search term for a user'), :pre_populate => tokenized_children})) : | |
| 64 | + '')) | |
| 65 | + end | |
| 66 | + | |
| 67 | + def prepare_to_token_input(array) | |
| 68 | + array.map { |object| {:id => object.id, :name => object.name} } | |
| 69 | + end | |
| 70 | + | |
| 56 | 71 | def cms_label_for_new_children |
| 57 | 72 | _('New article') |
| 58 | 73 | end | ... | ... |
app/helpers/blog_helper.rb
| 1 | 1 | module BlogHelper |
| 2 | 2 | |
| 3 | - def custom_options_for_article(article) | |
| 3 | + include ArticleHelper | |
| 4 | + | |
| 5 | + def custom_options_for_article(article,tokenized_children) | |
| 4 | 6 | @article = article |
| 5 | 7 | hidden_field_tag('article[published]', 1) + |
| 6 | - hidden_field_tag('article[accept_comments]', 0) | |
| 8 | + hidden_field_tag('article[accept_comments]', 0) + | |
| 9 | + visibility_options(article,tokenized_children) | |
| 7 | 10 | end |
| 8 | 11 | |
| 9 | 12 | def cms_label_for_new_children | ... | ... |
app/helpers/cms_helper.rb
| ... | ... | @@ -22,9 +22,9 @@ module CmsHelper |
| 22 | 22 | |
| 23 | 23 | attr_reader :environment |
| 24 | 24 | |
| 25 | - def options_for_article(article) | |
| 25 | + def options_for_article(article, tokenized_children=nil) | |
| 26 | 26 | article_helper = helper_for_article(article) |
| 27 | - article_helper.custom_options_for_article(article) | |
| 27 | + article_helper.custom_options_for_article(article, tokenized_children) | |
| 28 | 28 | end |
| 29 | 29 | |
| 30 | 30 | def link_to_article(article) | ... | ... |
app/helpers/folder_helper.rb
| 1 | 1 | module FolderHelper |
| 2 | 2 | |
| 3 | 3 | include ShortFilename |
| 4 | + include ArticleHelper | |
| 4 | 5 | |
| 5 | 6 | def list_articles(articles, recursive = false) |
| 6 | 7 | if !articles.blank? |
| ... | ... | @@ -60,19 +61,10 @@ module FolderHelper |
| 60 | 61 | "icon-new icon-new%s" % klass.icon_name |
| 61 | 62 | end |
| 62 | 63 | |
| 63 | - def custom_options_for_article(article) | |
| 64 | + def custom_options_for_article(article,tokenized_children) | |
| 64 | 65 | @article = article |
| 65 | - content_tag('h4', _('Visibility')) + | |
| 66 | - content_tag('div', | |
| 67 | - content_tag('div', | |
| 68 | - radio_button(:article, :published, true) + | |
| 69 | - content_tag('label', _('Public (visible to other people)'), :for => 'article_published_true') | |
| 70 | - ) + | |
| 71 | - content_tag('div', | |
| 72 | - radio_button(:article, :published, false) + | |
| 73 | - content_tag('label', _('Private'), :for => 'article_published_false') | |
| 74 | - ) | |
| 75 | - ) + | |
| 66 | + | |
| 67 | + visibility_options(article,tokenized_children) + | |
| 76 | 68 | content_tag('div', |
| 77 | 69 | hidden_field_tag('article[accept_comments]', 0) |
| 78 | 70 | ) | ... | ... |
| ... | ... | @@ -0,0 +1,51 @@ |
| 1 | +module TokenHelper | |
| 2 | + | |
| 3 | + def jquery_token_input_messages_json(hintText = _('Type in an keyword'), noResultsText = _('No results'), searchingText = _('Searching...')) | |
| 4 | + "hintText: '#{hintText}', noResultsText: '#{noResultsText}', searchingText: '#{searchingText}'" | |
| 5 | + end | |
| 6 | + | |
| 7 | + def token_input_field_tag(name, element_id, search_action, options = {}, text_field_options = {}, html_options = {}) | |
| 8 | + options[:min_chars] ||= 3 | |
| 9 | + options[:hint_text] ||= _("Type in a search term") | |
| 10 | + options[:no_results_text] ||= _("No results") | |
| 11 | + options[:searching_text] ||= _("Searching...") | |
| 12 | + options[:search_delay] ||= 1000 | |
| 13 | + options[:prevent_duplicates] ||= true | |
| 14 | + options[:backspace_delete_item] ||= false | |
| 15 | + options[:focus] ||= false | |
| 16 | + options[:avoid_enter] ||= true | |
| 17 | + options[:on_result] ||= 'null' | |
| 18 | + options[:on_add] ||= 'null' | |
| 19 | + options[:on_delete] ||= 'null' | |
| 20 | + options[:on_ready] ||= 'null' | |
| 21 | + | |
| 22 | + result = text_field_tag(name, nil, text_field_options.merge(html_options.merge({:id => element_id}))) | |
| 23 | + result += javascript_tag("jQuery('##{element_id}') | |
| 24 | + .tokenInput('#{url_for(search_action)}', { | |
| 25 | + minChars: #{options[:min_chars].to_json}, | |
| 26 | + prePopulate: #{options[:pre_populate].to_json}, | |
| 27 | + hintText: #{options[:hint_text].to_json}, | |
| 28 | + noResultsText: #{options[:no_results_text].to_json}, | |
| 29 | + searchingText: #{options[:searching_text].to_json}, | |
| 30 | + searchDelay: #{options[:serach_delay].to_json}, | |
| 31 | + preventDuplicates: #{options[:prevent_duplicates].to_json}, | |
| 32 | + backspaceDeleteItem: #{options[:backspace_delete_item].to_json}, | |
| 33 | + queryParam: #{name.to_json}, | |
| 34 | + tokenLimit: #{options[:token_limit].to_json}, | |
| 35 | + onResult: #{options[:on_result]}, | |
| 36 | + onAdd: #{options[:on_add]}, | |
| 37 | + onDelete: #{options[:on_delete]}, | |
| 38 | + onReady: #{options[:on_ready]}, | |
| 39 | + }); | |
| 40 | + ") | |
| 41 | + result += javascript_tag("jQuery('##{element_id}').focus();") if options[:focus] | |
| 42 | + if options[:avoid_enter] | |
| 43 | + result += javascript_tag("jQuery('#token-input-#{element_id}') | |
| 44 | + .live('keydown', function(event){ | |
| 45 | + if(event.keyCode == '13') return false; | |
| 46 | + });") | |
| 47 | + end | |
| 48 | + result | |
| 49 | + end | |
| 50 | + | |
| 51 | +end | |
| 0 | 52 | \ No newline at end of file | ... | ... |
app/models/article.rb
| ... | ... | @@ -69,6 +69,7 @@ class Article < ActiveRecord::Base |
| 69 | 69 | settings_items :allow_members_to_edit, :type => :boolean, :default => false |
| 70 | 70 | settings_items :moderate_comments, :type => :boolean, :default => false |
| 71 | 71 | settings_items :followers, :type => Array, :default => [] |
| 72 | + has_and_belongs_to_many :article_privacy_exceptions, :class_name => 'Person', :join_table => 'article_privacy_exceptions' | |
| 72 | 73 | |
| 73 | 74 | belongs_to :reference_article, :class_name => "Article", :foreign_key => 'reference_article_id' |
| 74 | 75 | |
| ... | ... | @@ -470,7 +471,8 @@ class Article < ActiveRecord::Base |
| 470 | 471 | |
| 471 | 472 | def display_unpublished_article_to?(user) |
| 472 | 473 | user == author || allow_view_private_content?(user) || user == profile || |
| 473 | - user.is_admin?(profile.environment) || user.is_admin?(profile) | |
| 474 | + user.is_admin?(profile.environment) || user.is_admin?(profile) || | |
| 475 | + article_privacy_exceptions.include?(user) | |
| 474 | 476 | end |
| 475 | 477 | |
| 476 | 478 | def display_to?(user = nil) | ... | ... |
app/models/person.rb
| ... | ... | @@ -63,6 +63,8 @@ class Person < Profile |
| 63 | 63 | |
| 64 | 64 | has_many :scraps_sent, :class_name => 'Scrap', :foreign_key => :sender_id, :dependent => :destroy |
| 65 | 65 | |
| 66 | + has_and_belongs_to_many :articles_with_access, :class_name => 'Article', :join_table => 'article_privacy_exceptions' | |
| 67 | + | |
| 66 | 68 | named_scope :more_popular, |
| 67 | 69 | :select => "#{Profile.qualified_column_names}, count(friend_id) as total", |
| 68 | 70 | :group => Profile.qualified_column_names, | ... | ... |
app/views/cms/edit.rhtml
| 1 | 1 | <%= error_messages_for 'article' %> |
| 2 | +<%= javascript_include_tag "article.js" %> | |
| 2 | 3 | |
| 3 | 4 | <div class='<%= (environment.enabled?('media_panel') ? 'with_media_panel' : 'no_media_panel') %>'> |
| 4 | 5 | <% labelled_form_for 'article', @article, :html => { :multipart => true, :class => @type } do |f| %> |
| ... | ... | @@ -33,7 +34,7 @@ |
| 33 | 34 | <%= content_tag( 'small', _('Separate tags with commas') ) %> |
| 34 | 35 | |
| 35 | 36 | <div id='edit-article-options'> |
| 36 | - <%= options_for_article(@article) %> | |
| 37 | + <%= options_for_article(@article, @tokenized_children) %> | |
| 37 | 38 | </div> |
| 38 | 39 | |
| 39 | 40 | <% button_bar do %> | ... | ... |
| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | +class ArticlePrivacyExceptions < ActiveRecord::Migration | |
| 2 | + def self.up | |
| 3 | + create_table :article_privacy_exceptions, :id => false do |t| | |
| 4 | + t.integer :article_id | |
| 5 | + t.integer :person_id | |
| 6 | + end | |
| 7 | + end | |
| 8 | + | |
| 9 | + def self.down | |
| 10 | + drop_table :article_privacy_exceptions | |
| 11 | + end | |
| 12 | +end | ... | ... |
db/schema.rb
| ... | ... | @@ -9,8 +9,7 @@ |
| 9 | 9 | # |
| 10 | 10 | # It's strongly recommended to check this file into your version control system. |
| 11 | 11 | |
| 12 | -ActiveRecord::Schema.define(:version => 20131121162641) do | |
| 13 | - | |
| 12 | +ActiveRecord::Schema.define(:version => 20140108132730) do | |
| 14 | 13 | create_table "abuse_reports", :force => true do |t| |
| 15 | 14 | t.integer "reporter_id" |
| 16 | 15 | t.integer "abuse_complaint_id" |
| ... | ... | @@ -46,6 +45,11 @@ ActiveRecord::Schema.define(:version => 20131121162641) do |
| 46 | 45 | add_index "action_tracker_notifications", ["profile_id", "action_tracker_id"], :name => "index_action_tracker_notif_on_prof_id_act_tracker_id", :unique => true |
| 47 | 46 | add_index "action_tracker_notifications", ["profile_id"], :name => "index_action_tracker_notifications_on_profile_id" |
| 48 | 47 | |
| 48 | + create_table "article_privacy_exceptions", :id => false, :force => true do |t| | |
| 49 | + t.integer "article_id" | |
| 50 | + t.integer "person_id" | |
| 51 | + end | |
| 52 | + | |
| 49 | 53 | create_table "article_versions", :force => true do |t| |
| 50 | 54 | t.integer "article_id" |
| 51 | 55 | t.integer "version" |
| ... | ... | @@ -460,6 +464,7 @@ ActiveRecord::Schema.define(:version => 20131121162641) do |
| 460 | 464 | t.boolean "is_template", :default => false |
| 461 | 465 | t.integer "template_id" |
| 462 | 466 | t.string "redirection_after_login" |
| 467 | + t.text "settings" | |
| 463 | 468 | end |
| 464 | 469 | |
| 465 | 470 | add_index "profiles", ["environment_id"], :name => "index_profiles_on_environment_id" |
| ... | ... | @@ -566,6 +571,11 @@ ActiveRecord::Schema.define(:version => 20131121162641) do |
| 566 | 571 | |
| 567 | 572 | add_index "tasks", ["spam"], :name => "index_tasks_on_spam" |
| 568 | 573 | |
| 574 | + create_table "terms_forum_people", :id => false, :force => true do |t| | |
| 575 | + t.integer "forum_id" | |
| 576 | + t.integer "person_id" | |
| 577 | + end | |
| 578 | + | |
| 569 | 579 | create_table "thumbnails", :force => true do |t| |
| 570 | 580 | t.integer "size" |
| 571 | 581 | t.string "content_type" | ... | ... |
features/edit_article.feature
| ... | ... | @@ -22,6 +22,70 @@ Feature: edit article |
| 22 | 22 | And I go to joaosilva's control panel |
| 23 | 23 | Then I should see "My Folder" |
| 24 | 24 | |
| 25 | + @selenium | |
| 26 | + Scenario: denied access folder for a not logged user | |
| 27 | + Given the following communities | |
| 28 | + | name | identifier | owner | | |
| 29 | + | Free Software | freesoftware | joaosilva | | |
| 30 | + And the following users | |
| 31 | + | login | name | | |
| 32 | + | mario | Mario Souto | | |
| 33 | + | maria | Maria Silva | | |
| 34 | + And "Mario Souto" is a member of "Free Software" | |
| 35 | + And "Maria Silva" is a member of "Free Software" | |
| 36 | + And I am on freesoftware's control panel | |
| 37 | + And I follow "Manage Content" | |
| 38 | + And I follow "New content" | |
| 39 | + When I follow "Folder" | |
| 40 | + And I fill in "Title" with "My Folder" | |
| 41 | + And I choose "article_published_false" | |
| 42 | + And I press "Save" | |
| 43 | + And I log off | |
| 44 | + And I go to /freesoftware/my-folder | |
| 45 | + Then I should see "Access denied" | |
| 46 | + | |
| 47 | + @selenium | |
| 48 | + Scenario: show exception users field when you choose the private option | |
| 49 | + Given the following communities | |
| 50 | + | name | identifier | owner | | |
| 51 | + | Free Software | freesoftware | joaosilva | | |
| 52 | + And the following users | |
| 53 | + | login | name | | |
| 54 | + | mario | Mario Souto | | |
| 55 | + | maria | Maria Silva | | |
| 56 | + And "Mario Souto" is a member of "Free Software" | |
| 57 | + And "Maria Silva" is a member of "Free Software" | |
| 58 | + And I am on freesoftware's control panel | |
| 59 | + And I follow "Manage Content" | |
| 60 | + And I follow "New content" | |
| 61 | + When I follow "Folder" | |
| 62 | + And I fill in "Title" with "My Folder" | |
| 63 | + And I choose "article_published_false" | |
| 64 | + Then I should see "Fill in the search field to add the exception users to see this content" | |
| 65 | + | |
| 66 | + @selenium | |
| 67 | + Scenario: allowed user should see the content of a folder | |
| 68 | + Given the following communities | |
| 69 | + | name | identifier | owner | | |
| 70 | + | Free Software | freesoftware | joaosilva | | |
| 71 | + And the following users | |
| 72 | + | login | name | | |
| 73 | + | mario | Mario Souto | | |
| 74 | + | maria | Maria Silva | | |
| 75 | + And the following articles | |
| 76 | + | owner | name | body | | |
| 77 | + | freesoftware | My Folder | ... | | |
| 78 | + And "Mario Souto" is a member of "Free Software" | |
| 79 | + And "Maria Silva" is a member of "Free Software" | |
| 80 | + And I go to /freesoftware/my-folder | |
| 81 | + When I follow "Edit" | |
| 82 | + And I choose "article_published_false" | |
| 83 | + And I press "Save" | |
| 84 | + And I add to "My Folder" the following exception "Maria Silva" | |
| 85 | + And I am logged in as "maria" | |
| 86 | + And I go to /freesoftware/my-folder | |
| 87 | + Then I should see "My Folder" | |
| 88 | + | |
| 25 | 89 | Scenario: redirect to the created folder |
| 26 | 90 | Given I am on joaosilva's control panel |
| 27 | 91 | And I follow "Manage Content" |
| ... | ... | @@ -40,6 +104,7 @@ Feature: edit article |
| 40 | 104 | When I follow "Cancel" within ".main-block" |
| 41 | 105 | Then I should be on joaosilva's cms |
| 42 | 106 | |
| 107 | + @selenium | |
| 43 | 108 | Scenario: display tag list field when creating event |
| 44 | 109 | Given I am on joaosilva's control panel |
| 45 | 110 | And I follow "Manage Content" | ... | ... |
features/step_definitions/content_steps.rb
| ... | ... | @@ -8,3 +8,15 @@ When /^I create a content of type "([^\"]*)" with the following data$/ do |conte |
| 8 | 8 | |
| 9 | 9 | click_button "Save" |
| 10 | 10 | end |
| 11 | + | |
| 12 | +And /^I add to "([^\"]*)" the following exception "([^\"]*)"$/ do |article_name, user_exception| | |
| 13 | + article = Article.find_by_name(article_name) | |
| 14 | + community = article.profile | |
| 15 | + raise "The article profile is not a community." unless community.class == Community | |
| 16 | + | |
| 17 | + my_user = community.members.find_by_name(user_exception) | |
| 18 | + raise "Could not find #{user_exception} in #{community.name} community." if my_user.nil? | |
| 19 | + | |
| 20 | + article.article_privacy_exceptions << my_user | |
| 21 | + article.save | |
| 22 | +end | |
| 11 | 23 | \ No newline at end of file | ... | ... |
public/javascripts/article.js
| ... | ... | @@ -172,4 +172,19 @@ jQuery(function($) { |
| 172 | 172 | return false; |
| 173 | 173 | }); |
| 174 | 174 | |
| 175 | + function show_hide_token_input() { | |
| 176 | + if($("#article_published_false").attr('checked')) | |
| 177 | + $("#text-input-search-exception-users").parent("div").css('display', 'block'); | |
| 178 | + else | |
| 179 | + $("#text-input-search-exception-users").parent("div").css('display', 'none'); | |
| 180 | + } | |
| 181 | + | |
| 182 | + if( $("#token-input-search-article-privacy-exceptions").length == 1 ) { | |
| 183 | + show_hide_token_input(); | |
| 184 | + | |
| 185 | + //Hide / Show the text area | |
| 186 | + $("#article_published_false").click(show_hide_token_input); | |
| 187 | + $("#article_published_true").click(show_hide_token_input); | |
| 188 | + } | |
| 189 | + | |
| 175 | 190 | }); | ... | ... |