Commit ce9e80c8df11255286264e77dbac8c78fc1f32ed

Authored by Victor Costa
2 parents db62fbb8 df49d037

Merge branch 'next' into serpro-context

app/controllers/public/account_controller.rb
... ... @@ -315,7 +315,11 @@ class AccountController < ApplicationController
315 315 session[:notice] = nil # consume the notice
316 316 end
317 317  
318   - @plugins.each { |plugin| user_data.merge!(plugin.user_data_extras) }
  318 + @plugins.each do |plugin|
  319 + user_data_extras = plugin.user_data_extras
  320 + user_data_extras = instance_exec(&user_data_extras) if user_data_extras.kind_of?(Proc)
  321 + user_data.merge!(user_data_extras)
  322 + end
319 323  
320 324 render :text => user_data.to_json, :layout => false, :content_type => "application/javascript"
321 325 end
... ...
app/models/profile.rb
... ... @@ -3,7 +3,7 @@
3 3 # which by default is the one returned by Environment:default.
4 4 class Profile < ActiveRecord::Base
5 5  
6   - attr_accessible :name, :identifier, :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :environment, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time, :redirection_after_login, :email_suggestions, :allow_members_to_invite, :invite_friends_only
  6 + attr_accessible :name, :identifier, :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :environment, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time, :redirection_after_login, :email_suggestions, :allow_members_to_invite, :invite_friends_only, :secret
7 7  
8 8 # use for internationalizable human type names in search facets
9 9 # reimplement on subclasses
... ... @@ -119,9 +119,9 @@ class Profile &lt; ActiveRecord::Base
119 119 Profile.column_names.map{|n| [Profile.table_name, n].join('.')}.join(',')
120 120 end
121 121  
122   - scope :visible, :conditions => { :visible => true }
  122 + scope :visible, :conditions => { :visible => true, :secret => false }
123 123 scope :disabled, :conditions => { :visible => false }
124   - scope :public, :conditions => { :visible => true, :public_profile => true }
  124 + scope :public, :conditions => { :visible => true, :public_profile => true, :secret => false }
125 125 scope :enabled, :conditions => { :enabled => true }
126 126  
127 127 # Subclasses must override this method
... ...
app/models/user.rb
... ... @@ -159,6 +159,7 @@ class User &lt; ActiveRecord::Base
159 159 @task.name = self.name
160 160 @task.email = self.email
161 161 @task.target = self.environment
  162 + @task.requestor = self.person
162 163 @task.save
163 164 end
164 165  
... ... @@ -301,6 +302,10 @@ class User &lt; ActiveRecord::Base
301 302 end
302 303 end
303 304  
  305 + def moderate_registration_pending?
  306 + return ModerateUserRegistration.exists?(:requestor_id => self.person.id, :target_id => self.environment.id, :status => Task::Status::ACTIVE)
  307 + end
  308 +
304 309 def data_hash(gravatar_default = nil)
305 310 friends_list = {}
306 311 enterprises = person.enterprises.map { |e| { 'name' => e.short_name, 'identifier' => e.identifier } }
... ...
app/views/favorite_enterprises/index.html.erb
... ... @@ -9,7 +9,7 @@
9 9 enterprise.identifier, :class => 'profile-link' %>
10 10 <%# profile_image_link enterprise, :portrait, 'div' %>
11 11 <div class="controll">
12   - <%= button(:delete, _('remove'), { :action => 'remove', :id => enterprise.id },:title => _('remove')) %>
  12 + <%= button_without_text(:delete, _('remove'), { :action => 'remove', :id => enterprise.id },:title => _('remove')) %>
13 13 </div><!-- end class="controll" -->
14 14 </li>
15 15 <% end %>
... ...
app/views/layouts/application-ng.html.erb
... ... @@ -6,6 +6,10 @@
6 6 <!--<meta http-equiv="refresh" content="1"/>-->
7 7 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
8 8  
  9 + <% unless defined? MetadataPlugin and environment.enabled_plugins.include? 'MetadataPlugin' %>
  10 + <meta name="description" content="<%= @environment.name %>" />
  11 + <% end %>
  12 +
9 13 <!-- site root -->
10 14 <meta property="noosfero:root" content="<%= Noosfero.root %>"/>
11 15  
... ...
app/views/profile_editor/edit.html.erb
... ... @@ -34,10 +34,13 @@
34 34 </div>
35 35 <% else %>
36 36 <div>
37   - <%= labelled_radio_button _('Public &mdash; show content of this group to all internet users'), 'profile_data[public_profile]', true, @profile.public_profile? %>
  37 + <%= labelled_check_box _("Secret &mdash; hide the community and all its contents for non members and other people can't join this community unless they are invited to."), 'profile_data[secret]', true, profile.secret, :class => "profile-secret-box" %>
38 38 </div>
39 39 <div>
40   - <%= labelled_radio_button _('Private &mdash; show content of this group only to members'), 'profile_data[public_profile]', false, !@profile.public_profile? %>
  40 + <%= labelled_radio_button _('Public &mdash; show content of this group to all internet users'), 'profile_data[public_profile]', true, @profile.public_profile?, :class => "public-community-button" %>
  41 + </div>
  42 + <div>
  43 + <%= labelled_radio_button _('Private &mdash; show content of this group only to members'), 'profile_data[public_profile]', false, !@profile.public_profile?, :class => "private-community-button" %>
41 44 </div>
42 45 <% end %>
43 46  
... ... @@ -85,4 +88,6 @@
85 88 <% end %>
86 89 <% end %>
87 90 <% end %>
88   -<% end %>
89 91 \ No newline at end of file
  92 +<% end %>
  93 +
  94 +<%= javascript_include_tag 'profile_editor' %>
... ...
db/migrate/20150223180806_add_secret_to_profile.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +class AddSecretToProfile < ActiveRecord::Migration
  2 + def change
  3 + add_column :profiles, :secret, :boolean, :default => false
  4 + end
  5 +end
... ...
db/schema.rb
... ... @@ -11,7 +11,7 @@
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13  
14   -ActiveRecord::Schema.define(:version => 20150122165042) do
  14 +ActiveRecord::Schema.define(:version => 20150223180806) do
15 15  
16 16 create_table "abuse_reports", :force => true do |t|
17 17 t.integer "reporter_id"
... ... @@ -535,6 +535,7 @@ ActiveRecord::Schema.define(:version =&gt; 20150122165042) do
535 535 t.integer "welcome_page_id"
536 536 t.boolean "allow_members_to_invite", :default => true
537 537 t.boolean "invite_friends_only", :default => false
  538 + t.boolean "secret", :default => false
538 539 end
539 540  
540 541 add_index "profiles", ["activities_count"], :name => "index_profiles_on_activities_count"
... ...
features/secret_community.feature 0 → 100644
... ... @@ -0,0 +1,60 @@
  1 +Feature: Use a secret community
  2 + As a community administrator
  3 + I want to manage the community privacy
  4 +
  5 + Background:
  6 + Given the following users
  7 + | login | name |
  8 + | jose | Jose Wilker |
  9 + | maria | Maria Carminha |
  10 + And the following community
  11 + | identifier | name |
  12 + | mycommunity | My Community |
  13 + And "Jose Wilker" is admin of "My Community"
  14 + And I am logged in as "jose"
  15 + And I go to mycommunity's control panel
  16 + And I follow "Community Info and settings"
  17 + And I check "Secret"
  18 + And I press "Save"
  19 + And I follow "Logout"
  20 +
  21 + @selenium
  22 + Scenario: Hide privacity options when secret is checked
  23 + Given I am logged in as "jose"
  24 + And I go to mycommunity's control panel
  25 + And I follow "Community Info and settings"
  26 + Then I should not see "Public — show content of this group to all internet users"
  27 + And I should not see "Private — show content of this group only to members"
  28 + And I uncheck "Secret"
  29 + Then I should see "Public — show content of this group to all internet users"
  30 + Then I should see "Private — show content of this group only to members"
  31 +
  32 + @selenium
  33 + Scenario: Non members shouldn't see secret communit's content
  34 + Given I am logged in as "maria"
  35 + And I go to mycommunity's homepage
  36 + And I should see "Access denied"
  37 + And I follow "Communities"
  38 + Then I should not see "My Community"
  39 +
  40 + Scenario: A member should see the secret community's content
  41 + Given I am logged in as "maria"
  42 + And "Maria Carminha" is a member of "My Community"
  43 + And I go to maria's control panel
  44 + And I follow "Manage my groups"
  45 + And I follow "My Community"
  46 + Then I should see "My Community"
  47 +
  48 + @selenium
  49 + Scenario: public article on a secret profile should not be displayed
  50 + Given I am logged in as "jose"
  51 + And I go to mycommunity's control panel
  52 + And I follow "Manage Content"
  53 + And I follow "New content"
  54 + And I follow "Text article with visual editor"
  55 + And I fill in "Title" with "My public article"
  56 + And I choose "Public"
  57 + And I press "Save and continue"
  58 + When I am logged in as "maria"
  59 + And I go to /mycommunity/my-public-article
  60 + Then I should not see "My public article"
... ...
lib/user_activation_job.rb
1 1 class UserActivationJob < Struct.new(:user_id)
2 2 def perform
3 3 user = User.find(user_id)
4   - user.destroy unless user.activated? || user.person.is_template?
  4 + user.destroy unless user.activated? || user.person.is_template? || user.moderate_registration_pending?
5 5 end
6 6 end
... ...
plugins/breadcrumbs/lib/breadcrumbs_plugin/content_breadcrumbs_block.rb
... ... @@ -2,8 +2,9 @@ class BreadcrumbsPlugin::ContentBreadcrumbsBlock &lt; Block
2 2  
3 3 settings_items :show_cms_action, :type => :boolean, :default => true
4 4 settings_items :show_profile, :type => :boolean, :default => true
  5 + settings_items :show_section_name, :type => :boolean, :default => true
5 6  
6   - attr_accessible :show_cms_action, :show_profile
  7 + attr_accessible :show_cms_action, :show_profile, :show_section_name
7 8  
8 9 def self.description
9 10 _('Content Breadcrumbs')
... ... @@ -40,7 +41,18 @@ class BreadcrumbsPlugin::ContentBreadcrumbsBlock &lt; Block
40 41 proc do
41 42 trail = block.trail(@page, @profile, params)
42 43 if !trail.empty?
43   - trail.map { |t| link_to(t[:name], t[:url], :class => 'item') }.join(content_tag('span', ' > ', :class => 'separator'))
  44 + separator = content_tag('span', ' > ', :class => 'separator')
  45 +
  46 + breadcrumb = trail.map do |t|
  47 + link_to(t[:name], t[:url], :class => 'item')
  48 + end.join(separator)
  49 +
  50 + if block.show_section_name
  51 + section_name = block.show_profile ? trail.second[:name] : trail.first[:name]
  52 + breadcrumb << content_tag('div', section_name, :class => 'section-name')
  53 + end
  54 +
  55 + breadcrumb
44 56 else
45 57 ''
46 58 end
... ...
plugins/breadcrumbs/test/functional/profile_design_controller_test.rb
... ... @@ -41,4 +41,9 @@ class ProfileDesignControllerTest &lt; ActionController::TestCase
41 41 assert !@block.show_cms_action
42 42 end
43 43  
  44 + should 'be able save breadcrumbs block with show_section_name option' do
  45 + get :edit, :id => @block.id, :profile => @profile.identifier
  46 + post :save, :id => @block.id, :profile => @profile.identifier, :block => {:title => 'breadcrumbs', :show_cms_action => false, :show_profile => true, :show_section_name => true }
  47 + assert @block.show_section_name
  48 + end
44 49 end
... ...
plugins/breadcrumbs/views/box_organizer/breadcrumbs_plugin/_content_breadcrumbs_block.html.erb
1 1 <div id='edit-breadcrumbs-block'>
2 2 <%= labelled_form_field check_box(:block, :show_cms_action) + _('Show cms action'), '' %>
3 3 <%= labelled_form_field check_box(:block, :show_profile) + _('Show profile'), '' %>
  4 + <%= labelled_form_field check_box(:block, :show_section_name) + _('Show section name'), '' %>
4 5 </div>
... ...
plugins/metadata/lib/ext/environment.rb
... ... @@ -2,6 +2,10 @@ require_dependency &#39;environment&#39;
2 2  
3 3 class Environment
4 4  
  5 + metadata_spec tags: {
  6 + description: proc{ |e, plugin| e.name },
  7 + }
  8 +
5 9 metadata_spec namespace: :og, tags: {
6 10 type: 'website',
7 11 title: proc{ |e, plugin| e.name },
... ...
plugins/pg_search/db/migrate/20130320010063_create_indexes_for_search.rb
1 1 class CreateIndexesForSearch < ActiveRecord::Migration
  2 + SEARCHABLES = %w[ article comment qualifier national_region certifier profile license scrap category ]
  3 + KLASSES = SEARCHABLES.map {|searchable| searchable.camelize.constantize }
2 4 def self.up
3   - searchables = %w[ article comment qualifier national_region certifier profile license scrap category ]
4   - klasses = searchables.map {|searchable| searchable.camelize.constantize }
5   - klasses.each do |klass|
  5 + KLASSES.each do |klass|
6 6 fields = klass.pg_search_plugin_fields
7 7 execute "create index pg_search_plugin_#{klass.name.singularize.downcase} on #{klass.table_name} using gin(to_tsvector('simple', #{fields}))"
8 8 end
9 9 end
10 10  
11 11 def self.down
12   - klasses.each do |klass|
  12 + KLASSES.each do |klass|
13 13 execute "drop index pg_search_plugin_#{klass.name.singularize.downcase}"
14 14 end
15 15 end
... ...
public/javascripts/application.js
... ... @@ -1064,7 +1064,7 @@ jQuery(document).ready(function(){
1064 1064 function apply_zoom_to_images(zoom_text) {
1065 1065 jQuery(function($) {
1066 1066 $(window).load( function() {
1067   - $('#article .article-body img').each( function(index) {
  1067 + $('#article .article-body img:not(.disable-zoom)').each( function(index) {
1068 1068 var original = original_image_dimensions($(this).attr('src'));
1069 1069 if ($(this).width() < original['width'] || $(this).height() < original['height']) {
1070 1070 $(this).wrap('<div class="zoomable-image" />');
... ...
public/javascripts/profile_editor.js 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +(function($){
  2 + 'use strict';
  3 +
  4 + function show_or_hide_privacy_radio_buttons(hide_options) {
  5 + var public_community = $(".public-community-button").parent();
  6 + var private_community = $(".private-community-button").parent();
  7 + if (hide_options) {
  8 + $(".private-community-button").selected();
  9 + public_community.hide();
  10 + private_community.hide();
  11 +
  12 + } else {
  13 + public_community.show();
  14 + private_community.show();
  15 + }
  16 + }
  17 +
  18 + $(document).ready(function(){
  19 + var profile_secret = $(".profile-secret-box");
  20 + show_or_hide_privacy_radio_buttons(profile_secret.is(":checked"));
  21 + profile_secret.change(function(){
  22 + show_or_hide_privacy_radio_buttons(this.checked);
  23 + });
  24 +
  25 + });
  26 +})(jQuery);
... ...
test/functional/account_controller_test.rb
... ... @@ -712,7 +712,9 @@ class AccountControllerTest &lt; ActionController::TestCase
712 712  
713 713 class Plugin2 < Noosfero::Plugin
714 714 def user_data_extras
715   - {:test => 5}
  715 + proc do
  716 + {:test => 5}
  717 + end
716 718 end
717 719 end
718 720 Noosfero::Plugin.stubs(:all).returns([Plugin1.name, Plugin2.name])
... ...
test/unit/profile_test.rb
... ... @@ -443,6 +443,24 @@ class ProfileTest &lt; ActiveSupport::TestCase
443 443 assert_not_includes result, p2
444 444 end
445 445  
  446 + should 'be able to find the public profiles but not secret ones' do
  447 + p1 = create(Profile, :public_profile => true)
  448 + p2 = create(Profile, :public_profile => true, :secret => true)
  449 +
  450 + result = Profile.public
  451 + assert_includes result, p1
  452 + assert_not_includes result, p2
  453 + end
  454 +
  455 + should 'be able to find visible profiles but not secret ones' do
  456 + p1 = create(Profile, :visible => true)
  457 + p2 = create(Profile, :visible => true, :secret => true)
  458 +
  459 + result = Profile.visible
  460 + assert_includes result, p1
  461 + assert_not_includes result, p2
  462 + end
  463 +
446 464 should 'have public content by default' do
447 465 assert_equal true, Profile.new.public_content
448 466 end
... ... @@ -485,7 +503,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
485 503 should 'categorize in the entire category hierarchy' do
486 504 c1 = fast_create(Category)
487 505 c2 = fast_create(Category, :parent_id => c1.id)
488   - c3 = fast_create(Category, :parent_id => c2.id)
  506 + c3 = fast_create(Category, :parent_id => c2.id)
489 507  
490 508 profile = create_user('testuser').person
491 509 profile.add_category(c3)
... ... @@ -1006,7 +1024,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1006 1024  
1007 1025 should 'copy header when applying template' do
1008 1026 template = fast_create(Profile)
1009   - template[:custom_header] = '{name}'
  1027 + template[:custom_header] = '{name}'
1010 1028 template.save!
1011 1029  
1012 1030 p = create(Profile, :name => 'test prof')
... ... @@ -1260,7 +1278,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1260 1278 task2 = Task.create!(:requestor => person, :target => another)
1261 1279  
1262 1280 person.stubs(:is_admin?).with(other).returns(true)
1263   - Environment.find(:all).select{|i| i != other }.each do |env|
  1281 + Environment.find(:all).select{|i| i != other }.each do |env|
1264 1282 person.stubs(:is_admin?).with(env).returns(false)
1265 1283 end
1266 1284  
... ... @@ -1729,7 +1747,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1729 1747 assert profile.is_on_homepage?("/#{profile.identifier}/#{homepage.slug}", homepage)
1730 1748 end
1731 1749  
1732   -
  1750 +
1733 1751 should 'find profiles with image' do
1734 1752 env = fast_create(Environment)
1735 1753 2.times do |n|
... ...
test/unit/user_activation_job_test.rb
... ... @@ -40,6 +40,18 @@ class UserActivationJobTest &lt; ActiveSupport::TestCase
40 40 end
41 41 end
42 42  
  43 + should 'not destroy user if a moderate user registration task exists' do
  44 + env = Environment.default
  45 + env.enable('skip_new_user_email_confirmation')
  46 + env.enable('admin_must_approve_new_users')
  47 + user = new_user :login => 'test3'
  48 + job = UserActivationJob.new(user.id)
  49 + assert_no_difference 'User.count' do
  50 + job.perform
  51 + process_delayed_job_queue
  52 + end
  53 + end
  54 +
43 55 protected
44 56 def new_user(options = {})
45 57 user = User.new({ :login => 'quire', :email => 'quire@example.com', :password => 'quire', :password_confirmation => 'quire' }.merge(options))
... ...
test/unit/user_test.rb
... ... @@ -302,6 +302,17 @@ class UserTest &lt; ActiveSupport::TestCase
302 302 assert !user.email_activation_pending?
303 303 end
304 304  
  305 + should 'has moderate registration pending' do
  306 + user = create_user('cooler')
  307 + ModerateUserRegistration.create!(:requestor => user.person, :target => Environment.default)
  308 + assert user.moderate_registration_pending?
  309 + end
  310 +
  311 + should 'not has moderate registration pending if not have a pending task' do
  312 + user = create_user('cooler')
  313 + assert !user.moderate_registration_pending?
  314 + end
  315 +
305 316 should 'be able to use [] operator to find users by login' do
306 317 user = fast_create(User)
307 318 assert_equal user, User[user.login]
... ...