Commit 3a320e4ba3c282ec1140f602761d96b61df74ca6

Authored by Francisco Marcelo de Araújo Lima Júnior
2 parents 8455bcd4 3193dfa1

Merge branch 'rails3-custom_fields' into rails3_stable

app/controllers/application_controller.rb
... ... @@ -8,7 +8,7 @@ class ApplicationController < ActionController::Base
8 8 before_filter :init_noosfero_plugins
9 9 before_filter :allow_cross_domain_access
10 10 before_filter :login_required, :if => :private_environment?
11   - before_filter :verify_members_whitelist, :if => :user
  11 + before_filter :verify_members_whitelist, :if => [:private_environment?, :user]
12 12  
13 13 def verify_members_whitelist
14 14 render_access_denied unless user.is_admin? || environment.in_whitelist?(user)
... ...
app/controllers/my_profile/profile_editor_controller.rb
... ... @@ -14,7 +14,10 @@ class ProfileEditorController < MyProfileController
14 14 @profile_data = profile
15 15 @possible_domains = profile.possible_domains
16 16 if request.post?
17   - params[:profile_data][:fields_privacy] ||= {} if profile.person? && params[:profile_data].is_a?(Hash)
  17 + if profile.person? && params[:profile_data].is_a?(Hash)
  18 + params[:profile_data][:fields_privacy] ||= {}
  19 + params[:profile_data][:custom_fields] ||= {}
  20 + end
18 21 Profile.transaction do
19 22 Image.transaction do
20 23 if @profile_data.update_attributes(params[:profile_data])
... ...
app/controllers/public/account_controller.rb
... ... @@ -77,6 +77,13 @@ class AccountController < ApplicationController
77 77 render :text => { :ok=>true, :key=>key }.to_json
78 78 end
79 79  
  80 + def custom_fields_for_template
  81 + custom_fields ||= environment.people.templates.find(params[:template_id]).custom_fields.map { |k,v|
  82 + { :name => k, :title => v[:title] } if v['signup']
  83 + }.compact
  84 + render :text => {:ok => true, :custom_fields => custom_fields}.to_json
  85 + end
  86 +
80 87 # action to register an user to the application
81 88 def signup
82 89 if @plugins.dispatch(:allow_user_registration).include?(false)
... ...
app/helpers/application_helper.rb
... ... @@ -1304,17 +1304,8 @@ module ApplicationHelper
1304 1304 templates = environment.send(kind).templates
1305 1305 return '' if templates.count == 0
1306 1306 return hidden_field_tag("#{field_name}[template_id]", templates.first.id) if templates.count == 1
1307   -
1308   - radios = templates.map do |template|
1309   - content_tag('li', labelled_radio_button(link_to(template.name, template.url, :target => '_blank'), "#{field_name}[template_id]", template.id, environment.is_default_template?(template)))
1310   - end.join("\n")
1311   -
1312   - content_tag('div', content_tag('label', _('Profile organization'), :for => 'template-options', :class => 'formlabel') +
1313   - content_tag('p', _('Your profile will be created according to the selected template. Click on the options to view them.'), :style => 'margin: 5px 15px;padding: 0px 10px;') +
1314   - content_tag('ul', radios, :style => 'list-style: none; padding-left: 20px; margin-top: 0.5em;'),
1315   - :id => 'template-options',
1316   - :style => 'margin-top: 1em'
1317   - )
  1307 + options = options_for_select(templates.collect{ |template| [template.name, template.id]})
  1308 + content_tag('div', content_tag('label', _('Profile organization'), :class => 'formlabel') + (select_tag 'profile_data[template_id]', options, :onchange => 'show_fields_for_template(this);'))
1318 1309 end
1319 1310  
1320 1311 def expirable_content_reference(content, action, text, url, options = {})
... ...
app/helpers/profile_helper.rb
... ... @@ -40,4 +40,22 @@ module ProfileHelper
40 40 end
41 41 end
42 42  
  43 + def display_custom_field(title, profile, field, force = false)
  44 + unless force || profile.may_display_field_to?(field, user)
  45 + return
  46 + end
  47 + value = profile.custom_fields[field][:value]
  48 + !value.blank? ? content_tag('tr', content_tag('td', title) + content_tag('td', value)) : ''
  49 + end
  50 +
  51 + def display_custom_fields(profile)
  52 + fields = []
  53 + profile.custom_fields.each { |custom_field_key,custom_field_data|
  54 + if !profile.fields_privacy.blank? && profile.fields_privacy.include?(custom_field_key)
  55 + fields << display_custom_field(custom_field_data[:title], profile, custom_field_key) if profile.fields_privacy[custom_field_key] == 'public'
  56 + end
  57 + }
  58 + fields.size >= 1 ? content_tag('tr', content_tag('th', _('Custom Fields'), { :colspan => 2 })) + fields.join.html_safe : ''
  59 + end
  60 +
43 61 end
... ...
app/models/person.rb
... ... @@ -152,7 +152,7 @@ class Person &lt; Profile
152 152 organization
153 153 organization_website
154 154 contact_phone
155   - contact_information
  155 + contact_informatioin
156 156 ]
157 157  
158 158 validates_multiparameter_assignments
... ...
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
  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, :custom_fields
7 7  
8 8 # use for internationalizable human type names in search facets
9 9 # reimplement on subclasses
... ... @@ -23,6 +23,30 @@ class Profile &lt; ActiveRecord::Base
23 23  
24 24 SEARCH_DISPLAYS = %w[compact]
25 25  
  26 + settings_items :custom_fields, :default => {}
  27 +
  28 + def custom_field_value(field)
  29 + self.custom_fields[field][:value]
  30 + end
  31 +
  32 + def custom_field_title(field)
  33 + if !self.custom_fields.blank?
  34 + self.custom_fields[field][:title]
  35 + else
  36 + ''
  37 + end
  38 + end
  39 +
  40 + def custom_fields_template
  41 + fields = {}
  42 + fields = self.template.custom_fields unless self.template.blank?
  43 + fields
  44 + end
  45 +
  46 + def custom_fields_template_title(field)
  47 + self.template.custom_fields[field][:title]
  48 + end
  49 +
26 50 def self.default_search_display
27 51 'compact'
28 52 end
... ...
app/views/account/_signup_form.html.erb
... ... @@ -103,14 +103,44 @@
103 103  
104 104 <div id="signup-form-profile">
105 105  
106   - <%= labelled_fields_for :profile_data, @person do |f| %>
107   - <%= render :partial => 'profile_editor/person_form', :locals => {:f => f} %>
108   - <% end %>
109   -
110   - <%= @plugins.dispatch(:signup_extra_contents).collect { |content| instance_eval(&content) }.join("") %>
  106 + <script>
  107 + function show_fields_for_template(element) {
  108 + jQuery('div#signup-form-profile div.formfieldline').remove();
  109 + var selected_template = element.options[element.selectedIndex].value;
  110 + jQuery.ajax({
  111 + type: "GET",
  112 + url: "<%= url_for :controller=>'account', :action=>'custom_fields_for_template' %>",
  113 + dataType: 'json',
  114 + data: { template_id : selected_template },
  115 + success: function(data) {
  116 + if (data.ok) {
  117 + data.custom_fields.each(function(field) {
  118 + html = '<div class="formfieldline">' +
  119 + '<label class="formlabel" for="profile_data_custom_fields_{#CUSTOM_FIELD_ID#}">{#CUSTOM_FIELD_NAME#}</label>' +
  120 + '<input type="hidden" name="profile_data[custom_fields][{#CUSTOM_FIELD_ID#}][title]" id="profile_data_custom_fields_{#CUSTOM_FIELD_ID#}_title" value="{#CUSTOM_FIELD_NAME#}" />' +
  121 + '<div class="formfield type-text">' +
  122 + '<input type="text" name="profile_data[custom_fields][{#CUSTOM_FIELD_ID#}][value]" id="profile_data_custom_fields_{#CUSTOM_FIELD_ID#}_value" />' +
  123 + '</div>' +
  124 + '</div>';
  125 +
  126 + html = html.replace( /{#CUSTOM_FIELD_ID#}/g, field.name );
  127 + html = html.replace( /{#CUSTOM_FIELD_NAME#}/g, field.title );
  128 + jQuery('div#signup-form-profile').append(html);
  129 + });
  130 + };
  131 + }
  132 + });
  133 + }
  134 + </script>
111 135  
112 136 <%= template_options(:people, 'profile_data') %>
113 137  
  138 + <%#= labelled_fields_for :profile_data, @person do |f| %>
  139 + <%#= render :partial => 'profile_editor/person_form', :locals => {:f => f} %>
  140 + <%# end %>
  141 +
  142 + <%= @plugins.dispatch(:signup_extra_contents).collect { |content| instance_eval(&content) }.join("") %>
  143 +
114 144 <% unless @terms_of_use.blank? %>
115 145 <div id='terms-of-use-box' class='formfieldline'>
116 146 <%= labelled_check_box(_('I accept the %s') % link_to(_('terms of use'), {:controller => 'home', :action => 'terms'}, :target => '_blank'), 'user[terms_accepted]') %>
... ...
app/views/profile/_person_profile.html.erb
... ... @@ -18,6 +18,8 @@
18 18 <% cache_timeout(profile.relationships_cache_key, 4.hours) do %>
19 19 <%= display_work_info profile %>
20 20  
  21 + <%= display_custom_fields(profile) %>
  22 +
21 23 <tr>
22 24 <th colspan='2'><%= _('Network')%></th>
23 25 </tr>
... ... @@ -40,4 +42,3 @@
40 42  
41 43 <% end %>
42 44 </table>
43   -
... ...
app/views/profile_editor/_person_form.html.erb
... ... @@ -64,3 +64,74 @@
64 64 <%= optional_field(@person, 'professional_activity', f.text_field(:professional_activity, :rel => _('Professional activity'))) %>
65 65 <%= optional_field(@person, 'organization', f.text_field(:organization, :rel => _('Organization'))) %>
66 66 <%= optional_field(@person, 'organization_website', f.text_field(:organization_website, :rel => _('Organization website'))) %>
  67 +
  68 +<br />
  69 +
  70 +<div id="custom-fields-container">
  71 +
  72 + <h2><%= _('Custom fields') %></h2>
  73 +
  74 + <% if @person.is_template? %>
  75 +
  76 + <%= javascript_include_tag "manage-custom-fields.js" %>
  77 +
  78 + <table border="0" style="display: none;">
  79 + <tr>
  80 + <th align="left"><%= _('Field name') %></th>
  81 + <th><%= _('Display on signup?') %></th>
  82 + <th>&nbsp;</th>
  83 + </tr>
  84 +
  85 + <% @person.custom_fields.each { |field,value| %>
  86 + <tr>
  87 + <td>
  88 + <%= text_field_tag( "profile_data[custom_fields][#{field}][title]", value[:title], :style => "display:block") %>
  89 + </td>
  90 + <td align="center">
  91 + <%= check_box_tag "profile_data[custom_fields][#{field}][signup]", value['signup'], value['signup'], :onclick => "signup_action('profile_data[custom_fields][#{field}][active]','profile_data[custom_fields][#{field}][required]', 'profile_data[custom_fields][#{field}][signup]')" %>
  92 + </td>
  93 + <td align="center">
  94 + <%= link_to content_tag(:span, _('Delete')), '#', onclick: "return remove_custom_field(this);", title: "Delete", class: "button icon-delete" %>
  95 + </td>
  96 + </tr>
  97 + <% } %>
  98 +
  99 + </table>
  100 +
  101 + <% if @person.custom_fields.length > 0 %>
  102 + <script>
  103 + jQuery('#custom-fields-container table').css('display', 'table');
  104 + </script>
  105 + <% end %>
  106 +
  107 + <span>
  108 + <%= link_to_function(_('Add field'), "add_new_field('person');", :class => 'button icon-add with-text') %>
  109 + </span>
  110 +
  111 + <% else %>
  112 +
  113 + <% @person.custom_fields_template.each { |field,value| %>
  114 +
  115 + <div class="field-with-privacy-selector">
  116 + <div class="formfieldline">
  117 +
  118 + <span style="display: block;">
  119 + <%= label_tag @person.custom_fields_template_title(field) %>
  120 + </span>
  121 +
  122 + <div class="formfield type-text" style="display: inline-block;">
  123 + <%= hidden_field_tag "profile_data[custom_fields][#{field}[title]", @person.custom_fields_template_title(field) %>
  124 + <%= text_field_tag( "profile_data[custom_fields][#{field}][value]", @person.custom_field_value(field), :size => 30 ) %>
  125 + </div>
  126 +
  127 + </div>
  128 +
  129 + <%= profile_field_privacy_selector @person, field %>
  130 +
  131 + </div>
  132 +
  133 + <% } %>
  134 +
  135 + <% end %>
  136 +
  137 +</div>
... ...
public/javascripts/manage-custom-fields.js 0 → 100644
... ... @@ -0,0 +1,72 @@
  1 +function update_active(name_active, name_required, name_signup) {
  2 + var required = jQuery("input[name='" + name_required + "']")[0]
  3 + var signup = jQuery("input[name='" + name_signup + "']")[0]
  4 + var active = jQuery("input[name='" + name_active + "']")[0]
  5 +
  6 + if(required.checked || signup.checked)
  7 + active.checked = true
  8 +}
  9 +
  10 +function active_action(obj_active, name_required, name_signup) {
  11 + var required = jQuery("input[name='" + name_required + "']")[0]
  12 + var signup = jQuery("input[name='" + name_signup + "']")[0]
  13 +
  14 + required.disabled = signup.disabled = !obj_active.checked
  15 +}
  16 +
  17 +function required_action(name_active, name_required, name_signup) {
  18 + var obj_required = jQuery("input[name='" + name_required + "']")[0]
  19 +
  20 + if(obj_required.checked) {
  21 + jQuery("input[name='" + name_signup + "']")[0].checked = true
  22 + }
  23 +
  24 + update_active(name_active, name_required, name_signup)
  25 +}
  26 +
  27 +function signup_action(name_active, name_required, name_signup) {
  28 + var obj_signup = jQuery("input[name='" + name_signup + "']")[0]
  29 +
  30 + if(!obj_signup.checked) {
  31 + jQuery("input[name='" + name_required + "']")[0].checked = false
  32 + }
  33 +
  34 + update_active(name_active, name_required, name_signup)
  35 +}
  36 +
  37 +function remove_custom_field(element) {
  38 + jQuery(element).parent().parent().remove();
  39 + if ( (jQuery('#custom-fields-container tr').length) == 1 ) {
  40 + jQuery('#custom-fields-container table').hide();
  41 + }
  42 + return false;
  43 +}
  44 +
  45 +function add_new_field() {
  46 + var next_custom_field_id;
  47 + var re = /\d+/g;
  48 +
  49 + if ( (jQuery('#custom-fields-container tr').length) == 1 ) {
  50 + next_custom_field_id = 1;
  51 + }
  52 + else {
  53 + next_custom_field_id = parseInt(re.exec( jQuery('#custom-fields-container input').last().attr('id') )[0]) + 1;
  54 + }
  55 +
  56 + jQuery('#custom-fields-container table').show();
  57 +
  58 + new_custom_field = '' +
  59 + '<tr>' +
  60 + '<td>' +
  61 + '<input id="profile_data_custom_fields_custom_field_' + next_custom_field_id + '_title" name="profile_data[custom_fields][custom_field_' + next_custom_field_id + '][title]" style="display:block" type="text" value="">' +
  62 + '</td>' +
  63 + '<td align="center">' +
  64 + '<input id="profile_data_custom_fields_custom_field_' + next_custom_field_id + '_signup" name="profile_data[custom_fields][custom_field_' + next_custom_field_id + '][signup]" onclick="signup_action("profile_data[custom_fields][custom_field_' + next_custom_field_id + '][active]","profile_data[custom_fields][custom_field_' + next_custom_field_id + '][required]", "profile_data[custom_fields][custom_field_' + next_custom_field_id + '][signup]")" type="checkbox">' +
  65 + '</td>' +
  66 + '<td align="center">' +
  67 + '<a href="#" class="button icon-delete link-this-page" onclick="return remove_custom_field(this);" title="Delete"><span>Delete</span></a>' +
  68 + '</td>' +
  69 + '</tr>'
  70 +
  71 + jQuery('#custom-fields-container tbody').append(new_custom_field);
  72 +}
... ...
public/stylesheets/application.css
... ... @@ -5937,6 +5937,7 @@ li.profile-activity-item.upload_image .activity-gallery-images-count-1 img {
5937 5937 -webkit-border-radius: 8px;
5938 5938 margin: 60px auto 5px;
5939 5939 position: relative;
  5940 + width: 400px;
5940 5941 }
5941 5942  
5942 5943 #signup-form input.invalid_input {
... ... @@ -5985,7 +5986,7 @@ li.profile-activity-item.upload_image .activity-gallery-images-count-1 img {
5985 5986 #signup-form select {
5986 5987 height: auto;
5987 5988 padding-right: 3px;
5988   - width: 365px;
  5989 + width: 100%;
5989 5990 }
5990 5991  
5991 5992 #signup-form .select-birth-date select {
... ... @@ -6366,12 +6367,12 @@ li.profile-activity-item.upload_image .activity-gallery-images-count-1 img {
6366 6367 }
6367 6368  
6368 6369 .controller-profile_editor #profile-data {
6369   - display: table;
  6370 + /*display: table;*/
6370 6371 width: auto;
6371 6372 }
6372 6373  
6373 6374 .field-with-privacy-selector {
6374   - display: table-row;
  6375 + /*display: table-row;*/
6375 6376 }
6376 6377  
6377 6378 .field-with-privacy-selector:hover {
... ... @@ -6379,14 +6380,38 @@ li.profile-activity-item.upload_image .activity-gallery-images-count-1 img {
6379 6380 }
6380 6381  
6381 6382 .controller-profile_editor #profile-data .field-with-privacy-selector .formfieldline {
6382   - width: auto;
  6383 + /*width: auto;*/
  6384 + display: inline-block;
6383 6385 }
6384 6386  
6385 6387 .field-privacy-selector {
6386   - display: table-cell;
  6388 + /*display: table-cell;*/
  6389 + display: inline-block;
6387 6390 vertical-align: middle;
6388 6391 text-align: center;
6389 6392 width: 100px;
  6393 + float: right;
  6394 + position: relative;
  6395 + top: 15px;
  6396 +}
  6397 +
  6398 +#custom-fields-container {
  6399 + margin-bottom: 25px;
  6400 +}
  6401 +
  6402 +#custom-fields-container label.required {
  6403 + font-weight: bold;
  6404 + color: #c00;
  6405 +}
  6406 +
  6407 +#custom-fields-container table {
  6408 + margin-bottom: 5px;
  6409 + border-bottom: 1px solid #c0c0c0;
  6410 +}
  6411 +
  6412 +#custom-fields-container th {
  6413 + border-top: 1px solid #c0c0c0;
  6414 + border-bottom: 1px solid #c0c0c0;
6390 6415 }
6391 6416  
6392 6417 #profile_change_picture {
... ...
test/functional/application_controller_test.rb
... ... @@ -564,9 +564,10 @@ class ApplicationControllerTest &lt; ActionController::TestCase
564 564 assert_redirected_to :controller => 'account', :action => 'login'
565 565 end
566 566  
567   - should 'do not allow member not included in whitelist to access an environment' do
  567 + should 'do not allow member not included in whitelist to access an restricted environment' do
568 568 user = create_user
569 569 e = Environment.default
  570 + e.enable(:restrict_to_members)
570 571 e.members_whitelist_enabled = true
571 572 e.save!
572 573 login_as(user.login)
... ... @@ -604,4 +605,15 @@ class ApplicationControllerTest &lt; ActionController::TestCase
604 605 assert_response :success
605 606 end
606 607  
  608 + should 'not check whitelist members if the environment is not restrict to members' do
  609 + e = Environment.default
  610 + e.disable(:restrict_to_members)
  611 + e.members_whitelist_enabled = true
  612 + e.save!
  613 + @controller.expects(:verify_members_whitelist).never
  614 + login_as create_user.login
  615 + get :index
  616 + assert_response :success
  617 + end
  618 +
607 619 end
... ...