]> git.openstreetmap.org Git - rails.git/blob - test/controllers/api/notes_controller_test.rb
Merge pull request #5019 from tomhughes/oauth2-cleanup
[rails.git] / test / controllers / api / notes_controller_test.rb
1 require "test_helper"
2
3 module Api
4   class NotesControllerTest < ActionDispatch::IntegrationTest
5     def setup
6       super
7       # Stub nominatim response for note locations
8       stub_request(:get, %r{^https://nominatim\.openstreetmap\.org/reverse\?})
9         .to_return(:status => 404)
10     end
11
12     ##
13     # test all routes which lead to this controller
14     def test_routes
15       assert_routing(
16         { :path => "/api/0.6/notes", :method => :post },
17         { :controller => "api/notes", :action => "create" }
18       )
19       assert_routing(
20         { :path => "/api/0.6/notes/1", :method => :get },
21         { :controller => "api/notes", :action => "show", :id => "1" }
22       )
23       assert_recognizes(
24         { :controller => "api/notes", :action => "show", :id => "1", :format => "xml" },
25         { :path => "/api/0.6/notes/1.xml", :method => :get }
26       )
27       assert_routing(
28         { :path => "/api/0.6/notes/1.rss", :method => :get },
29         { :controller => "api/notes", :action => "show", :id => "1", :format => "rss" }
30       )
31       assert_routing(
32         { :path => "/api/0.6/notes/1.json", :method => :get },
33         { :controller => "api/notes", :action => "show", :id => "1", :format => "json" }
34       )
35       assert_routing(
36         { :path => "/api/0.6/notes/1.gpx", :method => :get },
37         { :controller => "api/notes", :action => "show", :id => "1", :format => "gpx" }
38       )
39       assert_routing(
40         { :path => "/api/0.6/notes/1/comment", :method => :post },
41         { :controller => "api/notes", :action => "comment", :id => "1" }
42       )
43       assert_routing(
44         { :path => "/api/0.6/notes/1/close", :method => :post },
45         { :controller => "api/notes", :action => "close", :id => "1" }
46       )
47       assert_routing(
48         { :path => "/api/0.6/notes/1/reopen", :method => :post },
49         { :controller => "api/notes", :action => "reopen", :id => "1" }
50       )
51       assert_routing(
52         { :path => "/api/0.6/notes/1", :method => :delete },
53         { :controller => "api/notes", :action => "destroy", :id => "1" }
54       )
55
56       assert_routing(
57         { :path => "/api/0.6/notes", :method => :get },
58         { :controller => "api/notes", :action => "index" }
59       )
60       assert_recognizes(
61         { :controller => "api/notes", :action => "index", :format => "xml" },
62         { :path => "/api/0.6/notes.xml", :method => :get }
63       )
64       assert_routing(
65         { :path => "/api/0.6/notes.rss", :method => :get },
66         { :controller => "api/notes", :action => "index", :format => "rss" }
67       )
68       assert_routing(
69         { :path => "/api/0.6/notes.json", :method => :get },
70         { :controller => "api/notes", :action => "index", :format => "json" }
71       )
72       assert_routing(
73         { :path => "/api/0.6/notes.gpx", :method => :get },
74         { :controller => "api/notes", :action => "index", :format => "gpx" }
75       )
76
77       assert_routing(
78         { :path => "/api/0.6/notes/search", :method => :get },
79         { :controller => "api/notes", :action => "search" }
80       )
81       assert_recognizes(
82         { :controller => "api/notes", :action => "search", :format => "xml" },
83         { :path => "/api/0.6/notes/search.xml", :method => :get }
84       )
85       assert_routing(
86         { :path => "/api/0.6/notes/search.rss", :method => :get },
87         { :controller => "api/notes", :action => "search", :format => "rss" }
88       )
89       assert_routing(
90         { :path => "/api/0.6/notes/search.json", :method => :get },
91         { :controller => "api/notes", :action => "search", :format => "json" }
92       )
93       assert_routing(
94         { :path => "/api/0.6/notes/search.gpx", :method => :get },
95         { :controller => "api/notes", :action => "search", :format => "gpx" }
96       )
97
98       assert_routing(
99         { :path => "/api/0.6/notes/feed", :method => :get },
100         { :controller => "api/notes", :action => "feed", :format => "rss" }
101       )
102     end
103
104     def test_create_success
105       assert_difference "Note.count", 1 do
106         assert_difference "NoteComment.count", 1 do
107           post api_notes_path(:lat => -1.0, :lon => -1.0, :text => "This is a comment", :format => "json")
108         end
109       end
110       assert_response :success
111       js = ActiveSupport::JSON.decode(@response.body)
112       assert_not_nil js
113       assert_equal "Feature", js["type"]
114       assert_equal "Point", js["geometry"]["type"]
115       assert_equal [-1.0, -1.0], js["geometry"]["coordinates"]
116       assert_equal "open", js["properties"]["status"]
117       assert_equal 1, js["properties"]["comments"].count
118       assert_equal "opened", js["properties"]["comments"].last["action"]
119       assert_equal "This is a comment", js["properties"]["comments"].last["text"]
120       assert_nil js["properties"]["comments"].last["user"]
121       id = js["properties"]["id"]
122
123       get api_note_path(id, :format => "json")
124       assert_response :success
125       js = ActiveSupport::JSON.decode(@response.body)
126       assert_not_nil js
127       assert_equal "Feature", js["type"]
128       assert_equal "Point", js["geometry"]["type"]
129       assert_equal [-1.0, -1.0], js["geometry"]["coordinates"]
130       assert_equal id, js["properties"]["id"]
131       assert_equal "open", js["properties"]["status"]
132       assert_equal 1, js["properties"]["comments"].count
133       assert_equal "opened", js["properties"]["comments"].last["action"]
134       assert_equal "This is a comment", js["properties"]["comments"].last["text"]
135       assert_nil js["properties"]["comments"].last["user"]
136     end
137
138     def test_create_fail
139       assert_no_difference "Note.count" do
140         assert_no_difference "NoteComment.count" do
141           post api_notes_path(:lon => -1.0, :text => "This is a comment")
142         end
143       end
144       assert_response :bad_request
145
146       assert_no_difference "Note.count" do
147         assert_no_difference "NoteComment.count" do
148           post api_notes_path(:lat => -1.0, :text => "This is a comment")
149         end
150       end
151       assert_response :bad_request
152
153       assert_no_difference "Note.count" do
154         assert_no_difference "NoteComment.count" do
155           post api_notes_path(:lat => -1.0, :lon => -1.0)
156         end
157       end
158       assert_response :bad_request
159
160       assert_no_difference "Note.count" do
161         assert_no_difference "NoteComment.count" do
162           post api_notes_path(:lat => -1.0, :lon => -1.0, :text => "")
163         end
164       end
165       assert_response :bad_request
166
167       assert_no_difference "Note.count" do
168         assert_no_difference "NoteComment.count" do
169           post api_notes_path(:lat => -100.0, :lon => -1.0, :text => "This is a comment")
170         end
171       end
172       assert_response :bad_request
173
174       assert_no_difference "Note.count" do
175         assert_no_difference "NoteComment.count" do
176           post api_notes_path(:lat => -1.0, :lon => -200.0, :text => "This is a comment")
177         end
178       end
179       assert_response :bad_request
180
181       assert_no_difference "Note.count" do
182         assert_no_difference "NoteComment.count" do
183           post api_notes_path(:lat => "abc", :lon => -1.0, :text => "This is a comment")
184         end
185       end
186       assert_response :bad_request
187
188       assert_no_difference "Note.count" do
189         assert_no_difference "NoteComment.count" do
190           post api_notes_path(:lat => -1.0, :lon => "abc", :text => "This is a comment")
191         end
192       end
193       assert_response :bad_request
194
195       assert_no_difference "Note.count" do
196         assert_no_difference "NoteComment.count" do
197           post api_notes_path(:lat => -1.0, :lon => -1.0, :text => "x\u0000y")
198         end
199       end
200       assert_response :bad_request
201     end
202
203     def test_comment_success
204       open_note_with_comment = create(:note_with_comments)
205       user = create(:user)
206       auth_header = basic_authorization_header user.email, "test"
207       assert_difference "NoteComment.count", 1 do
208         assert_no_difference "ActionMailer::Base.deliveries.size" do
209           perform_enqueued_jobs do
210             post comment_api_note_path(open_note_with_comment, :text => "This is an additional comment", :format => "json"), :headers => auth_header
211           end
212         end
213       end
214       assert_response :success
215       js = ActiveSupport::JSON.decode(@response.body)
216       assert_not_nil js
217       assert_equal "Feature", js["type"]
218       assert_equal open_note_with_comment.id, js["properties"]["id"]
219       assert_equal "open", js["properties"]["status"]
220       assert_equal 2, js["properties"]["comments"].count
221       assert_equal "commented", js["properties"]["comments"].last["action"]
222       assert_equal "This is an additional comment", js["properties"]["comments"].last["text"]
223       assert_equal user.display_name, js["properties"]["comments"].last["user"]
224
225       get api_note_path(open_note_with_comment, :format => "json")
226       assert_response :success
227       js = ActiveSupport::JSON.decode(@response.body)
228       assert_not_nil js
229       assert_equal "Feature", js["type"]
230       assert_equal open_note_with_comment.id, js["properties"]["id"]
231       assert_equal "open", js["properties"]["status"]
232       assert_equal 2, js["properties"]["comments"].count
233       assert_equal "commented", js["properties"]["comments"].last["action"]
234       assert_equal "This is an additional comment", js["properties"]["comments"].last["text"]
235       assert_equal user.display_name, js["properties"]["comments"].last["user"]
236
237       # Ensure that emails are sent to users
238       first_user = create(:user)
239       second_user = create(:user)
240       third_user = create(:user)
241
242       note_with_comments_by_users = create(:note) do |note|
243         create(:note_comment, :note => note, :author => first_user)
244         create(:note_comment, :note => note, :author => second_user)
245       end
246
247       auth_header = basic_authorization_header third_user.email, "test"
248
249       assert_difference "NoteComment.count", 1 do
250         assert_difference "ActionMailer::Base.deliveries.size", 2 do
251           perform_enqueued_jobs do
252             post comment_api_note_path(note_with_comments_by_users, :text => "This is an additional comment", :format => "json"), :headers => auth_header
253           end
254         end
255       end
256       assert_response :success
257       js = ActiveSupport::JSON.decode(@response.body)
258       assert_not_nil js
259       assert_equal "Feature", js["type"]
260       assert_equal note_with_comments_by_users.id, js["properties"]["id"]
261       assert_equal "open", js["properties"]["status"]
262       assert_equal 3, js["properties"]["comments"].count
263       assert_equal "commented", js["properties"]["comments"].last["action"]
264       assert_equal "This is an additional comment", js["properties"]["comments"].last["text"]
265       assert_equal third_user.display_name, js["properties"]["comments"].last["user"]
266
267       email = ActionMailer::Base.deliveries.find { |e| e.to.first == first_user.email }
268       assert_not_nil email
269       assert_equal 1, email.to.length
270       assert_equal "[OpenStreetMap] #{third_user.display_name} has commented on one of your notes", email.subject
271       assert_equal first_user.email, email.to.first
272
273       email = ActionMailer::Base.deliveries.find { |e| e.to.first == second_user.email }
274       assert_not_nil email
275       assert_equal 1, email.to.length
276       assert_equal "[OpenStreetMap] #{third_user.display_name} has commented on a note you are interested in", email.subject
277
278       get api_note_path(note_with_comments_by_users, :format => "json")
279       assert_response :success
280       js = ActiveSupport::JSON.decode(@response.body)
281       assert_not_nil js
282       assert_equal "Feature", js["type"]
283       assert_equal note_with_comments_by_users.id, js["properties"]["id"]
284       assert_equal "open", js["properties"]["status"]
285       assert_equal 3, js["properties"]["comments"].count
286       assert_equal "commented", js["properties"]["comments"].last["action"]
287       assert_equal "This is an additional comment", js["properties"]["comments"].last["text"]
288       assert_equal third_user.display_name, js["properties"]["comments"].last["user"]
289
290       ActionMailer::Base.deliveries.clear
291     end
292
293     def test_comment_fail
294       open_note_with_comment = create(:note_with_comments)
295
296       user = create(:user)
297
298       assert_no_difference "NoteComment.count" do
299         post comment_api_note_path(open_note_with_comment)
300         assert_response :unauthorized
301       end
302
303       auth_header = basic_authorization_header user.email, "test"
304
305       assert_no_difference "NoteComment.count" do
306         post comment_api_note_path(open_note_with_comment), :headers => auth_header
307       end
308       assert_response :bad_request
309
310       assert_no_difference "NoteComment.count" do
311         post comment_api_note_path(open_note_with_comment, :text => ""), :headers => auth_header
312       end
313       assert_response :bad_request
314
315       assert_no_difference "NoteComment.count" do
316         post comment_api_note_path(12345, :text => "This is an additional comment"), :headers => auth_header
317       end
318       assert_response :not_found
319
320       hidden_note_with_comment = create(:note_with_comments, :status => "hidden")
321
322       assert_no_difference "NoteComment.count" do
323         post comment_api_note_path(hidden_note_with_comment, :text => "This is an additional comment"), :headers => auth_header
324       end
325       assert_response :gone
326
327       closed_note_with_comment = create(:note_with_comments, :closed)
328
329       assert_no_difference "NoteComment.count" do
330         post comment_api_note_path(closed_note_with_comment, :text => "This is an additional comment"), :headers => auth_header
331       end
332       assert_response :conflict
333
334       assert_no_difference "NoteComment.count" do
335         post comment_api_note_path(open_note_with_comment, :text => "x\u0000y"), :headers => auth_header
336       end
337       assert_response :bad_request
338     end
339
340     def test_close_success
341       open_note_with_comment = create(:note_with_comments)
342       user = create(:user)
343
344       post close_api_note_path(open_note_with_comment, :text => "This is a close comment", :format => "json")
345       assert_response :unauthorized
346
347       auth_header = basic_authorization_header user.email, "test"
348
349       post close_api_note_path(open_note_with_comment, :text => "This is a close comment", :format => "json"), :headers => auth_header
350       assert_response :success
351       js = ActiveSupport::JSON.decode(@response.body)
352       assert_not_nil js
353       assert_equal "Feature", js["type"]
354       assert_equal open_note_with_comment.id, js["properties"]["id"]
355       assert_equal "closed", js["properties"]["status"]
356       assert_equal 2, js["properties"]["comments"].count
357       assert_equal "closed", js["properties"]["comments"].last["action"]
358       assert_equal "This is a close comment", js["properties"]["comments"].last["text"]
359       assert_equal user.display_name, js["properties"]["comments"].last["user"]
360
361       get api_note_path(open_note_with_comment.id, :format => "json")
362       assert_response :success
363       js = ActiveSupport::JSON.decode(@response.body)
364       assert_not_nil js
365       assert_equal "Feature", js["type"]
366       assert_equal open_note_with_comment.id, js["properties"]["id"]
367       assert_equal "closed", js["properties"]["status"]
368       assert_equal 2, js["properties"]["comments"].count
369       assert_equal "closed", js["properties"]["comments"].last["action"]
370       assert_equal "This is a close comment", js["properties"]["comments"].last["text"]
371       assert_equal user.display_name, js["properties"]["comments"].last["user"]
372     end
373
374     def test_close_fail
375       post close_api_note_path(12345)
376       assert_response :unauthorized
377
378       auth_header = basic_authorization_header create(:user).email, "test"
379
380       post close_api_note_path(12345), :headers => auth_header
381       assert_response :not_found
382
383       hidden_note_with_comment = create(:note_with_comments, :status => "hidden")
384
385       post close_api_note_path(hidden_note_with_comment), :headers => auth_header
386       assert_response :gone
387
388       closed_note_with_comment = create(:note_with_comments, :closed)
389
390       post close_api_note_path(closed_note_with_comment), :headers => auth_header
391       assert_response :conflict
392     end
393
394     def test_reopen_success
395       closed_note_with_comment = create(:note_with_comments, :closed)
396       user = create(:user)
397
398       post reopen_api_note_path(closed_note_with_comment, :text => "This is a reopen comment", :format => "json")
399       assert_response :unauthorized
400
401       auth_header = basic_authorization_header user.email, "test"
402
403       post reopen_api_note_path(closed_note_with_comment, :text => "This is a reopen comment", :format => "json"), :headers => auth_header
404       assert_response :success
405       js = ActiveSupport::JSON.decode(@response.body)
406       assert_not_nil js
407       assert_equal "Feature", js["type"]
408       assert_equal closed_note_with_comment.id, js["properties"]["id"]
409       assert_equal "open", js["properties"]["status"]
410       assert_equal 3, js["properties"]["comments"].count
411       assert_equal "reopened", js["properties"]["comments"].last["action"]
412       assert_equal "This is a reopen comment", js["properties"]["comments"].last["text"]
413       assert_equal user.display_name, js["properties"]["comments"].last["user"]
414
415       get api_note_path(closed_note_with_comment, :format => "json")
416       assert_response :success
417       js = ActiveSupport::JSON.decode(@response.body)
418       assert_not_nil js
419       assert_equal "Feature", js["type"]
420       assert_equal closed_note_with_comment.id, js["properties"]["id"]
421       assert_equal "open", js["properties"]["status"]
422       assert_equal 3, js["properties"]["comments"].count
423       assert_equal "reopened", js["properties"]["comments"].last["action"]
424       assert_equal "This is a reopen comment", js["properties"]["comments"].last["text"]
425       assert_equal user.display_name, js["properties"]["comments"].last["user"]
426     end
427
428     def test_reopen_fail
429       hidden_note_with_comment = create(:note_with_comments, :status => "hidden")
430
431       post reopen_api_note_path(hidden_note_with_comment)
432       assert_response :unauthorized
433
434       auth_header = basic_authorization_header create(:user).email, "test"
435
436       post reopen_api_note_path(12345), :headers => auth_header
437       assert_response :not_found
438
439       post reopen_api_note_path(hidden_note_with_comment), :headers => auth_header
440       assert_response :gone
441
442       open_note_with_comment = create(:note_with_comments)
443
444       post reopen_api_note_path(open_note_with_comment), :headers => auth_header
445       assert_response :conflict
446     end
447
448     def test_show_success
449       open_note = create(:note_with_comments)
450
451       get api_note_path(open_note, :format => "xml")
452       assert_response :success
453       assert_equal "application/xml", @response.media_type
454       assert_select "osm", :count => 1 do
455         assert_select "note[lat='#{open_note.lat}'][lon='#{open_note.lon}']", :count => 1 do
456           assert_select "id", open_note.id.to_s
457           assert_select "url", api_note_url(open_note, :format => "xml")
458           assert_select "comment_url", comment_api_note_url(open_note, :format => "xml")
459           assert_select "close_url", close_api_note_url(open_note, :format => "xml")
460           assert_select "date_created", open_note.created_at.to_s
461           assert_select "status", open_note.status
462           assert_select "comments", :count => 1 do
463             assert_select "comment", :count => 1
464           end
465         end
466       end
467
468       get api_note_path(open_note, :format => "rss")
469       assert_response :success
470       assert_equal "application/rss+xml", @response.media_type
471       assert_select "rss", :count => 1 do
472         assert_select "channel", :count => 1 do
473           assert_select "item", :count => 1 do
474             assert_select "link", note_url(open_note)
475             assert_select "guid", api_note_url(open_note)
476             assert_select "pubDate", open_note.created_at.to_fs(:rfc822)
477             assert_select "geo|lat", open_note.lat.to_s
478             assert_select "geo|long", open_note.lon.to_s
479             assert_select "georss|point", "#{open_note.lon} #{open_note.lon}"
480           end
481         end
482       end
483
484       get api_note_path(open_note, :format => "json")
485       assert_response :success
486       assert_equal "application/json", @response.media_type
487       js = ActiveSupport::JSON.decode(@response.body)
488       assert_not_nil js
489       assert_equal "Feature", js["type"]
490       assert_equal "Point", js["geometry"]["type"]
491       assert_equal open_note.lat, js["geometry"]["coordinates"][0]
492       assert_equal open_note.lon, js["geometry"]["coordinates"][1]
493       assert_equal open_note.id, js["properties"]["id"]
494       assert_equal api_note_url(open_note, :format => "json"), js["properties"]["url"]
495       assert_equal comment_api_note_url(open_note, :format => "json"), js["properties"]["comment_url"]
496       assert_equal close_api_note_url(open_note, :format => "json"), js["properties"]["close_url"]
497       assert_equal open_note.created_at.to_s, js["properties"]["date_created"]
498       assert_equal open_note.status, js["properties"]["status"]
499
500       get api_note_path(open_note, :format => "gpx")
501       assert_response :success
502       assert_equal "application/gpx+xml", @response.media_type
503       assert_select "gpx", :count => 1 do
504         assert_select "wpt[lat='#{open_note.lat}'][lon='#{open_note.lon}']", :count => 1 do
505           assert_select "time", :count => 1
506           assert_select "name", "Note: #{open_note.id}"
507           assert_select "desc", :count => 1
508           assert_select "link[href='http://www.example.com/note/#{open_note.id}']", :count => 1
509           assert_select "extensions", :count => 1 do
510             assert_select "id", open_note.id.to_s
511             assert_select "url", api_note_url(open_note, :format => "gpx")
512             assert_select "comment_url", comment_api_note_url(open_note, :format => "gpx")
513             assert_select "close_url", close_api_note_url(open_note, :format => "gpx")
514           end
515         end
516       end
517     end
518
519     def test_show_hidden_comment
520       note_with_hidden_comment = create(:note) do |note|
521         create(:note_comment, :note => note, :body => "Valid comment for hidden note")
522         create(:note_comment, :note => note, :visible => false)
523         create(:note_comment, :note => note, :body => "Another valid comment for hidden note")
524       end
525
526       get api_note_path(note_with_hidden_comment, :format => "json")
527       assert_response :success
528       js = ActiveSupport::JSON.decode(@response.body)
529       assert_not_nil js
530       assert_equal "Feature", js["type"]
531       assert_equal note_with_hidden_comment.id, js["properties"]["id"]
532       assert_equal 2, js["properties"]["comments"].count
533       assert_equal "Valid comment for hidden note", js["properties"]["comments"][0]["text"]
534       assert_equal "Another valid comment for hidden note", js["properties"]["comments"][1]["text"]
535     end
536
537     def test_show_fail
538       get api_note_path(12345)
539       assert_response :not_found
540
541       get api_note_path(create(:note, :status => "hidden"))
542       assert_response :gone
543     end
544
545     def test_destroy_success
546       open_note_with_comment = create(:note_with_comments)
547       user = create(:user)
548       moderator_user = create(:moderator_user)
549
550       delete api_note_path(open_note_with_comment, :text => "This is a hide comment", :format => "json")
551       assert_response :unauthorized
552
553       auth_header = basic_authorization_header user.email, "test"
554
555       delete api_note_path(open_note_with_comment, :text => "This is a hide comment", :format => "json"), :headers => auth_header
556       assert_response :forbidden
557
558       auth_header = basic_authorization_header moderator_user.email, "test"
559
560       delete api_note_path(open_note_with_comment, :text => "This is a hide comment", :format => "json"), :headers => auth_header
561       assert_response :success
562       js = ActiveSupport::JSON.decode(@response.body)
563       assert_not_nil js
564       assert_equal "Feature", js["type"]
565       assert_equal open_note_with_comment.id, js["properties"]["id"]
566       assert_equal "hidden", js["properties"]["status"]
567       assert_equal 2, js["properties"]["comments"].count
568       assert_equal "hidden", js["properties"]["comments"].last["action"]
569       assert_equal "This is a hide comment", js["properties"]["comments"].last["text"]
570       assert_equal moderator_user.display_name, js["properties"]["comments"].last["user"]
571
572       get api_note_path(open_note_with_comment, :format => "json"), :headers => auth_header
573       assert_response :success
574
575       auth_header = basic_authorization_header user.email, "test"
576
577       get api_note_path(open_note_with_comment, :format => "json"), :headers => auth_header
578       assert_response :gone
579     end
580
581     def test_destroy_fail
582       user = create(:user)
583       moderator_user = create(:moderator_user)
584
585       delete api_note_path(12345, :format => "json")
586       assert_response :unauthorized
587
588       auth_header = basic_authorization_header user.email, "test"
589
590       delete api_note_path(12345, :format => "json"), :headers => auth_header
591       assert_response :forbidden
592
593       auth_header = basic_authorization_header moderator_user.email, "test"
594
595       delete api_note_path(12345, :format => "json"), :headers => auth_header
596       assert_response :not_found
597
598       hidden_note_with_comment = create(:note_with_comments, :status => "hidden")
599
600       delete api_note_path(hidden_note_with_comment, :format => "json"), :headers => auth_header
601       assert_response :gone
602     end
603
604     def test_index_success
605       position = (1.1 * GeoRecord::SCALE).to_i
606       create(:note_with_comments, :latitude => position, :longitude => position)
607       create(:note_with_comments, :latitude => position, :longitude => position)
608
609       get api_notes_path(:bbox => "1,1,1.2,1.2", :format => "rss")
610       assert_response :success
611       assert_equal "application/rss+xml", @response.media_type
612       assert_select "rss", :count => 1 do
613         assert_select "channel", :count => 1 do
614           assert_select "description", :text => /1\.2/, :count => 1
615           assert_select "item", :count => 2
616         end
617       end
618
619       get api_notes_path(:bbox => "1,1,1.2,1.2", :format => "json")
620       assert_response :success
621       assert_equal "application/json", @response.media_type
622       js = ActiveSupport::JSON.decode(@response.body)
623       assert_not_nil js
624       assert_equal "FeatureCollection", js["type"]
625       assert_equal 2, js["features"].count
626
627       get api_notes_path(:bbox => "1,1,1.2,1.2", :format => "xml")
628       assert_response :success
629       assert_equal "application/xml", @response.media_type
630       assert_select "osm", :count => 1 do
631         assert_select "note", :count => 2
632       end
633
634       get api_notes_path(:bbox => "1,1,1.2,1.2", :format => "gpx")
635       assert_response :success
636       assert_equal "application/gpx+xml", @response.media_type
637       assert_select "gpx", :count => 1 do
638         assert_select "wpt", :count => 2
639       end
640     end
641
642     def test_index_limit
643       position = (1.1 * GeoRecord::SCALE).to_i
644       create(:note_with_comments, :latitude => position, :longitude => position)
645       create(:note_with_comments, :latitude => position, :longitude => position)
646
647       get api_notes_path(:bbox => "1,1,1.2,1.2", :limit => 1, :format => "rss")
648       assert_response :success
649       assert_equal "application/rss+xml", @response.media_type
650       assert_select "rss", :count => 1 do
651         assert_select "channel", :count => 1 do
652           assert_select "item", :count => 1
653         end
654       end
655
656       get api_notes_path(:bbox => "1,1,1.2,1.2", :limit => 1, :format => "json")
657       assert_response :success
658       assert_equal "application/json", @response.media_type
659       js = ActiveSupport::JSON.decode(@response.body)
660       assert_not_nil js
661       assert_equal "FeatureCollection", js["type"]
662       assert_equal 1, js["features"].count
663
664       get api_notes_path(:bbox => "1,1,1.2,1.2", :limit => 1, :format => "xml")
665       assert_response :success
666       assert_equal "application/xml", @response.media_type
667       assert_select "osm", :count => 1 do
668         assert_select "note", :count => 1
669       end
670
671       get api_notes_path(:bbox => "1,1,1.2,1.2", :limit => 1, :format => "gpx")
672       assert_response :success
673       assert_equal "application/gpx+xml", @response.media_type
674       assert_select "gpx", :count => 1 do
675         assert_select "wpt", :count => 1
676       end
677
678       get api_notes_path(:bbox => "1,1,1.2,1.2", :limit => Settings.max_note_query_limit, :format => "rss")
679       assert_response :success
680     end
681
682     def test_index_empty_area
683       get api_notes_path(:bbox => "5,5,5.1,5.1", :format => "rss")
684       assert_response :success
685       assert_equal "application/rss+xml", @response.media_type
686       assert_select "rss", :count => 1 do
687         assert_select "channel", :count => 1 do
688           assert_select "item", :count => 0
689         end
690       end
691
692       get api_notes_path(:bbox => "5,5,5.1,5.1", :format => "json")
693       assert_response :success
694       assert_equal "application/json", @response.media_type
695       js = ActiveSupport::JSON.decode(@response.body)
696       assert_not_nil js
697       assert_equal "FeatureCollection", js["type"]
698       assert_equal 0, js["features"].count
699
700       get api_notes_path(:bbox => "5,5,5.1,5.1", :format => "xml")
701       assert_response :success
702       assert_equal "application/xml", @response.media_type
703       assert_select "osm", :count => 1 do
704         assert_select "note", :count => 0
705       end
706
707       get api_notes_path(:bbox => "5,5,5.1,5.1", :format => "gpx")
708       assert_response :success
709       assert_equal "application/gpx+xml", @response.media_type
710       assert_select "gpx", :count => 1 do
711         assert_select "wpt", :count => 0
712       end
713     end
714
715     def test_index_large_area
716       get api_notes_path(:bbox => "-2.5,-2.5,2.5,2.5", :format => :json)
717       assert_response :success
718       assert_equal "application/json", @response.media_type
719
720       get api_notes_path(:l => "-2.5", :b => "-2.5", :r => "2.5", :t => "2.5", :format => :json)
721       assert_response :success
722       assert_equal "application/json", @response.media_type
723
724       get api_notes_path(:bbox => "-10,-10,12,12", :format => :json)
725       assert_response :bad_request
726       assert_equal "text/plain", @response.media_type
727
728       get api_notes_path(:l => "-10", :b => "-10", :r => "12", :t => "12", :format => :json)
729       assert_response :bad_request
730       assert_equal "text/plain", @response.media_type
731     end
732
733     def test_index_closed
734       create(:note_with_comments, :closed, :closed_at => Time.now.utc - 5.days)
735       create(:note_with_comments, :closed, :closed_at => Time.now.utc - 100.days)
736       create(:note_with_comments, :status => "hidden")
737       create(:note_with_comments)
738
739       # Open notes + closed in last 7 days
740       get api_notes_path(:bbox => "1,1,1.7,1.7", :closed => "7", :format => "json")
741       assert_response :success
742       assert_equal "application/json", @response.media_type
743       js = ActiveSupport::JSON.decode(@response.body)
744       assert_not_nil js
745       assert_equal "FeatureCollection", js["type"]
746       assert_equal 2, js["features"].count
747
748       # Only open notes
749       get api_notes_path(:bbox => "1,1,1.7,1.7", :closed => "0", :format => "json")
750       assert_response :success
751       assert_equal "application/json", @response.media_type
752       js = ActiveSupport::JSON.decode(@response.body)
753       assert_not_nil js
754       assert_equal "FeatureCollection", js["type"]
755       assert_equal 1, js["features"].count
756
757       # Open notes + all closed notes
758       get api_notes_path(:bbox => "1,1,1.7,1.7", :closed => "-1", :format => "json")
759       assert_response :success
760       assert_equal "application/json", @response.media_type
761       js = ActiveSupport::JSON.decode(@response.body)
762       assert_not_nil js
763       assert_equal "FeatureCollection", js["type"]
764       assert_equal 3, js["features"].count
765     end
766
767     def test_index_bad_params
768       get api_notes_path
769       assert_response :bad_request
770       assert_equal "The parameter bbox is required", @response.body
771
772       get api_notes_path(:bbox => "-2.5,-2.5,2.5")
773       assert_response :bad_request
774
775       get api_notes_path(:bbox => "-2.5,-2.5,2.5,2.5,2.5")
776       assert_response :bad_request
777
778       get api_notes_path(:b => "-2.5", :r => "2.5", :t => "2.5")
779       assert_response :bad_request
780
781       get api_notes_path(:l => "-2.5", :r => "2.5", :t => "2.5")
782       assert_response :bad_request
783
784       get api_notes_path(:l => "-2.5", :b => "-2.5", :t => "2.5")
785       assert_response :bad_request
786
787       get api_notes_path(:l => "-2.5", :b => "-2.5", :r => "2.5")
788       assert_response :bad_request
789
790       get api_notes_path(:bbox => "1,1,1.7,1.7", :limit => "0", :format => "json")
791       assert_response :bad_request
792
793       get api_notes_path(:bbox => "1,1,1.7,1.7", :limit => Settings.max_note_query_limit + 1, :format => "json")
794       assert_response :bad_request
795     end
796
797     def test_search_success
798       create(:note_with_comments)
799
800       get search_api_notes_path(:q => "note comment", :format => "xml")
801       assert_response :success
802       assert_equal "application/xml", @response.media_type
803       assert_select "osm", :count => 1 do
804         assert_select "note", :count => 1
805       end
806
807       get search_api_notes_path(:q => "note comment", :format => "json")
808       assert_response :success
809       assert_equal "application/json", @response.media_type
810       js = ActiveSupport::JSON.decode(@response.body)
811       assert_not_nil js
812       assert_equal "FeatureCollection", js["type"]
813       assert_equal 1, js["features"].count
814
815       get search_api_notes_path(:q => "note comment", :format => "rss")
816       assert_response :success
817       assert_equal "application/rss+xml", @response.media_type
818       assert_select "rss", :count => 1 do
819         assert_select "channel", :count => 1 do
820           assert_select "item", :count => 1
821         end
822       end
823
824       get search_api_notes_path(:q => "note comment", :format => "gpx")
825       assert_response :success
826       assert_equal "application/gpx+xml", @response.media_type
827       assert_select "gpx", :count => 1 do
828         assert_select "wpt", :count => 1
829       end
830
831       get search_api_notes_path(:q => "note comment", :limit => Settings.max_note_query_limit, :format => "xml")
832       assert_response :success
833     end
834
835     def test_search_by_display_name_success
836       user = create(:user)
837
838       create(:note) do |note|
839         create(:note_comment, :note => note, :author => user)
840       end
841
842       get search_api_notes_path(:display_name => user.display_name, :format => "xml")
843       assert_response :success
844       assert_equal "application/xml", @response.media_type
845       assert_select "osm", :count => 1 do
846         assert_select "note", :count => 1
847       end
848
849       get search_api_notes_path(:display_name => user.display_name, :format => "json")
850       assert_response :success
851       assert_equal "application/json", @response.media_type
852       js = ActiveSupport::JSON.decode(@response.body)
853       assert_not_nil js
854       assert_equal "FeatureCollection", js["type"]
855       assert_equal 1, js["features"].count
856
857       get search_api_notes_path(:display_name => user.display_name, :format => "rss")
858       assert_response :success
859       assert_equal "application/rss+xml", @response.media_type
860       assert_select "rss", :count => 1 do
861         assert_select "channel", :count => 1 do
862           assert_select "item", :count => 1
863         end
864       end
865
866       get search_api_notes_path(:display_name => user.display_name, :format => "gpx")
867       assert_response :success
868       assert_equal "application/gpx+xml", @response.media_type
869       assert_select "gpx", :count => 1 do
870         assert_select "wpt", :count => 1
871       end
872     end
873
874     def test_search_by_user_success
875       user = create(:user)
876
877       create(:note) do |note|
878         create(:note_comment, :note => note, :author => user)
879       end
880
881       get search_api_notes_path(:user => user.id, :format => "xml")
882       assert_response :success
883       assert_equal "application/xml", @response.media_type
884       assert_select "osm", :count => 1 do
885         assert_select "note", :count => 1
886       end
887
888       get search_api_notes_path(:user => user.id, :format => "json")
889       assert_response :success
890       assert_equal "application/json", @response.media_type
891       js = ActiveSupport::JSON.decode(@response.body)
892       assert_not_nil js
893       assert_equal "FeatureCollection", js["type"]
894       assert_equal 1, js["features"].count
895
896       get search_api_notes_path(:user => user.id, :format => "rss")
897       assert_response :success
898       assert_equal "application/rss+xml", @response.media_type
899       assert_select "rss", :count => 1 do
900         assert_select "channel", :count => 1 do
901           assert_select "item", :count => 1
902         end
903       end
904
905       get search_api_notes_path(:user => user.id, :format => "gpx")
906       assert_response :success
907       assert_equal "application/gpx+xml", @response.media_type
908       assert_select "gpx", :count => 1 do
909         assert_select "wpt", :count => 1
910       end
911     end
912
913     def test_search_by_bbox_success
914       notes = Array.new(5) do |i|
915         position = ((1.0 + (i * 0.1)) * GeoRecord::SCALE).to_i
916         create(:note_with_comments, :created_at => Time.parse("2020-01-01T00:00:00Z") + i.day, :latitude => position, :longitude => position)
917       end
918
919       get search_api_notes_path(:bbox => "1.0,1.0,1.6,1.6", :sort => "created_at", :order => "oldest", :format => "xml")
920       assert_response :success
921       assert_equal "application/xml", @response.media_type
922       assert_notes_in_order notes
923
924       get search_api_notes_path(:bbox => "1.25,1.25,1.45,1.45", :sort => "created_at", :order => "oldest", :format => "xml")
925       assert_response :success
926       assert_equal "application/xml", @response.media_type
927       assert_notes_in_order [notes[3], notes[4]]
928
929       get search_api_notes_path(:bbox => "2.0,2.0,2.5,2.5", :sort => "created_at", :order => "oldest", :format => "xml")
930       assert_response :success
931       assert_equal "application/xml", @response.media_type
932       assert_notes_in_order []
933     end
934
935     def test_search_no_match
936       create(:note_with_comments)
937
938       get search_api_notes_path(:q => "no match", :format => "xml")
939       assert_response :success
940       assert_equal "application/xml", @response.media_type
941       assert_select "osm", :count => 1 do
942         assert_select "note", :count => 0
943       end
944
945       get search_api_notes_path(:q => "no match", :format => "json")
946       assert_response :success
947       assert_equal "application/json", @response.media_type
948       js = ActiveSupport::JSON.decode(@response.body)
949       assert_not_nil js
950       assert_equal "FeatureCollection", js["type"]
951       assert_equal 0, js["features"].count
952
953       get search_api_notes_path(:q => "no match", :format => "rss")
954       assert_response :success
955       assert_equal "application/rss+xml", @response.media_type
956       assert_select "rss", :count => 1 do
957         assert_select "channel", :count => 1 do
958           assert_select "item", :count => 0
959         end
960       end
961
962       get search_api_notes_path(:q => "no match", :format => "gpx")
963       assert_response :success
964       assert_equal "application/gpx+xml", @response.media_type
965       assert_select "gpx", :count => 1 do
966         assert_select "wpt", :count => 0
967       end
968     end
969
970     def test_search_by_time_no_match
971       create(:note_with_comments)
972
973       get search_api_notes_path(:from => "01.01.2010", :to => "01.10.2010", :format => "xml")
974       assert_response :success
975       assert_equal "application/xml", @response.media_type
976       assert_select "osm", :count => 1 do
977         assert_select "note", :count => 0
978       end
979
980       get search_api_notes_path(:from => "01.01.2010", :to => "01.10.2010", :format => "json")
981       assert_response :success
982       assert_equal "application/json", @response.media_type
983       js = ActiveSupport::JSON.decode(@response.body)
984       assert_not_nil js
985       assert_equal "FeatureCollection", js["type"]
986       assert_equal 0, js["features"].count
987
988       get search_api_notes_path(:from => "01.01.2010", :to => "01.10.2010", :format => "rss")
989       assert_response :success
990       assert_equal "application/rss+xml", @response.media_type
991       assert_select "rss", :count => 1 do
992         assert_select "channel", :count => 1 do
993           assert_select "item", :count => 0
994         end
995       end
996
997       get search_api_notes_path(:from => "01.01.2010", :to => "01.10.2010", :format => "gpx")
998       assert_response :success
999       assert_equal "application/gpx+xml", @response.media_type
1000       assert_select "gpx", :count => 1 do
1001         assert_select "wpt", :count => 0
1002       end
1003     end
1004
1005     def test_search_bad_params
1006       get search_api_notes_path(:q => "no match", :limit => "0", :format => "json")
1007       assert_response :bad_request
1008
1009       get search_api_notes_path(:q => "no match", :limit => Settings.max_note_query_limit + 1, :format => "json")
1010       assert_response :bad_request
1011
1012       get search_api_notes_path(:display_name => "non-existent")
1013       assert_response :bad_request
1014
1015       get search_api_notes_path(:user => "-1")
1016       assert_response :bad_request
1017
1018       get search_api_notes_path(:from => "wrong-date", :to => "wrong-date")
1019       assert_response :bad_request
1020
1021       get search_api_notes_path(:from => "01.01.2010", :to => "2010.01.2010")
1022       assert_response :bad_request
1023     end
1024
1025     def test_feed_success
1026       position = (1.1 * GeoRecord::SCALE).to_i
1027       create(:note_with_comments, :latitude => position, :longitude => position)
1028       create(:note_with_comments, :latitude => position, :longitude => position)
1029       position = (1.5 * GeoRecord::SCALE).to_i
1030       create(:note_with_comments, :latitude => position, :longitude => position)
1031       create(:note_with_comments, :latitude => position, :longitude => position)
1032
1033       get feed_api_notes_path(:format => "rss")
1034       assert_response :success
1035       assert_equal "application/rss+xml", @response.media_type
1036       assert_select "rss", :count => 1 do
1037         assert_select "channel", :count => 1 do
1038           assert_select "item", :count => 4
1039         end
1040       end
1041
1042       get feed_api_notes_path(:bbox => "1,1,1.2,1.2", :format => "rss")
1043       assert_response :success
1044       assert_equal "application/rss+xml", @response.media_type
1045       assert_select "rss", :count => 1 do
1046         assert_select "channel", :count => 1 do
1047           assert_select "description", :text => /1\.2/, :count => 1
1048           assert_select "item", :count => 2
1049         end
1050       end
1051
1052       get feed_api_notes_path(:bbox => "1,1,1.2,1.2", :limit => Settings.max_note_query_limit, :format => "rss")
1053       assert_response :success
1054     end
1055
1056     def test_feed_fail
1057       get feed_api_notes_path(:bbox => "1,1,1.2", :format => "rss")
1058       assert_response :bad_request
1059
1060       get feed_api_notes_path(:bbox => "1,1,1.2,1.2,1.2", :format => "rss")
1061       assert_response :bad_request
1062
1063       get feed_api_notes_path(:bbox => "1,1,1.2,1.2", :limit => "0", :format => "rss")
1064       assert_response :bad_request
1065
1066       get feed_api_notes_path(:bbox => "1,1,1.2,1.2", :limit => Settings.max_note_query_limit + 1, :format => "rss")
1067       assert_response :bad_request
1068     end
1069
1070     private
1071
1072     def assert_notes_in_order(notes)
1073       assert_select "osm>note", notes.size
1074       notes.each_with_index do |note, index|
1075         assert_select "osm>note:nth-child(#{index + 1})>id", :text => note.id.to_s, :count => 1
1076       end
1077     end
1078   end
1079 end