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