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