Commit 946bd81026a5103e75454301a0118840015a5d4c
1 parent
f0141cef
Exists in
staging
and in
42 other branches
ActionItem791: 'contact us' feature for enterprises
users can send message to enterprises
the enterprise must choose if 'contact us' is available or not
Showing
17 changed files
with
223 additions
and
4 deletions
Show diff stats
| @@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
| 1 | +class ContactController < PublicController | ||
| 2 | + | ||
| 3 | + needs_profile | ||
| 4 | + | ||
| 5 | + def new | ||
| 6 | + @contact = Contact.new(params[:contact]) | ||
| 7 | + if request.post? | ||
| 8 | + if @contact.save | ||
| 9 | + flash[:notice] = _('Contact successfully sent') | ||
| 10 | + redirect_to :controller => 'profile', :profile => profile.identifier | ||
| 11 | + else | ||
| 12 | + flash[:notice] = _('Contact not sent') | ||
| 13 | + end | ||
| 14 | + end | ||
| 15 | + end | ||
| 16 | + | ||
| 17 | +end |
| @@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
| 1 | +class Contact < Task | ||
| 2 | + | ||
| 3 | + validates_presence_of :target_id, :subject, :email, :message | ||
| 4 | + validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT | ||
| 5 | + | ||
| 6 | + acts_as_having_settings :field => :data | ||
| 7 | + settings_items :subject, :message, :city_and_state, :email, :phone | ||
| 8 | + | ||
| 9 | + def description | ||
| 10 | + _('%s sent a new message') % (requestor ? requestor.name : _('Someone')) | ||
| 11 | + end | ||
| 12 | + | ||
| 13 | +end |
app/models/enterprise.rb
| @@ -57,7 +57,6 @@ class Enterprise < Organization | @@ -57,7 +57,6 @@ class Enterprise < Organization | ||
| 57 | end | 57 | end |
| 58 | end | 58 | end |
| 59 | 59 | ||
| 60 | - | ||
| 61 | def default_set_of_blocks | 60 | def default_set_of_blocks |
| 62 | blocks = [ | 61 | blocks = [ |
| 63 | [MainBlock], | 62 | [MainBlock], |
| @@ -74,6 +73,8 @@ class Enterprise < Organization | @@ -74,6 +73,8 @@ class Enterprise < Organization | ||
| 74 | environment.enterprise_template | 73 | environment.enterprise_template |
| 75 | end | 74 | end |
| 76 | 75 | ||
| 76 | + settings_items :enable_contact_us, :type => :boolean, :default => true | ||
| 77 | + | ||
| 77 | protected | 78 | protected |
| 78 | 79 | ||
| 79 | def default_homepage(attrs) | 80 | def default_homepage(attrs) |
app/views/blocks/profile_info_actions/enterprise.rhtml
| @@ -9,4 +9,7 @@ | @@ -9,4 +9,7 @@ | ||
| 9 | <li><%= link_to content_tag('span', _('Join')), { :profile => user.identifier, :controller => 'memberships', :action => 'join', :id => profile.id }, :class => 'button with-text icon-add', :title => __('Join this enterprise') %></li> | 9 | <li><%= link_to content_tag('span', _('Join')), { :profile => user.identifier, :controller => 'memberships', :action => 'join', :id => profile.id }, :class => 'button with-text icon-add', :title => __('Join this enterprise') %></li> |
| 10 | <% end %> | 10 | <% end %> |
| 11 | <% end %> | 11 | <% end %> |
| 12 | + <% if profile.enable_contact_us %> | ||
| 13 | + <li> <%= link_to content_tag('span', _('Contact us')), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, :class => 'button with-text icon-menu-mail' %> </li> | ||
| 14 | + <% end %> | ||
| 12 | </ul> | 15 | </ul> |
| @@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
| 1 | +<h1><%= _('Contact %s') % profile.name %></h1> | ||
| 2 | + | ||
| 3 | +<%= error_messages_for 'contact' %> | ||
| 4 | + | ||
| 5 | +<% labelled_form_for :contact, @contact do |f| %> | ||
| 6 | + | ||
| 7 | + <%= hidden_field_tag 'contact[target_id]', profile.id %> | ||
| 8 | + <%= hidden_field_tag 'contact[requestor_id]', (logged_in? ? current_user.person.id : nil) %> | ||
| 9 | + <%= f.text_field :subject %> | ||
| 10 | + <%= f.text_field :email %> | ||
| 11 | + <%= f.text_field :city_and_state %> | ||
| 12 | + <%= f.text_field :phone %> | ||
| 13 | + <%= f.text_area :message, :rows => 5 %> | ||
| 14 | + | ||
| 15 | + <%= submit_button(:send, _('Send')) %> | ||
| 16 | + | ||
| 17 | +<% end %> |
app/views/profile_editor/_organization.rhtml
| @@ -9,12 +9,13 @@ | @@ -9,12 +9,13 @@ | ||
| 9 | 9 | ||
| 10 | </div> | 10 | </div> |
| 11 | <%= f.text_field(:acronym) %> | 11 | <%= f.text_field(:acronym) %> |
| 12 | - <%= f.text_field(:address, 'size' => 50) if @profile.kind_of?(Enterprise) %> | 12 | + <%= f.text_field(:address, 'size' => 50) if @profile.enterprise? %> |
| 13 | <%= f.text_field(:foundation_year) %> | 13 | <%= f.text_field(:foundation_year) %> |
| 14 | <%= f.text_field(:contact_person) %> | 14 | <%= f.text_field(:contact_person) %> |
| 15 | <%= f.text_field(:contact_email) %> | 15 | <%= f.text_field(:contact_email) %> |
| 16 | <%= f.text_field(:economic_activity) %> | 16 | <%= f.text_field(:economic_activity) %> |
| 17 | - <%= f.text_area(:description, :rows => 5) if @profile.kind_of?(Community) %> | 17 | + <%= f.text_area(:description, :rows => 5) if @profile.community? %> |
| 18 | + <%= f.check_box(:enable_contact_us) if @profile.enterprise? %> | ||
| 18 | <h1><%= _('Moderation options') %></h1> | 19 | <h1><%= _('Moderation options') %></h1> |
| 19 | <div style='margin-bottom: 1em'> | 20 | <div style='margin-bottom: 1em'> |
| 20 | <%= _('New members must be approved:')%> | 21 | <%= _('New members must be approved:')%> |
| @@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
| 1 | +<h2><%= task.description %></h2> | ||
| 2 | + | ||
| 3 | +<% form_for('task', task, :url => { :action => 'close', :id => task.id}) do |f| %> | ||
| 4 | + | ||
| 5 | + <%= hidden_field_tag(:decision, :finish) %> | ||
| 6 | + <table> | ||
| 7 | + <% %w[ subject email phone city_and_state message ].each do |field| %> | ||
| 8 | + <% if task.respond_to?(field) and !task.send(field).nil? and !task.send(field).empty? %> | ||
| 9 | + <tr> <td><strong><%= _(field.humanize) %></strong></td> <td><%= task.send(field) %></td> </tr> | ||
| 10 | + <% end %> | ||
| 11 | + <% end %> | ||
| 12 | + </table> | ||
| 13 | + | ||
| 14 | + <% button_bar do %> | ||
| 15 | + <%= submit_button(:ok, _('Ok!')) %> | ||
| 16 | + <% end %> | ||
| 17 | + | ||
| 18 | +<% end %> |
config/routes.rb
| @@ -53,6 +53,9 @@ ActionController::Routing::Routes.draw do |map| | @@ -53,6 +53,9 @@ ActionController::Routing::Routes.draw do |map| | ||
| 53 | map.catalog 'catalog/:profile', :controller => 'catalog', :action => 'index', :profile => /#{Noosfero.identifier_format}/ | 53 | map.catalog 'catalog/:profile', :controller => 'catalog', :action => 'index', :profile => /#{Noosfero.identifier_format}/ |
| 54 | map.product 'catalog/:profile/:id', :controller => 'catalog', :action => 'show', :profile => /#{Noosfero.identifier_format}/ | 54 | map.product 'catalog/:profile/:id', :controller => 'catalog', :action => 'show', :profile => /#{Noosfero.identifier_format}/ |
| 55 | 55 | ||
| 56 | + # contact | ||
| 57 | + map.contact 'contact/:profile/:action/:id', :controller => 'contact', :action => 'index', :id => /.*/, :profile => /#{Noosfero.identifier_format}/ | ||
| 58 | + | ||
| 56 | ###################################################### | 59 | ###################################################### |
| 57 | ## Controllers that are profile-specific (for profile admins ) | 60 | ## Controllers that are profile-specific (for profile admins ) |
| 58 | ###################################################### | 61 | ###################################################### |
public/designs/icons/default/style.css
| @@ -5,6 +5,7 @@ | @@ -5,6 +5,7 @@ | ||
| 5 | .icon-open { background-image: url(folder-open.gif) } | 5 | .icon-open { background-image: url(folder-open.gif) } |
| 6 | .icon-cms { background-image: url(abiword_48.png) } | 6 | .icon-cms { background-image: url(abiword_48.png) } |
| 7 | .icon-save { background-image: url(save-HC.gif) } | 7 | .icon-save { background-image: url(save-HC.gif) } |
| 8 | +.icon-send { background-image: url(mail-HC.gif) } | ||
| 8 | .icon-up { background-image: url(go-up-HC.gif) } | 9 | .icon-up { background-image: url(go-up-HC.gif) } |
| 9 | .icon-cancel { background-image: url(cancel-HC.gif) } | 10 | .icon-cancel { background-image: url(cancel-HC.gif) } |
| 10 | .icon-person { background-image: url(user_icon.png) } | 11 | .icon-person { background-image: url(user_icon.png) } |
| @@ -0,0 +1,75 @@ | @@ -0,0 +1,75 @@ | ||
| 1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
| 2 | +require 'contact_controller' | ||
| 3 | + | ||
| 4 | +# Re-raise errors caught by the controller. | ||
| 5 | +class ContactController; def rescue_action(e) raise e end; end | ||
| 6 | + | ||
| 7 | +class ContactControllerTest < Test::Unit::TestCase | ||
| 8 | + | ||
| 9 | + all_fixtures | ||
| 10 | + | ||
| 11 | + def setup | ||
| 12 | + @controller = ContactController.new | ||
| 13 | + @request = ActionController::TestRequest.new | ||
| 14 | + @response = ActionController::TestResponse.new | ||
| 15 | + | ||
| 16 | + @profile = create_user('contact_test_user').person | ||
| 17 | + @enterprise = Enterprise.create!(:identifier => 'contact_test_enterprise', :name => 'Test contact enteprise') | ||
| 18 | + end | ||
| 19 | + attr_reader :profile, :enterprise | ||
| 20 | + | ||
| 21 | + should 'respond to new' do | ||
| 22 | + get :new, :profile => enterprise.identifier | ||
| 23 | + assert_response :success | ||
| 24 | + end | ||
| 25 | + | ||
| 26 | + should 'display destinatary name in title' do | ||
| 27 | + get :new, :profile => enterprise.identifier | ||
| 28 | + assert_tag :tag => 'h1', :content => "Contact #{enterprise.name}" | ||
| 29 | + end | ||
| 30 | + | ||
| 31 | + should 'add form to create contact via post' do | ||
| 32 | + get :new, :profile => enterprise.identifier | ||
| 33 | + assert_tag :tag => 'form', :attributes => { :action => "/contact/#{enterprise.identifier}/new", :method => 'post' } | ||
| 34 | + end | ||
| 35 | + | ||
| 36 | + should 'display input for destinatary email' do | ||
| 37 | + get :new, :profile => enterprise.identifier | ||
| 38 | + assert_tag :tag => 'input', :attributes => { :name => 'contact[email]', :type => 'text' } | ||
| 39 | + end | ||
| 40 | + | ||
| 41 | + should 'display input for message' do | ||
| 42 | + get :new, :profile => enterprise.identifier | ||
| 43 | + assert_tag :tag => 'textarea', :attributes => { :name => 'contact[message]' } | ||
| 44 | + end | ||
| 45 | + | ||
| 46 | + should 'add hidden field with target_id' do | ||
| 47 | + get :new, :profile => enterprise.identifier | ||
| 48 | + assert_tag :tag => 'input', :attributes => { :name => 'contact[target_id]', :value => enterprise.id, :type => 'hidden' } | ||
| 49 | + end | ||
| 50 | + | ||
| 51 | + should 'add requestor id if logged in' do | ||
| 52 | + login_as(profile.identifier) | ||
| 53 | + @controller.stubs(:current_user).returns(profile.user) | ||
| 54 | + get :new, :profile => enterprise.identifier | ||
| 55 | + assert_tag :tag => 'input', :attributes => { :name => 'contact[requestor_id]', :value => profile.id } | ||
| 56 | + end | ||
| 57 | + | ||
| 58 | + should 'nil requestor id if not logged in' do | ||
| 59 | + get :new, :profile => enterprise.identifier | ||
| 60 | + assert_tag :tag => 'input', :attributes => { :name => 'contact[requestor_id]', :value => nil } | ||
| 61 | + end | ||
| 62 | + | ||
| 63 | + should 'redirect to profile page after contact' do | ||
| 64 | + post :new, :profile => enterprise.identifier, :contact => {:subject => 'Hi', :email => 'visitor@mail.invalid', :message => 'Hi, all', :target_id => enterprise.id} | ||
| 65 | + assert_response :redirect | ||
| 66 | + assert_redirected_to :controller => 'profile', :profile => enterprise.identifier | ||
| 67 | + end | ||
| 68 | + | ||
| 69 | + should 'be able to send contact' do | ||
| 70 | + assert_difference Contact, :count do | ||
| 71 | + post :new, :profile => enterprise.identifier, :contact => {:subject => 'Hi', :email => 'visitor@mail.invalid', :message => 'Hi, all', :target_id => enterprise.id} | ||
| 72 | + end | ||
| 73 | + end | ||
| 74 | + | ||
| 75 | +end |
test/functional/profile_controller_test.rb
| @@ -249,7 +249,7 @@ class ProfileControllerTest < Test::Unit::TestCase | @@ -249,7 +249,7 @@ class ProfileControllerTest < Test::Unit::TestCase | ||
| 249 | get :index, :profile => 'my-test-enterprise' | 249 | get :index, :profile => 'my-test-enterprise' |
| 250 | assert_tag :tag => 'a', :attributes => { :href => '/catalog/my-test-enterprise'}, :content => /Products\/Services/ | 250 | assert_tag :tag => 'a', :attributes => { :href => '/catalog/my-test-enterprise'}, :content => /Products\/Services/ |
| 251 | end | 251 | end |
| 252 | - | 252 | + |
| 253 | should 'not display "Products" link for enterprise if environment do not let' do | 253 | should 'not display "Products" link for enterprise if environment do not let' do |
| 254 | env = Environment.default | 254 | env = Environment.default |
| 255 | env.enable('disable_products_for_enterprises') | 255 | env.enable('disable_products_for_enterprises') |
| @@ -304,4 +304,21 @@ class ProfileControllerTest < Test::Unit::TestCase | @@ -304,4 +304,21 @@ class ProfileControllerTest < Test::Unit::TestCase | ||
| 304 | assert_no_tag :content => /t2@t2.com/ | 304 | assert_no_tag :content => /t2@t2.com/ |
| 305 | end | 305 | end |
| 306 | 306 | ||
| 307 | + should 'display contact us for enterprises' do | ||
| 308 | + ent = Enterprise.create!(:name => 'my test enterprise', :identifier => 'my-test-enterprise') | ||
| 309 | + get :index, :profile => 'my-test-enterprise' | ||
| 310 | + assert_tag :tag => 'a', :attributes => { :href => "/contact/my-test-enterprise/new" }, :content => 'Contact us' | ||
| 311 | + end | ||
| 312 | + | ||
| 313 | + should 'not display contact us for non-enterprises' do | ||
| 314 | + get :index, :profile => @profile.identifier | ||
| 315 | + assert_no_tag :tag => 'a', :attributes => { :href => "/contact/#{@profile.identifier}/new" }, :content => 'Contact us' | ||
| 316 | + end | ||
| 317 | + | ||
| 318 | + should 'display contact us only if enabled' do | ||
| 319 | + ent = Enterprise.create!(:name => 'my test enterprise', :identifier => 'my-test-enterprise', :enable_contact_us => false) | ||
| 320 | + get :index, :profile => 'my-test-enterprise' | ||
| 321 | + assert_no_tag :tag => 'a', :attributes => { :href => "/contact/my-test-enterprise/new" }, :content => 'Contact us' | ||
| 322 | + end | ||
| 323 | + | ||
| 307 | end | 324 | end |
test/functional/profile_editor_controller_test.rb
| @@ -517,4 +517,10 @@ class ProfileEditorControllerTest < Test::Unit::TestCase | @@ -517,4 +517,10 @@ class ProfileEditorControllerTest < Test::Unit::TestCase | ||
| 517 | :attributes => { :name=>'profile_data[email]', :value=>'teste_user@teste.com' } | 517 | :attributes => { :name=>'profile_data[email]', :value=>'teste_user@teste.com' } |
| 518 | end | 518 | end |
| 519 | 519 | ||
| 520 | + should 'display enable contact us for enterprise' do | ||
| 521 | + org = Enterprise.create!(:name => 'test org', :identifier => 'testorg') | ||
| 522 | + get :edit, :profile => 'testorg' | ||
| 523 | + assert_tag :tag => 'input', :attributes => {:name => 'profile_data[enable_contact_us]', :type => 'checkbox'} | ||
| 524 | + end | ||
| 525 | + | ||
| 520 | end | 526 | end |
test/functional/tasks_controller_test.rb
| @@ -151,4 +151,16 @@ class TasksControllerTest < Test::Unit::TestCase | @@ -151,4 +151,16 @@ class TasksControllerTest < Test::Unit::TestCase | ||
| 151 | 151 | ||
| 152 | assert_equal f, assigns(:ticket).target | 152 | assert_equal f, assigns(:ticket).target |
| 153 | end | 153 | end |
| 154 | + | ||
| 155 | + should 'list enterprise contacts' do | ||
| 156 | + ent = Enterprise.create!(:identifier => 'contact_test_enterprise', :name => 'Test contact enteprise') | ||
| 157 | + task = Contact.create!(:subject => 'test', :target_id => profile.id, :email => 'visitor@invalid.com', :message => 'Hi, all') | ||
| 158 | + | ||
| 159 | + login_as(profile.identifier) | ||
| 160 | + get :index, :profile => ent.identifier | ||
| 161 | + | ||
| 162 | + assert_includes assigns(:tasks), task | ||
| 163 | + assert_tag :tag => 'li', :attributes => { :class => 'task-Contact' }, :content => 'Someone sent a new message' | ||
| 164 | + end | ||
| 165 | + | ||
| 154 | end | 166 | end |
test/integration/routing_test.rb
| @@ -186,4 +186,8 @@ class RoutingTest < ActionController::IntegrationTest | @@ -186,4 +186,8 @@ class RoutingTest < ActionController::IntegrationTest | ||
| 186 | assert_routing('/myprofile/profile.withdot', :controller => 'profile_editor', :action => 'index', :profile => 'profile.withdot') | 186 | assert_routing('/myprofile/profile.withdot', :controller => 'profile_editor', :action => 'index', :profile => 'profile.withdot') |
| 187 | end | 187 | end |
| 188 | 188 | ||
| 189 | + def test_contact_routing | ||
| 190 | + assert_routing('/contact/wintermute/new', :controller => 'contact', :action => 'new', :profile => 'wintermute') | ||
| 191 | + end | ||
| 192 | + | ||
| 189 | end | 193 | end |
| @@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
| 1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
| 2 | + | ||
| 3 | +class ContactTest < ActiveSupport::TestCase | ||
| 4 | + | ||
| 5 | + should 'have serialized data' do | ||
| 6 | + t = Contact.new | ||
| 7 | + t.data[:test] = 'test' | ||
| 8 | + | ||
| 9 | + assert_equal({:test => 'test'}, t.data) | ||
| 10 | + end | ||
| 11 | + | ||
| 12 | + should 'validates required fields' do | ||
| 13 | + contact = Contact.new | ||
| 14 | + assert !contact.valid? | ||
| 15 | + contact.subject = 'Hi' | ||
| 16 | + assert !contact.valid? | ||
| 17 | + contact.email = 'visitor@invalid.com' | ||
| 18 | + assert !contact.valid? | ||
| 19 | + contact.message = 'Hi, all' | ||
| 20 | + assert !contact.valid? | ||
| 21 | + contact.target = create_user('contact_user_test').person | ||
| 22 | + assert contact.save! | ||
| 23 | + end | ||
| 24 | + | ||
| 25 | +end |
test/unit/enterprise_test.rb
| @@ -211,5 +211,9 @@ class EnterpriseTest < Test::Unit::TestCase | @@ -211,5 +211,9 @@ class EnterpriseTest < Test::Unit::TestCase | ||
| 211 | assert_kind_of Enterprise, p.template | 211 | assert_kind_of Enterprise, p.template |
| 212 | end | 212 | end |
| 213 | 213 | ||
| 214 | + should 'contact us enabled by default' do | ||
| 215 | + e = Enterprise.create!(:name => 'test_com', :identifier => 'test_com', :environment => Environment.default) | ||
| 216 | + assert e.enable_contact_us | ||
| 217 | + end | ||
| 214 | 218 | ||
| 215 | end | 219 | end |