From: nertc Date: Fri, 25 Apr 2025 14:31:39 +0000 (+0400) Subject: Add profile location X-Git-Tag: live~16^2 X-Git-Url: https://git.openstreetmap.org./rails.git/commitdiff_plain/bafaf78c7de4e8a224e1957f5b7c3f054ad05211?ds=inline Add profile location --- diff --git a/app/assets/javascripts/home_location_name-endpoint.js b/app/assets/javascripts/home_location_name-endpoint.js new file mode 100644 index 000000000..f1b5944ee --- /dev/null +++ b/app/assets/javascripts/home_location_name-endpoint.js @@ -0,0 +1,65 @@ +OSM.HomeLocationNameGeocoder = function Endpoint(latInput, lonInput, locationNameInput) { + const endpoint = { + autofill: true, + countryName: locationNameInput.val().trim() + }; + + let requestController = null; + + endpoint.updateHomeLocationName = function ( + updateInput = true, + lat = latInput.val().trim(), + lon = lonInput.val().trim(), + successFn + ) { + if (!lat || !lon || !endpoint.autofill) { + return; + } + + const geocodeUrl = "/search/nominatim_reverse_query", + csrf_param = $("meta[name=csrf-param]").attr("content"), + csrf_token = $("meta[name=csrf-token]").attr("content"), + params = new URLSearchParams({ + lat, + lon, + zoom: 3 + }); + params.set(csrf_param, csrf_token); + + if (requestController) { + requestController.abort(); + } + const currentRequestController = new AbortController(); + requestController = currentRequestController; + + fetch(geocodeUrl, { + method: "POST", + body: params, + signal: requestController.signal, + headers: { accept: "application/json" } + }) + .then((response) => response.json()) + .then((data) => { + const country = data.length ? data[0].name : ""; + + if (updateInput) { + $("#home_location_name").val(country); + } else if (endpoint.countryName !== country) { + endpoint.autofill = false; + } + endpoint.countryName = country; + requestController = null; + + if (successFn) { + successFn(); + } + }) + .catch(() => { + if (currentRequestController === requestController) { + requestController = null; + } + }); + }; + + return endpoint; +}; diff --git a/app/assets/javascripts/user.js b/app/assets/javascripts/user.js index 5f8a931e3..028bf2074 100644 --- a/app/assets/javascripts/user.js +++ b/app/assets/javascripts/user.js @@ -1,4 +1,5 @@ //= require leaflet.locate +//= require ./home_location_name-endpoint (function () { $(document).on("change", "#user_all", function () { @@ -8,7 +9,7 @@ $(function () { const defaultHomeZoom = 12; - let map, marker, deleted_lat, deleted_lon; + let map, marker, deleted_lat, deleted_lon, deleted_home_name, homeLocationNameGeocoder, savedLat, savedLon; if ($("#map").length) { map = L.map("map", { @@ -16,6 +17,10 @@ $(function () { zoomControl: false }).addLayer(new L.OSM.Mapnik()); + savedLat = $("#home_lat").val(); + savedLon = $("#home_lon").val(); + homeLocationNameGeocoder = OSM.HomeLocationNameGeocoder($("#home_lat"), $("#home_lon"), $("#home_location_name")); + const position = $("html").attr("dir") === "rtl" ? "topleft" : "topright"; L.OSM.zoom({ position }).addTo(map); @@ -48,9 +53,8 @@ $(function () { $("#home_lat").val(lat); $("#home_lon").val(lon); - deleted_lat = null; - deleted_lon = null; - respondToHomeUpdate(); + clearDeletedText(); + respondToHomeLatLonUpdate(); }).on("moveend", function () { const lat = $("#home_lat").val().trim(), lon = $("#home_lon").val().trim(); @@ -68,9 +72,15 @@ $(function () { }); $("#home_lat, #home_lon").on("input", function () { - deleted_lat = null; - deleted_lon = null; - respondToHomeUpdate(); + clearDeletedText(); + respondToHomeLatLonUpdate(); + }); + + $("#home_location_name").on("input", function () { + homeLocationNameGeocoder.autofill = false; + clearDeletedText(); + + respondToHomeLatLonUpdate(false); }); $("#home_show").click(function () { @@ -82,21 +92,25 @@ $(function () { $("#home_delete").click(function () { const lat = $("#home_lat").val(), - lon = $("#home_lon").val(); + lon = $("#home_lon").val(), + locationName = $("#home_location_name").val(); - $("#home_lat, #home_lon").val(""); + $("#home_lat, #home_lon, #home_location_name").val(""); deleted_lat = lat; deleted_lon = lon; - respondToHomeUpdate(); + deleted_home_name = locationName; + + respondToHomeLatLonUpdate(false); $("#home_undelete").trigger("focus"); }); $("#home_undelete").click(function () { $("#home_lat").val(deleted_lat); $("#home_lon").val(deleted_lon); - deleted_lat = null; - deleted_lon = null; - respondToHomeUpdate(); + $("#home_location_name").val(deleted_home_name); + clearDeletedText(); + + respondToHomeLatLonUpdate(false); $("#home_delete").trigger("focus"); }); } else { @@ -110,14 +124,26 @@ $(function () { } } - function respondToHomeUpdate() { + function respondToHomeLatLonUpdate(updateLocationName = true) { const lat = $("#home_lat").val().trim(), - lon = $("#home_lon").val().trim(); + lon = $("#home_lon").val().trim(), + locationName = $("#home_location_name").val().trim(); let location; try { if (lat && lon) { location = L.latLng(lat, lon); + if (updateLocationName) { + if (savedLat && savedLon && $("#home_location_name").val().trim()) { + homeLocationNameGeocoder.updateHomeLocationName(false, savedLat, savedLon, () => { + savedLat = savedLon = null; + homeLocationNameGeocoder.updateHomeLocationName(); + }); + } else { + savedLat = savedLon = null; + homeLocationNameGeocoder.updateHomeLocationName(); + } + } } $("#home_lat, #home_lon").removeClass("is-invalid"); } catch (error) { @@ -127,8 +153,11 @@ $(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) || deleted_home_name) + )); if (location) { marker.setLatLng([lat, lon]); marker.addTo(map); @@ -155,6 +184,12 @@ $(function () { } } + function clearDeletedText() { + deleted_lat = null; + deleted_lon = null; + deleted_home_name = null; + } + updateAuthUID(); $("select#user_auth_provider").on("change", updateAuthUID); diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 4005176ce..9d050bd75 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -31,6 +31,7 @@ class ProfilesController < ApplicationController current_user.home_lat = params[:user][:home_lat] current_user.home_lon = params[:user][:home_lon] + current_user.home_location_name = params[:user][:home_location_name] if current_user.save flash[:notice] = t ".success" diff --git a/app/controllers/searches/nominatim_reverse_queries_controller.rb b/app/controllers/searches/nominatim_reverse_queries_controller.rb index c0fe8e6c9..c2eced4e5 100644 --- a/app/controllers/searches/nominatim_reverse_queries_controller.rb +++ b/app/controllers/searches/nominatim_reverse_queries_controller.rb @@ -24,6 +24,11 @@ module Searches :zoom => zoom, :name => description, :type => object_type, :id => object_id) + + respond_to do |format| + format.html + format.json { render :json => @results } + end end rescue StandardError => e host = URI(Settings.nominatim_url).host diff --git a/app/models/user.rb b/app/models/user.rb index 695f29ed8..27e42e665 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) +# home_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 ac76b4d2d..a7dd437e5 100644 --- a/app/views/profiles/edit.html.erb +++ b/app/views/profiles/edit.html.erb @@ -52,6 +52,7 @@ + <%= f.text_field :home_location_name, :wrapper_class => "my-2 col-sm-4 pe-3", :class => "mt-auto", :id => "home_location_name" %>
checked <% end %> id="updatehome" /> diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index da6ddfb9d..ace1d06a4 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -143,6 +143,16 @@
+ <% if @user.home_location_name&.strip.present? %> +
+ + + <%= t ".home location" %> + + +
+
<%= @user.home_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 aa0d99fb7..7774a203a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2891,6 +2891,7 @@ en: follow: Follow mapper since: "Mapper since:" last map edit: "Last map edit:" + home location: "Home location" no activity yet: "No activity yet" uid: "User id:" ct status: "Contributor terms:" 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 000000000..a1874a469 --- /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, :home_location_name, :string + end +end diff --git a/db/structure.sql b/db/structure.sql index 48036fd8e..5e5b92dc5 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1519,7 +1519,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, + home_location_name character varying ); @@ -3457,6 +3458,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20250121191749'), ('20250105154621'), ('20250104140952'), +('20241030090336'), ('20241023004427'), ('20241022141247'), ('20240913171951'), diff --git a/test/controllers/searches_controller_test.rb b/test/controllers/searches_controller_test.rb index bb625c521..d9e4d248c 100644 --- a/test/controllers/searches_controller_test.rb +++ b/test/controllers/searches_controller_test.rb @@ -311,6 +311,21 @@ class SearchesControllerTest < ActionDispatch::IntegrationTest search_check "foo bar baz", %w[nominatim] end + ## + # Test the nominatim reverse JSON search + def test_search_osm_nominatim_reverse_json + with_http_stubs "nominatim" do + post search_nominatim_reverse_query_path(:lat => 51.7632, :lon => -0.0076, :zoom => 15, :format => "json"), :xhr => true + result_name_check_json("Broxbourne, Hertfordshire, East of England, England, United Kingdom") + + post search_nominatim_reverse_query_path(:lat => 51.7632, :lon => -0.0076, :zoom => 17, :format => "json"), :xhr => true + result_name_check_json("Dinant Link Road, Broxbourne, Hertfordshire, East of England, England, EN11 8HX, United Kingdom") + + post search_nominatim_reverse_query_path(:lat => 13.7709, :lon => 100.50507, :zoom => 19, :format => "json"), :xhr => true + result_name_check_json("MM Steak&Grill, ถนนศรีอยุธยา, บางขุนพรหม, กรุงเทพมหานคร, เขตดุสิต, กรุงเทพมหานคร, 10300, ประเทศไทย") + end + end + private def latlon_check(query, lat, lon) @@ -350,4 +365,11 @@ class SearchesControllerTest < ActionDispatch::IntegrationTest assert_template :layout => "xhr" assert_equal sources, assigns(:sources).pluck(:name) end + + def result_name_check_json(name) + assert_response :success + js = ActiveSupport::JSON.decode(@response.body) + assert_not_nil js + assert_equal name, js[0]["name"] + end end diff --git a/test/system/user_location_change_test.rb b/test/system/user_location_change_test.rb new file mode 100644 index 000000000..5524c98f5 --- /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 "Home location name", :with => "Test Location" + click_on "Update Profile" + + visit user_path(user) + assert_text "Test Location" + end +end