diff --git a/app/controllers/my_profile/maps_controller.rb b/app/controllers/my_profile/maps_controller.rb new file mode 100644 index 0000000..dec4ec3 --- /dev/null +++ b/app/controllers/my_profile/maps_controller.rb @@ -0,0 +1,21 @@ +class MapsController < MyProfileController + + protect 'edit_profile', :profile + + def edit_location + @profile_data = profile + if request.post? + begin + Profile.transaction do + if profile.update_attributes!(params[:profile_data]) + flash[:notice] = _('Address was updated successfully!') + redirect_to :action => 'edit_location' + end + end + rescue + flash[:error] = _('Address could not be saved.') + end + end + end + +end diff --git a/app/controllers/my_profile/profile_design_controller.rb b/app/controllers/my_profile/profile_design_controller.rb index 46c24fa..7e0c348 100644 --- a/app/controllers/my_profile/profile_design_controller.rb +++ b/app/controllers/my_profile/profile_design_controller.rb @@ -5,7 +5,7 @@ class ProfileDesignController < BoxOrganizerController protect 'edit_profile_design', :profile def available_blocks - blocks = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock ] + blocks = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock, LocationBlock ] # blocks exclusive for organizations if profile.has_members? @@ -22,7 +22,6 @@ class ProfileDesignController < BoxOrganizerController # blocks exclusive for enterprises if profile.enterprise? - blocks << LocalizationBlock blocks << DisabledEnterpriseMessageBlock end diff --git a/app/models/community.rb b/app/models/community.rb index cf46a00..d56ffad 100644 --- a/app/models/community.rb +++ b/app/models/community.rb @@ -4,6 +4,7 @@ class Community < Organization settings_items :description settings_items :language + settings_items :zip_code, :city, :state, :country xss_terminate :only => [ :name, :address, :contact_phone, :description ] @@ -23,6 +24,10 @@ class Community < Organization end FIELDS = %w[ + city + state + country + zip_code description language ] diff --git a/app/models/environment.rb b/app/models/environment.rb index d109ef9..aa63db0 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -275,6 +275,16 @@ class Environment < ActiveRecord::Base self.settings['message_for_disabled_enterprise'] = value end + # the environment's default location + def location + self.settings['location'] + end + + # sets the environment's location. + def location=(value) + self.settings['location'] = value + end + # returns the approval method used for this environment. Possible values are: # # Defaults to :admim. diff --git a/app/models/localization_block.rb b/app/models/localization_block.rb deleted file mode 100644 index 588686e..0000000 --- a/app/models/localization_block.rb +++ /dev/null @@ -1,24 +0,0 @@ -class LocalizationBlock < Block - - def self.description - _('Localization map block') - end - - def help - _('Shows where the profile is on the material world.') - end - - def content - profile = self.owner - title = self.title - lambda do - profile.lat ? - block_title(title) + - content_tag('div', - '', - :class => 'the-localization-map' ) : - content_tag('i', _('This profile has no geographical position registered.')) - end - end - -end diff --git a/app/models/location_block.rb b/app/models/location_block.rb new file mode 100644 index 0000000..7d38c93 --- /dev/null +++ b/app/models/location_block.rb @@ -0,0 +1,30 @@ +class LocationBlock < Block + + settings_items :zoom, :type => :integer , :default => 4 + settings_items :map_type, :type => :string , :default => 'roadmap' + + def self.description + _('Location map block') + end + + def help + _('Shows where the profile is on the material world.') + end + + def content + profile = self.owner + title = self.title + if profile.lat + block_title(title) + + content_tag('div', + '', + :class => 'the-localization-map' ) + else + content_tag('i', _('This profile has no geographical position registered.')) + end + end + +end diff --git a/app/models/profile.rb b/app/models/profile.rb index b8dcdb1..e9498d2 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -151,12 +151,23 @@ class Profile < ActiveRecord::Base belongs_to :region - def location + def location(separator = ' - ') myregion = self.region if myregion - myregion.hierarchy.reverse.first(2).map(&:name).join(' - ') + myregion.hierarchy.reverse.first(2).map(&:name).join(separator) else - [ :city, :state, :country_name ].map {|item| self.respond_to?(item) ? self.send(item) : nil }.compact.join(' - ') + %w[address city state country_name zip_code ].map {|item| (self.respond_to?(item) && !self.send(item).blank?) ? self.send(item) : nil }.compact.join(separator) + end + end + + def geolocation + unless location.blank? + location + else + if environment.location.blank? + environment.location = "BRA" + end + environment.location end end diff --git a/app/views/box_organizer/_location_block.rhtml b/app/views/box_organizer/_location_block.rhtml new file mode 100644 index 0000000..6f6e405 --- /dev/null +++ b/app/views/box_organizer/_location_block.rhtml @@ -0,0 +1,10 @@ +
+ <%= labelled_form_field _('Zoom Level:'), select(:block, :zoom, [[_('World'), 0], + 1,2,3,4,5,6,7,8,10,11,12,13,14,15,16,17,18, + [_('Street'), 19]]) %> + <%= labelled_form_field _('Map Type:'), select(:block, :map_type, [[_('Road Map') , 'roadmap' ], + [_('Mobile') , 'mobile' ], + [_('Satellite'), 'satellite'], + [_('Terrain') , 'terrain' ], + [_('Hybrid') , 'hybrid' ]]) %> +
diff --git a/app/views/maps/_google_map.rhtml b/app/views/maps/_google_map.rhtml new file mode 100644 index 0000000..4cba405 --- /dev/null +++ b/app/views/maps/_google_map.rhtml @@ -0,0 +1,136 @@ +<%= content_tag('script', '', :src => GoogleMaps.api_url, :type => 'text/javascript') %> + + diff --git a/app/views/maps/edit_location.rhtml b/app/views/maps/edit_location.rhtml new file mode 100644 index 0000000..13ca1a9 --- /dev/null +++ b/app/views/maps/edit_location.rhtml @@ -0,0 +1,35 @@ +

<%= _('Location') %>

+ +<% form_for :profile_data, :url => {:action => 'edit_location'} do |f| %> + +
+ <%= optional_field(profile, 'country', select_country(_('Country'), 'profile_data', 'country', {:class => 'type-select'})) %> + <%= optional_field(profile, 'state', labelled_form_field(_('State'), f.text_field(:state))) %> + <%= optional_field(profile, 'city', labelled_form_field(_('City'), f.text_field(:city))) %> + <%= optional_field(profile, 'zip_code', labelled_form_field(_('ZIP code'), text_field(:profile_data, :zip_code))) %> + <%= optional_field(profile, 'address', labelled_form_field(_('Address (street and number)'), text_field(:profile_data, :address))) %> + <% button_bar do %> + <%= button_to_function :search, _('Locate in the map'), "getAddress(null, getAddressData())", :title => _("Locate the address informed above in the map below (note that you'll probably need to adjust the marker to get a precise position)") %> + <%= submit_button 'save', _('Save') %> + <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> + <% end %> +
+ + +
+

+
+ + <%= f.hidden_field(:lat) %> + <%= f.hidden_field(:lng) %> + + + + <% button_bar do %> + <%= submit_button 'save', _('Save') %> + <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> + <% end %> + +<% end %> + +<%= render :partial => 'google_map'%> diff --git a/app/views/profile_editor/index.rhtml b/app/views/profile_editor/index.rhtml index 25717a8..054ff25 100644 --- a/app/views/profile_editor/index.rhtml +++ b/app/views/profile_editor/index.rhtml @@ -14,6 +14,8 @@ <%= control_panel_button(__('Community Info and settings'), 'edit-profile-group', :controller => 'profile_editor', :action => 'edit') if profile.community? %> <%= control_panel_button(__('Enterprise Info and settings'), 'edit-profile-enterprise', :controller => 'profile_editor', :action => 'edit') if profile.enterprise? %> + <%= control_panel_button(_('Location'), 'edit-location', :controller => 'maps', :action => 'edit_location') %> + <%= control_panel_button(_('Mail settings'), 'mail', :controller => 'mailconf') if profile.person? && MailConf.enabled? %> <%= control_panel_button(_('Tasks'), 'todo', :controller => 'tasks', :action => 'index') %> diff --git a/db/migrate/077_rename_location_block.rb b/db/migrate/077_rename_location_block.rb new file mode 100644 index 0000000..4b7e948 --- /dev/null +++ b/db/migrate/077_rename_location_block.rb @@ -0,0 +1,9 @@ +class RenameLocationBlock < ActiveRecord::Migration + def self.up + execute "update blocks set type='LocationBlock' where type='LocalizationBlock'" + end + + def self.down + execute "update blocks set type='LocalizationBlock' where type='LocationBlock'" + end +end diff --git a/db/schema.rb b/db/schema.rb index cf1f56c..2f6a5d6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -9,7 +9,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 76) do +ActiveRecord::Schema.define(:version => 77) do create_table "article_versions", :force => true do |t| t.integer "article_id" @@ -88,8 +88,8 @@ ActiveRecord::Schema.define(:version => 76) do t.boolean "virtual", :default => false end - add_index "articles_categories", ["article_id"], :name => "index_articles_categories_on_article_id" add_index "articles_categories", ["category_id"], :name => "index_articles_categories_on_category_id" + add_index "articles_categories", ["article_id"], :name => "index_articles_categories_on_article_id" create_table "blocks", :force => true do |t| t.string "title" @@ -103,10 +103,10 @@ ActiveRecord::Schema.define(:version => 76) do t.datetime "fetched_at" end - add_index "blocks", ["box_id"], :name => "index_blocks_on_box_id" - add_index "blocks", ["enabled"], :name => "index_blocks_on_enabled" - add_index "blocks", ["fetched_at"], :name => "index_blocks_on_fetched_at" add_index "blocks", ["type"], :name => "index_blocks_on_type" + add_index "blocks", ["fetched_at"], :name => "index_blocks_on_fetched_at" + add_index "blocks", ["enabled"], :name => "index_blocks_on_enabled" + add_index "blocks", ["box_id"], :name => "index_blocks_on_box_id" create_table "boxes", :force => true do |t| t.string "owner_type" @@ -136,8 +136,8 @@ ActiveRecord::Schema.define(:version => 76) do t.boolean "virtual", :default => false end - add_index "categories_profiles", ["category_id"], :name => "index_categories_profiles_on_category_id" add_index "categories_profiles", ["profile_id"], :name => "index_categories_profiles_on_profile_id" + add_index "categories_profiles", ["category_id"], :name => "index_categories_profiles_on_category_id" create_table "comments", :force => true do |t| t.string "title" @@ -189,8 +189,8 @@ ActiveRecord::Schema.define(:version => 76) do t.integer "update_errors", :default => 0 end - add_index "external_feeds", ["enabled"], :name => "index_external_feeds_on_enabled" add_index "external_feeds", ["fetched_at"], :name => "index_external_feeds_on_fetched_at" + add_index "external_feeds", ["enabled"], :name => "index_external_feeds_on_enabled" create_table "favorite_enteprises_people", :id => false, :force => true do |t| t.integer "person_id" @@ -224,8 +224,8 @@ ActiveRecord::Schema.define(:version => 76) do t.datetime "updated_at" end - add_index "product_categorizations", ["category_id"], :name => "index_product_categorizations_on_category_id" add_index "product_categorizations", ["product_id"], :name => "index_product_categorizations_on_product_id" + add_index "product_categorizations", ["category_id"], :name => "index_product_categorizations_on_category_id" create_table "products", :force => true do |t| t.integer "enterprise_id" @@ -305,8 +305,8 @@ ActiveRecord::Schema.define(:version => 76) do t.datetime "created_at" end - add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id" add_index "taggings", ["taggable_id", "taggable_type"], :name => "index_taggings_on_taggable_id_and_taggable_type" + add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id" create_table "tags", :force => true do |t| t.string "name" diff --git a/features/location.feature b/features/location.feature new file mode 100644 index 0000000..d69c113 --- /dev/null +++ b/features/location.feature @@ -0,0 +1,57 @@ +Feature: Location + As a user + I want to edit my address and location + So that others can find me in the map + + Background: + And the following users + | login | + | zezinho | + And I am logged in as "zezinho" + + Scenario: editing my address + Given the following Person fields are enabled + | address | + | country | + | state | + | city | + | zip_code | + And I follow "Control panel" + And I follow "Location" + When I fill in "Address" with "Rua Marechal Floriano, 28" + And I select "Brazil" from "Country" + And I fill in "State" with "Bahia" + And I fill in "City" with "Salvador" + And I fill in "ZIP Code" with "40110010" + And I press "Save" + Then "zezinho" should have the following data + | address | country | state | city | zip_code | + | Rua Marechal Floriano, 28 | BR | Bahia | Salvador | 40110010 | + + Scenario Outline: editing address of collectives + Given the following fields are enabled + | address | + | country | + | state | + | city | + | zip_code | + Given the following + | identifier | name | owner | + | colivre | Colivre | zezinho | + And I am on Colivre's control panel + And I follow "Location" + And I select "Brazil" from "Country" + And I fill in the following: + | Address | Rua Marechal Floriano, 28 | + | State | Bahia | + | City | Salvador | + | ZIP Code | 40110010 | + When I press "Save" + Then "colivre" should have the following data + | address | country | state | city | zip_code | + | Rua Marechal Floriano, 28 | BR | Bahia | Salvador | 40110010 | + Examples: + | class | plural | + | Community | communities | + | Enterprise | enterprises | + diff --git a/features/step_definitions/custom_webrat_steps.rb b/features/step_definitions/custom_webrat_steps.rb index f88f67a..97ed810 100644 --- a/features/step_definitions/custom_webrat_steps.rb +++ b/features/step_definitions/custom_webrat_steps.rb @@ -6,3 +6,7 @@ When /^I should not see "([^\"]+)" link$/ do |link| response.should_not have_selector("a", :content => link) end +When /^I wait (\d+) seconds$/ do |seconds| + sleep seconds.to_i +end + diff --git a/features/step_definitions/noosfero_steps.rb b/features/step_definitions/noosfero_steps.rb index d4e3a27..f7d4f3b 100644 --- a/features/step_definitions/noosfero_steps.rb +++ b/features/step_definitions/noosfero_steps.rb @@ -7,15 +7,14 @@ Given /^the following users$/ do |table| end end -Given /^the following communities$/ do |table| - table.hashes.each do |item| - Community.create!(item) - end -end - -Given /^the following enterprises$/ do |table| - table.hashes.each do |item| - Enterprise.create!(item) +Given /^the following (communities|enterprises)$/ do |kind,table| + klass = kind.singularize.camelize.constantize + table.hashes.each do |row| + owner = row.delete("owner") + community = klass.create!(row) + if owner + community.add_admin(Profile[owner]) + end end end @@ -111,3 +110,24 @@ end Given /^"([^\"]*)" has no articles$/ do |profile| (Profile[profile] || Profile.find_by_name(profile)).articles.delete_all end + +Given /^the following (\w+) fields are enabled$/ do |klass, table| + env = Environment.default + fields = table.raw.inject({}) do |hash, line| + hash[line.first] = { "active" => 'true' } + hash + end + + env.send("custom_#{klass.downcase}_fields=", fields) + env.save! + if fields.keys != env.send("active_#{klass.downcase}_fields") + raise "Not all fields enabled! Requested: %s; Enabled: %s" % [fields.keys.inspect, env.send("active_#{klass.downcase}_fields").inspect] + end +end + +Then /^"([^\"]*)" should have the following data$/ do |id, table| + profile = Profile.find_by_identifier(id) + expected = table.hashes.first + data = expected.keys.inject({}) { |hash, key| hash[key] = profile.send(key).to_s; hash } + data.should == expected +end diff --git a/public/stylesheets/blocks/localization-block.css b/public/stylesheets/blocks/localization-block.css deleted file mode 100644 index dc34ec7..0000000 --- a/public/stylesheets/blocks/localization-block.css +++ /dev/null @@ -1,13 +0,0 @@ -.localization-block { - text-align: center; -} - -.the-localization-map { - margin: auto; - width: 211px; - max-width: 205px; - padding: 3px; - background: #FFF; - border: 1px solid #888; -} - diff --git a/public/stylesheets/blocks/location-block.css b/public/stylesheets/blocks/location-block.css new file mode 100644 index 0000000..129a9b2 --- /dev/null +++ b/public/stylesheets/blocks/location-block.css @@ -0,0 +1,13 @@ +.location-block { + text-align: center; +} + +.the-localization-map { + overflow: hidden; + margin: auto; + max-width: 205px; + padding: 3px; + background: #FFF; + border: 1px solid #888; +} + diff --git a/public/stylesheets/common.css b/public/stylesheets/common.css index ec97a3f..bf3cfdd 100644 --- a/public/stylesheets/common.css +++ b/public/stylesheets/common.css @@ -604,3 +604,10 @@ code input { cursor: progress; background: transparent url(../images/loading.gif) no-repeat scroll center 50px; } + +/**** Location Map ****/ +#location-map { + width: 100%; + height: 320px; +} + diff --git a/public/stylesheets/controller_profile_editor.css b/public/stylesheets/controller_profile_editor.css index 87f95f4..406f808 100644 --- a/public/stylesheets/controller_profile_editor.css +++ b/public/stylesheets/controller_profile_editor.css @@ -88,3 +88,5 @@ a.control-panel-validation {background-image: url(../images/control-panel/applic a.control-panel-mail {background-image: url(../images/control-panel/email.png)} .msie6 a.control-panel-mail {background-image: url(../images/control-panel/email.gif)} +a.control-panel-edit-location {background-image: url(../images/control-panel/set-geolocation.png)} +.msie6 a.control-panel-edit-location {background-image: url(../images/control-panel/set-geolocation.gif)} diff --git a/test/functional/maps_controller_test.rb b/test/functional/maps_controller_test.rb new file mode 100644 index 0000000..f1963a9 --- /dev/null +++ b/test/functional/maps_controller_test.rb @@ -0,0 +1,43 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'maps_controller' + +# Re-raise errors caught by the controller. +class MapsController; def rescue_action(e) raise e end; end + +class MapsControllerTest < Test::Unit::TestCase + + def setup + @controller = MapsController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + + @profile = create_user('test_profile').person + login_as(@profile.identifier) + end + + attr_reader :profile + + should 'save profile address' do + post :edit_location, :profile => profile.identifier, :profile_data => { 'address' => 'new address' } + assert_equal 'new address', Profile['test_profile'].address + end + + should 'back when update address fail' do + Profile.any_instance.stubs(:update_attributes!).returns(false) + post :edit_location, :profile => profile.identifier, :profile_data => { 'address' => 'new address' } + assert_nil profile.address + assert_template 'edit_location' + end + + should 'show page to edit location' do + get :edit_location, :profile => profile.identifier + assert_response :success + assert_template 'edit_location' + end + + should 'dispĺay form for address with profile address' do + get :edit_location, :profile => profile.identifier + assert_tag :tag => 'input', :attributes => { :name => 'location' } + end + +end diff --git a/test/unit/profile_test.rb b/test/unit/profile_test.rb index bf99987..41c0621 100644 --- a/test/unit/profile_test.rb +++ b/test/unit/profile_test.rb @@ -698,15 +698,60 @@ class ProfileTest < Test::Unit::TestCase assert_equal 'Salvador - Bahia', p.location end - should 'use city/state/country fields for location when no region object is set' do + should 'use city/state/country/address/zip_code fields for location when no region object is set' do p = Profile.new p.expects(:region).returns(nil) - p.expects(:city).returns("Salvador") - p.expects(:state).returns("Bahia") - p.expects(:country_name).returns("Brasil") - assert_equal 'Salvador - Bahia - Brasil', p.location + p.expects(:address).returns("Rua A").at_least_once + p.expects(:city).returns("Salvador").at_least_once + p.expects(:state).returns("Bahia").at_least_once + p.expects(:country_name).returns("Brasil").at_least_once + p.expects(:zip_code).returns("40000000").at_least_once + assert_equal 'Rua A - Salvador - Bahia - Brasil - 40000000', p.location end + should 'choose separator for location' do + p = Profile.new + p.expects(:region).returns(nil) + p.expects(:address).returns("Rua A").at_least_once + p.expects(:city).returns("Salvador").at_least_once + p.expects(:state).returns("Bahia").at_least_once + p.expects(:country_name).returns("Brasil").at_least_once + p.expects(:zip_code).returns("40000000").at_least_once + assert_equal 'Rua A, Salvador, Bahia, Brasil, 40000000', p.location(', ') + end + + should 'not display separator on location if city/state/country/address/zip_code is blank' do + p = Profile.new + p.expects(:region).returns(nil) + p.expects(:address).returns("Rua A").at_least_once + p.expects(:city).returns("Salvador").at_least_once + p.expects(:state).returns("").at_least_once + p.expects(:country_name).returns("Brasil").at_least_once + p.expects(:zip_code).returns("40000000").at_least_once + assert_equal 'Rua A - Salvador - Brasil - 40000000', p.location + end + + should 'use location on geolocation if not blank' do + p = Profile.new + p.expects(:region).returns(nil).at_least_once + p.expects(:address).returns("Rua A").at_least_once + p.expects(:city).returns("Salvador").at_least_once + p.expects(:state).returns("").at_least_once + p.expects(:country_name).returns("Brasil").at_least_once + p.expects(:zip_code).returns("40000000").at_least_once + assert_equal 'Rua A - Salvador - Brasil - 40000000', p.geolocation + end + + should 'use default location on geolocation if not blank' do + p = Profile.new + p.expects(:region).returns(nil) + e = Environment.default + p.expects(:environment).returns(e) + e.expects(:location).returns('Brasil') + assert_equal 'Brasil', p.geolocation + end + + should 'lookup country name' do p = Profile.new # two sample countries; trust the rest works -- libgit2 0.21.2