From 5fd8b6165732618de7d8ef987d170809eacfb59a Mon Sep 17 00:00:00 2001 From: nertc Date: Mon, 25 Nov 2024 13:57:29 +0400 Subject: [PATCH] Add profile location --- app/assets/javascripts/user.js | 102 ++++++++++++++++-- app/controllers/geocoder_controller.rb | 6 +- app/controllers/profiles_controller.rb | 1 + app/models/user.rb | 1 + app/views/profiles/edit.html.erb | 6 ++ app/views/users/show.html.erb | 8 ++ config/locales/en.yml | 3 + .../20241030090336_add_user_location_name.rb | 5 + db/structure.sql | 4 +- test/controllers/geocoder_controller_test.rb | 18 ++++ test/system/user_location_change_test.rb | 22 ++++ 11 files changed, 165 insertions(+), 11 deletions(-) create mode 100644 db/migrate/20241030090336_add_user_location_name.rb create mode 100644 test/system/user_location_change_test.rb diff --git a/app/assets/javascripts/user.js b/app/assets/javascripts/user.js index b94db8b557..71346e2125 100644 --- a/app/assets/javascripts/user.js +++ b/app/assets/javascripts/user.js @@ -10,6 +10,13 @@ $(document).ready(function () { var defaultHomeZoom = 12; var map, marker, deleted_lat, deleted_lon; + const locationInput = { + dirty: true, + request: null, + countryName: "", + deletedText: null + }; + if ($("#map").length) { map = L.map("map", { attributionControl: false, @@ -73,6 +80,7 @@ $(document).ready(function () { deleted_lat = null; deleted_lon = null; + locationInput.deletedText = null; respondToHomeUpdate(); }).on("moveend", function () { var lat = $("#home_lat").val().trim(), @@ -93,9 +101,26 @@ $(document).ready(function () { $("#home_lat, #home_lon").on("input", function () { deleted_lat = null; deleted_lon = null; + locationInput.deletedText = null; respondToHomeUpdate(); }); + $("#location_name").on("input", function () { + locationInput.dirty = true; + deleted_lat = null; + deleted_lon = null; + locationInput.deletedText = null; + + updateLocationWarning(); + respondToHomeUpdate(false); + }); + + $("#location_default_name").on("click", function () { + $("#location_name").val(locationInput.countryName); + $("#location_name_warning").addClass("d-none"); + locationInput.dirty = false; + }); + $("#home_show").click(function () { var lat = $("#home_lat").val(), lon = $("#home_lon").val(); @@ -104,24 +129,34 @@ $(document).ready(function () { }); $("#home_delete").click(function () { - var lat = $("#home_lat").val(), - lon = $("#home_lon").val(); + let lat = $("#home_lat").val(), + lon = $("#home_lon").val(), + locationName = $("#location_name").val(); - $("#home_lat, #home_lon").val(""); + $("#location_name_warning").addClass("d-none"); + $("#home_lat, #home_lon, #location_name").val(""); deleted_lat = lat; deleted_lon = lon; - respondToHomeUpdate(); + locationInput.deletedText = locationName; + + respondToHomeUpdate(false); $("#home_undelete").trigger("focus"); }); $("#home_undelete").click(function () { $("#home_lat").val(deleted_lat); $("#home_lon").val(deleted_lon); + $("#location_name").val(locationInput.deletedText); deleted_lat = null; deleted_lon = null; - respondToHomeUpdate(); + locationInput.deletedText = null; + + updateLocationWarning(); + respondToHomeUpdate(false); $("#home_delete").trigger("focus"); }); + + updateHomeLocation(); } else { $("[data-user]").each(function () { var user = $(this).data("user"); @@ -133,14 +168,18 @@ $(document).ready(function () { } } - function respondToHomeUpdate() { - var lat = $("#home_lat").val().trim(), + function respondToHomeUpdate(updateLocationName = true) { + let lat = $("#home_lat").val().trim(), lon = $("#home_lon").val().trim(), + locationName = $("#location_name").val().trim(), location; try { if (lat && lon) { location = L.latLng(lat, lon); + if (updateLocationName) { + updateHomeLocation(); + } } $("#home_lat, #home_lon").removeClass("is-invalid"); } catch (error) { @@ -150,8 +189,11 @@ $(document).ready(function () { $("#home_message").toggleClass("invisible", Boolean(location)); $("#home_show").prop("hidden", !location); - $("#home_delete").prop("hidden", !location); - $("#home_undelete").prop("hidden", !(!location && deleted_lat && deleted_lon)); + $("#home_delete").prop("hidden", !location && !locationName); + $("#home_undelete").prop("hidden", !( + (!location || !locationName) && + ((deleted_lat && deleted_lon) || locationInput.deletedText) + )); if (location) { marker.setLatLng([lat, lon]); marker.addTo(map); @@ -178,6 +220,48 @@ $(document).ready(function () { } } + function updateHomeLocation() { + const lat = $("#home_lat").val().trim(); + const lon = $("#home_lon").val().trim(); + if (!lat || !lon) { + return; + } + + const geocodeUrl = "/geocoder/search_osm_nominatim_reverse"; + const params = { + format: "json", + lat, + lon, + zoom: 3 + }; + + if (locationInput.request) locationInput.request.abort(); + locationInput.request = $.ajax({ + url: geocodeUrl, + method: "POST", + data: params, + success: function (country) { + locationInput.request = null; + locationInput.countryName = country; + $("#location_default_name").text(I18n.t("javascripts.profiles.edit.location_autofill", { country })); + if (locationInput.dirty) { + updateLocationWarning(); + } else { + $("#location_name").val(locationInput.countryName); + } + } + }); + } + + function updateLocationWarning() { + const locationName = $("#location_name").val(); + if (!locationInput.dirty || locationName.includes(locationInput.countryName)) { + $("#location_name_warning").addClass("d-none"); + } else { + $("#location_name_warning").removeClass("d-none"); + } + } + updateAuthUID(); $("select#user_auth_provider").on("change", updateAuthUID); diff --git a/app/controllers/geocoder_controller.rb b/app/controllers/geocoder_controller.rb index 43f276efa0..c2a7286719 100644 --- a/app/controllers/geocoder_controller.rb +++ b/app/controllers/geocoder_controller.rb @@ -147,7 +147,11 @@ def search_osm_nominatim_reverse :type => object_type, :id => object_id) end - render :action => "results" + if params[:format] == "json" + render :html => @results.pluck(:name).join(", ") + else + render :action => "results" + end rescue StandardError => e host = URI(Settings.nominatim_url).host @error = "Error contacting #{host}: #{e}" diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 4005176ce1..99d9d0e135 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -31,6 +31,7 @@ def update current_user.home_lat = params[:user][:home_lat] current_user.home_lon = params[:user][:home_lon] + current_user.location_name = params[:user][:location_name] if current_user.save flash[:notice] = t ".success" diff --git a/app/models/user.rb b/app/models/user.rb index 917faca218..47416ef2de 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -12,6 +12,7 @@ # home_lat :float # home_lon :float # home_zoom :integer default(3) +# location_name :string # pass_salt :string # email_valid :boolean default(FALSE), not null # new_email :string diff --git a/app/views/profiles/edit.html.erb b/app/views/profiles/edit.html.erb index ac76b4d2d5..fabbdc776a 100644 --- a/app/views/profiles/edit.html.erb +++ b/app/views/profiles/edit.html.erb @@ -52,6 +52,12 @@ +
+ <%= f.text_field :location_name, :wrapper_class => "col-sm-4 d-flex flex-column pe-3", :class => "mt-auto", :id => "location_name" %> +
+ +
+
checked <% end %> id="updatehome" /> diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index d479b1d56d..4cd100fb0a 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -139,6 +139,14 @@
+ <% if @user.location_name && @user.location_name.strip.present? %> +
+ + + +
+
<%= @user.location_name %>
+ <% end %>
<%= t ".mapper since" %>
<%= l @user.created_at.to_date, :format => :long %>
<%= t ".last map edit" %>
diff --git a/config/locales/en.yml b/config/locales/en.yml index 3f2a4cb140..e6e38ff802 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3176,6 +3176,9 @@ en: ninth: "9th" tenth: "10th" time: "Time" + profiles: + edit: + location_autofill: "Autofill %{country}" query: node: Node way: Way diff --git a/db/migrate/20241030090336_add_user_location_name.rb b/db/migrate/20241030090336_add_user_location_name.rb new file mode 100644 index 0000000000..3cace38c8f --- /dev/null +++ b/db/migrate/20241030090336_add_user_location_name.rb @@ -0,0 +1,5 @@ +class AddUserLocationName < ActiveRecord::Migration[7.2] + def change + add_column :users, :location_name, :string + end +end diff --git a/db/structure.sql b/db/structure.sql index 9679e0b925..7c924e0c1a 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1509,7 +1509,8 @@ CREATE TABLE public.users ( tou_agreed timestamp without time zone, diary_comments_count integer DEFAULT 0, note_comments_count integer DEFAULT 0, - creation_address inet + creation_address inet, + location_name character varying ); @@ -3397,6 +3398,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('23'), ('22'), ('21'), +('20241030090336'), ('20241023004427'), ('20241022141247'), ('20240913171951'), diff --git a/test/controllers/geocoder_controller_test.rb b/test/controllers/geocoder_controller_test.rb index ac9905589b..ca64c7952e 100644 --- a/test/controllers/geocoder_controller_test.rb +++ b/test/controllers/geocoder_controller_test.rb @@ -420,6 +420,24 @@ def test_search_osm_nominatim_reverse end end + ## + # Test the nominatim reverse JSON search + def test_search_osm_nominatim_reverse_json + with_http_stubs "nominatim" do + post geocoder_search_osm_nominatim_reverse_path(:lat => 51.7632, :lon => -0.0076, :zoom => 15, :format => "json"), :xhr => true + assert_response :success + assert_select "body", :text => "Broxbourne, Hertfordshire, East of England, England, United Kingdom" + + post geocoder_search_osm_nominatim_reverse_path(:lat => 51.7632, :lon => -0.0076, :zoom => 17, :format => "json"), :xhr => true + assert_response :success + assert_select "body", :text => "Dinant Link Road, Broxbourne, Hertfordshire, East of England, England, EN11 8HX, United Kingdom" + + post geocoder_search_osm_nominatim_reverse_path(:lat => 13.7709, :lon => 100.50507, :zoom => 19, :format => "json"), :xhr => true + assert_response :success + assert_select "body", :text => "MM Steak&Grill, ถนนศรีอยุธยา, บางขุนพรหม, กรุงเทพมหานคร, เขตดุสิต, กรุงเทพมหานคร, 10300, ประเทศไทย" + end + end + private def latlon_check(query, lat, lon) diff --git a/test/system/user_location_change_test.rb b/test/system/user_location_change_test.rb new file mode 100644 index 0000000000..9cf5f879e5 --- /dev/null +++ b/test/system/user_location_change_test.rb @@ -0,0 +1,22 @@ +require "application_system_test_case" + +class UserLocationChangeTest < ApplicationSystemTestCase + def setup + stub_request(:get, /.*gravatar.com.*d=404/).to_return(:status => 404) + end + + test "User can change their location" do + user = create(:user) + sign_in_as(user) + + visit user_path(user) + assert_no_selector ".bi.bi-geo-alt-fill" + + visit edit_profile_path + fill_in "Location name", :with => "Test Location" + click_on "Update Profile" + + visit user_path(user) + assert_text "Test Location" + end +end