mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 17:21:38 -05:00
Escape search query
This commit is contained in:
parent
2b1f6d66bc
commit
9967434edc
5 changed files with 43 additions and 16 deletions
|
|
@ -321,7 +321,7 @@ class LocationSearch {
|
||||||
this.resultsContainer.innerHTML = `
|
this.resultsContainer.innerHTML = `
|
||||||
<div class="p-8 text-center">
|
<div class="p-8 text-center">
|
||||||
<div class="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
|
<div class="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
|
||||||
<div class="text-sm text-gray-600 mt-3">Searching for "${this.currentSearchQuery}"...</div>
|
<div class="text-sm text-gray-600 mt-3">Searching for "${this.escapeHtml(this.currentSearchQuery)}"...</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
@ -335,7 +335,7 @@ class LocationSearch {
|
||||||
<div class="p-8 text-center">
|
<div class="p-8 text-center">
|
||||||
<div class="text-4xl mb-3">⚠️</div>
|
<div class="text-4xl mb-3">⚠️</div>
|
||||||
<div class="text-sm font-medium text-red-600 mb-2">Search Failed</div>
|
<div class="text-sm font-medium text-red-600 mb-2">Search Failed</div>
|
||||||
<div class="text-xs text-gray-500">${message}</div>
|
<div class="text-xs text-gray-500">${this.escapeHtml(message)}</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
@ -350,7 +350,7 @@ class LocationSearch {
|
||||||
<div class="p-6 text-center text-gray-500">
|
<div class="p-6 text-center text-gray-500">
|
||||||
<div class="text-3xl mb-3">📍</div>
|
<div class="text-3xl mb-3">📍</div>
|
||||||
<div class="text-sm font-medium">No visits found</div>
|
<div class="text-sm font-medium">No visits found</div>
|
||||||
<div class="text-xs mt-1">No visits found for "${this.currentSearchQuery}"</div>
|
<div class="text-xs mt-1">No visits found for "${this.escapeHtml(this.currentSearchQuery)}"</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
return;
|
return;
|
||||||
|
|
@ -362,7 +362,7 @@ class LocationSearch {
|
||||||
let resultsHtml = `
|
let resultsHtml = `
|
||||||
<div class="p-4 border-b bg-gray-50">
|
<div class="p-4 border-b bg-gray-50">
|
||||||
<div class="text-sm font-medium text-gray-700">Found ${data.total_locations} location(s)</div>
|
<div class="text-sm font-medium text-gray-700">Found ${data.total_locations} location(s)</div>
|
||||||
<div class="text-xs text-gray-500 mt-1">for "${this.currentSearchQuery}"</div>
|
<div class="text-xs text-gray-500 mt-1">for "${this.escapeHtml(this.currentSearchQuery)}"</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,15 @@ module LocationSearch
|
||||||
end
|
end
|
||||||
|
|
||||||
def normalize_geocoding_results(results)
|
def normalize_geocoding_results(results)
|
||||||
normalized_results = results.map do |result|
|
normalized_results = results.filter_map do |result|
|
||||||
|
lat = result.latitude.to_f
|
||||||
|
lon = result.longitude.to_f
|
||||||
|
|
||||||
|
next unless valid_coordinates?(lat, lon)
|
||||||
|
|
||||||
{
|
{
|
||||||
lat: result.latitude.to_f,
|
lat: lat,
|
||||||
lon: result.longitude.to_f,
|
lon: lon,
|
||||||
name: result.address&.split(',')&.first || 'Unknown location',
|
name: result.address&.split(',')&.first || 'Unknown location',
|
||||||
address: result.address || '',
|
address: result.address || '',
|
||||||
type: result.data&.dig('type') || result.data&.dig('class') || 'unknown',
|
type: result.data&.dig('type') || result.data&.dig('class') || 'unknown',
|
||||||
|
|
@ -83,5 +88,9 @@ module LocationSearch
|
||||||
|
|
||||||
distance_km * 1000 # Convert km to meters
|
distance_km * 1000 # Convert km to meters
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def valid_coordinates?(lat, lon)
|
||||||
|
lat.between?(-90, 90) && lon.between?(-180, 180)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ module LocationSearch
|
||||||
end
|
end
|
||||||
|
|
||||||
def call
|
def call
|
||||||
|
return empty_result unless valid_coordinates?
|
||||||
|
|
||||||
location = {
|
location = {
|
||||||
lat: @latitude,
|
lat: @latitude,
|
||||||
lon: @longitude,
|
lon: @longitude,
|
||||||
|
|
@ -103,5 +105,18 @@ module LocationSearch
|
||||||
500 # Default radius for unknown types
|
500 # Default radius for unknown types
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def valid_coordinates?
|
||||||
|
@latitude.present? && @longitude.present? &&
|
||||||
|
@latitude.to_f.between?(-90, 90) && @longitude.to_f.between?(-180, 180)
|
||||||
|
end
|
||||||
|
|
||||||
|
def empty_result
|
||||||
|
{
|
||||||
|
locations: [],
|
||||||
|
total_locations: 0,
|
||||||
|
search_metadata: {}
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,13 @@ RSpec.describe DataMigrations::MigratePointsLatlonJob, type: :job do
|
||||||
it 'updates the lonlat column for all tracked points' do
|
it 'updates the lonlat column for all tracked points' do
|
||||||
user = create(:user)
|
user = create(:user)
|
||||||
point = create(:point, latitude: 2.0, longitude: 1.0, user: user)
|
point = create(:point, latitude: 2.0, longitude: 1.0, user: user)
|
||||||
|
|
||||||
|
# Clear the lonlat to simulate points that need migration
|
||||||
|
point.update_column(:lonlat, nil)
|
||||||
|
|
||||||
expect { subject.perform(user.id) }.to change {
|
expect { subject.perform(user.id) }.to change {
|
||||||
point.reload.lonlat
|
point.reload.lonlat
|
||||||
}.to(RGeo::Geographic.spherical_factory.point(1.0, 2.0))
|
}.from(nil).to(RGeo::Geographic.spherical_factory.point(1.0, 2.0))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ RSpec.describe LocationSearch::PointFinder do
|
||||||
before do
|
before do
|
||||||
allow_any_instance_of(LocationSearch::SpatialMatcher)
|
allow_any_instance_of(LocationSearch::SpatialMatcher)
|
||||||
.to receive(:find_points_near).and_return(mock_matching_points)
|
.to receive(:find_points_near).and_return(mock_matching_points)
|
||||||
|
|
||||||
allow_any_instance_of(LocationSearch::ResultAggregator)
|
allow_any_instance_of(LocationSearch::ResultAggregator)
|
||||||
.to receive(:group_points_into_visits).and_return(mock_visits)
|
.to receive(:group_points_into_visits).and_return(mock_visits)
|
||||||
end
|
end
|
||||||
|
|
@ -62,7 +62,7 @@ RSpec.describe LocationSearch::PointFinder do
|
||||||
|
|
||||||
context 'with custom radius override' do
|
context 'with custom radius override' do
|
||||||
let(:search_params) { { latitude: 52.5200, longitude: 13.4050, radius_override: 150 } }
|
let(:search_params) { { latitude: 52.5200, longitude: 13.4050, radius_override: 150 } }
|
||||||
|
|
||||||
it 'uses custom radius when override provided' do
|
it 'uses custom radius when override provided' do
|
||||||
expect_any_instance_of(LocationSearch::SpatialMatcher)
|
expect_any_instance_of(LocationSearch::SpatialMatcher)
|
||||||
.to receive(:find_points_near)
|
.to receive(:find_points_near)
|
||||||
|
|
@ -101,7 +101,7 @@ RSpec.describe LocationSearch::PointFinder do
|
||||||
before do
|
before do
|
||||||
allow_any_instance_of(LocationSearch::SpatialMatcher)
|
allow_any_instance_of(LocationSearch::SpatialMatcher)
|
||||||
.to receive(:find_points_near).and_return([{}])
|
.to receive(:find_points_near).and_return([{}])
|
||||||
|
|
||||||
allow_any_instance_of(LocationSearch::ResultAggregator)
|
allow_any_instance_of(LocationSearch::ResultAggregator)
|
||||||
.to receive(:group_points_into_visits).and_return(many_visits)
|
.to receive(:group_points_into_visits).and_return(many_visits)
|
||||||
end
|
end
|
||||||
|
|
@ -116,7 +116,7 @@ RSpec.describe LocationSearch::PointFinder do
|
||||||
|
|
||||||
context 'when no matching points found' do
|
context 'when no matching points found' do
|
||||||
let(:search_params) { { latitude: 52.5200, longitude: 13.4050 } }
|
let(:search_params) { { latitude: 52.5200, longitude: 13.4050 } }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow_any_instance_of(LocationSearch::SpatialMatcher)
|
allow_any_instance_of(LocationSearch::SpatialMatcher)
|
||||||
.to receive(:find_points_near).and_return([])
|
.to receive(:find_points_near).and_return([])
|
||||||
|
|
@ -137,7 +137,7 @@ RSpec.describe LocationSearch::PointFinder do
|
||||||
expect(LocationSearch::SpatialMatcher).not_to receive(:new)
|
expect(LocationSearch::SpatialMatcher).not_to receive(:new)
|
||||||
|
|
||||||
result = service.call
|
result = service.call
|
||||||
|
|
||||||
expect(result[:locations]).to be_empty
|
expect(result[:locations]).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -147,7 +147,7 @@ RSpec.describe LocationSearch::PointFinder do
|
||||||
|
|
||||||
it 'returns empty result' do
|
it 'returns empty result' do
|
||||||
result = service.call
|
result = service.call
|
||||||
|
|
||||||
expect(result[:locations]).to be_empty
|
expect(result[:locations]).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -157,9 +157,9 @@ RSpec.describe LocationSearch::PointFinder do
|
||||||
|
|
||||||
it 'returns empty result' do
|
it 'returns empty result' do
|
||||||
result = service.call
|
result = service.call
|
||||||
|
|
||||||
expect(result[:locations]).to be_empty
|
expect(result[:locations]).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue