Skip to content

Commit 80f7887

Browse files
committed
extends the projects REST API to support the contains parameter #87
- https://<redmine>/projects.[xml|json]?contains=POINT(135.264123%2034.684302)
1 parent 498e3f5 commit 80f7887

File tree

3 files changed

+98
-0
lines changed

3 files changed

+98
-0
lines changed

lib/redmine_gtt/patches/projects_controller_patch.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,22 @@ def self.apply
66
ProjectsController.prepend self unless ProjectsController < self
77
end
88

9+
# overrides index action to add spatial filtering to projects API listing
10+
def index
11+
respond_to do |format|
12+
format.api {
13+
scope = RedmineGtt::SpatialProjectsQuery.new(
14+
contains: params[:contains],
15+
projects: Project.visible.sorted
16+
).scope
17+
@project_count = scope.count
18+
@offset, @limit = api_offset_and_limit
19+
@projects = scope.offset(@offset).limit(@limit).to_a
20+
}
21+
format.any { super }
22+
end
23+
end
24+
925
def show
1026
respond_to do |format|
1127
format.geojson { send_data(
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module RedmineGtt
2+
class SpatialProjectsQuery
3+
def initialize(contains: nil, projects: Project.active.visible)
4+
@contains = contains.presence
5+
@projects = projects
6+
end
7+
8+
QUERY_SQL = (<<-SQL
9+
#{Project.table_name}.geom IS NOT NULL AND
10+
ST_Intersects(#{Project.table_name}.geom, ST_GeomFromText('%s', 4326))
11+
SQL
12+
).freeze
13+
14+
def scope
15+
if @contains
16+
@projects = @projects.where(
17+
Project.send(:sanitize_sql_array, [ QUERY_SQL, @contains ])
18+
)
19+
end
20+
@projects
21+
end
22+
23+
end
24+
end
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
require_relative '../test_helper'
2+
3+
class ProjectsApiTest < Redmine::IntegrationTest
4+
fixtures :users, :email_addresses, :roles, :projects, :members, :member_roles
5+
6+
setup do
7+
User.current = nil
8+
@project = Project.find 'ecookbook'
9+
@project.enabled_modules.create name: 'gtt'
10+
end
11+
12+
test 'should should filter projects by geometry' do
13+
get '/projects.xml'
14+
assert_response :success
15+
xml = xml_data
16+
assert projects = xml.xpath('/projects/project')
17+
assert projects.any?
18+
assert_equal Project.visible.count, projects.size
19+
20+
get '/projects.xml', contains: 'POINT(123.271 9.35)'
21+
assert_response :success
22+
xml = xml_data
23+
assert projects = xml.xpath('/projects/project')
24+
assert_equal 0, projects.size
25+
26+
@project.update_attribute :geojson, {
27+
'type' => 'Feature',
28+
'geometry' => {
29+
'type' => 'Polygon',
30+
'coordinates' => [
31+
[[123.269691,9.305099], [123.279691,9.305099],[123.279691,9.405099],[123.269691,9.405099]]
32+
]
33+
}
34+
}.to_json
35+
36+
assert @project.visible?
37+
38+
get '/projects.xml', contains: 'POINT(123.271 9.55)'
39+
assert_response :success
40+
xml = xml_data
41+
assert projects = xml.xpath('/projects/project')
42+
assert_equal 0, projects.size
43+
44+
get '/projects.xml', contains: 'POINT(123.271 9.35)'
45+
assert_response :success
46+
xml = xml_data
47+
assert projects = xml.xpath('/projects/project')
48+
assert_equal 1, projects.size, xml.to_s
49+
assert_equal 'ecookbook', projects.xpath('identifier').text
50+
51+
end
52+
53+
def xml_data
54+
Nokogiri::XML(@response.body)
55+
end
56+
end
57+
58+

0 commit comments

Comments
 (0)