Merge f8c5cb4701
into 432fa57e61
This commit is contained in:
commit
8fd788d54e
11 changed files with 174 additions and 17 deletions
|
@ -8,9 +8,19 @@
|
|||
|
||||
$(function () {
|
||||
const defaultHomeZoom = 12;
|
||||
let map, marker, deleted_lat, deleted_lon;
|
||||
let map, marker, deleted_lat, deleted_lon, savedLat, savedLon, locationInput;
|
||||
|
||||
if ($("#map").length) {
|
||||
savedLat = $("#home_lat").val();
|
||||
savedLon = $("#home_lon").val();
|
||||
locationInput = {
|
||||
dirty: false,
|
||||
requestController: null,
|
||||
countryName: $("#location_name").val().trim(),
|
||||
deletedText: null,
|
||||
checkLocation: savedLat && savedLon && $("#location_name").val().trim()
|
||||
};
|
||||
|
||||
map = L.map("map", {
|
||||
attributionControl: false,
|
||||
zoomControl: false
|
||||
|
@ -69,8 +79,7 @@ $(function () {
|
|||
$("#home_lat").val(lat);
|
||||
$("#home_lon").val(lon);
|
||||
|
||||
deleted_lat = null;
|
||||
deleted_lon = null;
|
||||
clearDeletedText();
|
||||
respondToHomeUpdate();
|
||||
}).on("moveend", function () {
|
||||
const lat = $("#home_lat").val().trim(),
|
||||
|
@ -89,11 +98,17 @@ $(function () {
|
|||
});
|
||||
|
||||
$("#home_lat, #home_lon").on("input", function () {
|
||||
deleted_lat = null;
|
||||
deleted_lon = null;
|
||||
clearDeletedText();
|
||||
respondToHomeUpdate();
|
||||
});
|
||||
|
||||
$("#location_name").on("input", function () {
|
||||
locationInput.dirty = true;
|
||||
clearDeletedText();
|
||||
|
||||
respondToHomeUpdate(false);
|
||||
});
|
||||
|
||||
$("#home_show").click(function () {
|
||||
const lat = $("#home_lat").val(),
|
||||
lon = $("#home_lon").val();
|
||||
|
@ -103,21 +118,25 @@ $(function () {
|
|||
|
||||
$("#home_delete").click(function () {
|
||||
const lat = $("#home_lat").val(),
|
||||
lon = $("#home_lon").val();
|
||||
lon = $("#home_lon").val(),
|
||||
locationName = $("#location_name").val();
|
||||
|
||||
$("#home_lat, #home_lon").val("");
|
||||
$("#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);
|
||||
deleted_lat = null;
|
||||
deleted_lon = null;
|
||||
respondToHomeUpdate();
|
||||
$("#location_name").val(locationInput.deletedText);
|
||||
clearDeletedText();
|
||||
|
||||
respondToHomeUpdate(false);
|
||||
$("#home_delete").trigger("focus");
|
||||
});
|
||||
} else {
|
||||
|
@ -131,14 +150,22 @@ $(function () {
|
|||
}
|
||||
}
|
||||
|
||||
function respondToHomeUpdate() {
|
||||
function respondToHomeUpdate(updateLocationName = true) {
|
||||
const lat = $("#home_lat").val().trim(),
|
||||
lon = $("#home_lon").val().trim();
|
||||
lon = $("#home_lon").val().trim(),
|
||||
locationName = $("#location_name").val().trim();
|
||||
let location;
|
||||
|
||||
try {
|
||||
if (lat && lon) {
|
||||
location = L.latLng(lat, lon);
|
||||
if (updateLocationName) {
|
||||
if (locationInput.checkLocation) {
|
||||
updateHomeLocation(false, savedLat, savedLon, updateHomeLocation);
|
||||
} else {
|
||||
updateHomeLocation();
|
||||
}
|
||||
}
|
||||
}
|
||||
$("#home_lat, #home_lon").removeClass("is-invalid");
|
||||
} catch (error) {
|
||||
|
@ -148,8 +175,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) || locationInput.deletedText)
|
||||
));
|
||||
if (location) {
|
||||
marker.setLatLng([lat, lon]);
|
||||
marker.addTo(map);
|
||||
|
@ -176,6 +206,64 @@ $(function () {
|
|||
}
|
||||
}
|
||||
|
||||
function updateHomeLocation(updateInput = true, lat = $("#home_lat").val().trim(), lon = $("#home_lon").val().trim(), successFn) {
|
||||
if (!lat || !lon || locationInput.dirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
const geocodeUrl = "/geocoder/search_osm_nominatim_reverse",
|
||||
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 (locationInput.requestController) {
|
||||
locationInput.requestController.abort();
|
||||
}
|
||||
|
||||
const requestController = new AbortController();
|
||||
locationInput.requestController = requestController;
|
||||
fetch(geocodeUrl, {
|
||||
method: "POST",
|
||||
body: params,
|
||||
signal: locationInput.requestController.signal,
|
||||
headers: { accept: "application/json" }
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then((data) => {
|
||||
const country = data.length ? data[0].name : "";
|
||||
|
||||
if (updateInput) {
|
||||
$("#location_name").val(country);
|
||||
} else {
|
||||
locationInput.checkLocation = false;
|
||||
if (locationInput.countryName !== country) {
|
||||
locationInput.dirty = true;
|
||||
}
|
||||
}
|
||||
locationInput.countryName = country;
|
||||
locationInput.requestController = null;
|
||||
|
||||
if (successFn) {
|
||||
successFn();
|
||||
}
|
||||
}).catch(() => {
|
||||
if (location.requestController === requestController) {
|
||||
locationInput.requestController = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function clearDeletedText() {
|
||||
deleted_lat = null;
|
||||
deleted_lon = null;
|
||||
locationInput.deletedText = null;
|
||||
}
|
||||
|
||||
updateAuthUID();
|
||||
|
||||
$("select#user_auth_provider").on("change", updateAuthUID);
|
||||
|
|
|
@ -152,7 +152,11 @@ class GeocoderController < ApplicationController
|
|||
:type => object_type, :id => object_id)
|
||||
end
|
||||
|
||||
render :action => "results"
|
||||
respond_to do |format|
|
||||
format.html { render :action => "results" }
|
||||
format.json { render :json => @results }
|
||||
format.any { render :action => "results" }
|
||||
end
|
||||
rescue StandardError => e
|
||||
host = URI(Settings.nominatim_url).host
|
||||
@error = "Error contacting #{host}: #{e}"
|
||||
|
|
|
@ -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.location_name = params[:user][:location_name]
|
||||
|
||||
if current_user.save
|
||||
flash[:notice] = t ".success"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
<button type="button" id="home_undelete" class="btn btn-outline-primary" hidden><%= t ".undelete" %></button>
|
||||
</div>
|
||||
</div>
|
||||
<%= f.text_field :location_name, :wrapper_class => "my-2 col-sm-4 pe-3", :class => "mt-auto", :id => "location_name" %>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="updatehome" value="1" <% unless current_user.home_location? %> checked <% end %> id="updatehome" />
|
||||
<label class="form-check-label" for="updatehome"><%= t ".update home location on click" %></label>
|
||||
|
|
|
@ -143,6 +143,16 @@
|
|||
<div class='text-body-secondary'>
|
||||
<small>
|
||||
<dl class="list-inline">
|
||||
<% if @user.location_name && @user.location_name.strip.present? %>
|
||||
<dt class="list-inline-item m-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-geo-alt-fill" viewBox="0 0 16 16">
|
||||
<path d="M8 16s6-5.686 6-10A6 6 0 0 0 2 6c0 4.314 6 10 6 10m0-7a3 3 0 1 1 0-6 3 3 0 0 1 0 6">
|
||||
<title><%= t ".home location" %></title>
|
||||
</path>
|
||||
</svg>
|
||||
</dt>
|
||||
<dd class="list-inline-item"><%= @user.location_name %></dd>
|
||||
<% end %>
|
||||
<dt class="list-inline-item m-0"><%= t ".mapper since" %></dt>
|
||||
<dd class="list-inline-item"><%= l @user.created_at.to_date, :format => :long %></dd>
|
||||
<dt class="list-inline-item m-0"><%= t ".last map edit" %></dt>
|
||||
|
|
|
@ -2882,6 +2882,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:"
|
||||
|
|
5
db/migrate/20241030090336_add_user_location_name.rb
Normal file
5
db/migrate/20241030090336_add_user_location_name.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddUserLocationName < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
add_column :users, :location_name, :string
|
||||
end
|
||||
end
|
|
@ -1513,7 +1513,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
|
||||
);
|
||||
|
||||
|
||||
|
@ -3451,6 +3452,7 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||
('20250121191749'),
|
||||
('20250105154621'),
|
||||
('20250104140952'),
|
||||
('20241030090336'),
|
||||
('20241023004427'),
|
||||
('20241022141247'),
|
||||
('20240913171951'),
|
||||
|
|
|
@ -420,6 +420,21 @@ class GeocoderControllerTest < ActionDispatch::IntegrationTest
|
|||
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
|
||||
result_name_check_json("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
|
||||
result_name_check_json("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
|
||||
result_name_check_json("MM Steak&Grill, ถนนศรีอยุธยา, บางขุนพรหม, กรุงเทพมหานคร, เขตดุสิต, กรุงเทพมหานคร, 10300, ประเทศไทย")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def latlon_check(query, lat, lon)
|
||||
|
@ -484,4 +499,11 @@ class GeocoderControllerTest < ActionDispatch::IntegrationTest
|
|||
assert_template :layout => nil
|
||||
assert_select ".alert.alert-danger", error
|
||||
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
|
||||
|
|
22
test/system/user_location_change_test.rb
Normal file
22
test/system/user_location_change_test.rb
Normal file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue