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