##// END OF EJS Templates
Issue API: include is_private attribute in xml/json output (#10914)....
Jean-Philippe Lang -
r13032:d30367d46bcf
parent child
Show More
@@ -1,35 +1,36
1 1 api.array :issues, api_meta(:total_count => @issue_count, :offset => @offset, :limit => @limit) do
2 2 @issues.each do |issue|
3 3 api.issue do
4 4 api.id issue.id
5 5 api.project(:id => issue.project_id, :name => issue.project.name) unless issue.project.nil?
6 6 api.tracker(:id => issue.tracker_id, :name => issue.tracker.name) unless issue.tracker.nil?
7 7 api.status(:id => issue.status_id, :name => issue.status.name) unless issue.status.nil?
8 8 api.priority(:id => issue.priority_id, :name => issue.priority.name) unless issue.priority.nil?
9 9 api.author(:id => issue.author_id, :name => issue.author.name) unless issue.author.nil?
10 10 api.assigned_to(:id => issue.assigned_to_id, :name => issue.assigned_to.name) unless issue.assigned_to.nil?
11 11 api.category(:id => issue.category_id, :name => issue.category.name) unless issue.category.nil?
12 12 api.fixed_version(:id => issue.fixed_version_id, :name => issue.fixed_version.name) unless issue.fixed_version.nil?
13 13 api.parent(:id => issue.parent_id) unless issue.parent.nil?
14 14
15 15 api.subject issue.subject
16 16 api.description issue.description
17 17 api.start_date issue.start_date
18 18 api.due_date issue.due_date
19 19 api.done_ratio issue.done_ratio
20 api.is_private issue.is_private
20 21 api.estimated_hours issue.estimated_hours
21 22
22 23 render_api_custom_values issue.visible_custom_field_values, api
23 24
24 25 api.created_on issue.created_on
25 26 api.updated_on issue.updated_on
26 27 api.closed_on issue.closed_on
27 28
28 29 api.array :relations do
29 30 issue.relations.each do |relation|
30 31 api.relation(:id => relation.id, :issue_id => relation.issue_from_id, :issue_to_id => relation.issue_to_id, :relation_type => relation.relation_type, :delay => relation.delay)
31 32 end
32 33 end if include_in_api_response?('relations')
33 34 end
34 35 end
35 36 end
@@ -1,74 +1,75
1 1 api.issue do
2 2 api.id @issue.id
3 3 api.project(:id => @issue.project_id, :name => @issue.project.name) unless @issue.project.nil?
4 4 api.tracker(:id => @issue.tracker_id, :name => @issue.tracker.name) unless @issue.tracker.nil?
5 5 api.status(:id => @issue.status_id, :name => @issue.status.name) unless @issue.status.nil?
6 6 api.priority(:id => @issue.priority_id, :name => @issue.priority.name) unless @issue.priority.nil?
7 7 api.author(:id => @issue.author_id, :name => @issue.author.name) unless @issue.author.nil?
8 8 api.assigned_to(:id => @issue.assigned_to_id, :name => @issue.assigned_to.name) unless @issue.assigned_to.nil?
9 9 api.category(:id => @issue.category_id, :name => @issue.category.name) unless @issue.category.nil?
10 10 api.fixed_version(:id => @issue.fixed_version_id, :name => @issue.fixed_version.name) unless @issue.fixed_version.nil?
11 11 api.parent(:id => @issue.parent_id) unless @issue.parent.nil?
12 12
13 13 api.subject @issue.subject
14 14 api.description @issue.description
15 15 api.start_date @issue.start_date
16 16 api.due_date @issue.due_date
17 17 api.done_ratio @issue.done_ratio
18 api.is_private @issue.is_private
18 19 api.estimated_hours @issue.estimated_hours
19 20 api.spent_hours(@issue.spent_hours) if User.current.allowed_to?(:view_time_entries, @project)
20 21
21 22 render_api_custom_values @issue.visible_custom_field_values, api
22 23
23 24 api.created_on @issue.created_on
24 25 api.updated_on @issue.updated_on
25 26 api.closed_on @issue.closed_on
26 27
27 28 render_api_issue_children(@issue, api) if include_in_api_response?('children')
28 29
29 30 api.array :attachments do
30 31 @issue.attachments.each do |attachment|
31 32 render_api_attachment(attachment, api)
32 33 end
33 34 end if include_in_api_response?('attachments')
34 35
35 36 api.array :relations do
36 37 @relations.each do |relation|
37 38 api.relation(:id => relation.id, :issue_id => relation.issue_from_id, :issue_to_id => relation.issue_to_id, :relation_type => relation.relation_type, :delay => relation.delay)
38 39 end
39 40 end if include_in_api_response?('relations') && @relations.present?
40 41
41 42 api.array :changesets do
42 43 @issue.changesets.each do |changeset|
43 44 api.changeset :revision => changeset.revision do
44 45 api.user(:id => changeset.user_id, :name => changeset.user.name) unless changeset.user.nil?
45 46 api.comments changeset.comments
46 47 api.committed_on changeset.committed_on
47 48 end
48 49 end
49 50 end if include_in_api_response?('changesets') && User.current.allowed_to?(:view_changesets, @project)
50 51
51 52 api.array :journals do
52 53 @journals.each do |journal|
53 54 api.journal :id => journal.id do
54 55 api.user(:id => journal.user_id, :name => journal.user.name) unless journal.user.nil?
55 56 api.notes journal.notes
56 57 api.created_on journal.created_on
57 58 api.array :details do
58 59 journal.visible_details.each do |detail|
59 60 api.detail :property => detail.property, :name => detail.prop_key do
60 61 api.old_value detail.old_value
61 62 api.new_value detail.value
62 63 end
63 64 end
64 65 end
65 66 end
66 67 end
67 68 end if include_in_api_response?('journals')
68 69
69 70 api.array :watchers do
70 71 @issue.watcher_users.each do |user|
71 72 api.user :id => user.id, :name => user.name
72 73 end
73 74 end if include_in_api_response?('watchers') && User.current.allowed_to?(:view_issue_watchers, @issue.project)
74 75 end
@@ -1,869 +1,879
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2014 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../test_helper', __FILE__)
19 19
20 20 class Redmine::ApiTest::IssuesTest < Redmine::ApiTest::Base
21 21 fixtures :projects,
22 22 :users,
23 23 :roles,
24 24 :members,
25 25 :member_roles,
26 26 :issues,
27 27 :issue_statuses,
28 28 :issue_relations,
29 29 :versions,
30 30 :trackers,
31 31 :projects_trackers,
32 32 :issue_categories,
33 33 :enabled_modules,
34 34 :enumerations,
35 35 :attachments,
36 36 :workflows,
37 37 :custom_fields,
38 38 :custom_values,
39 39 :custom_fields_projects,
40 40 :custom_fields_trackers,
41 41 :time_entries,
42 42 :journals,
43 43 :journal_details,
44 44 :queries,
45 45 :attachments
46 46
47 47 def setup
48 48 Setting.rest_api_enabled = '1'
49 49 end
50 50
51 51 context "/issues" do
52 52 # Use a private project to make sure auth is really working and not just
53 53 # only showing public issues.
54 54 should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
55 55
56 56 should "contain metadata" do
57 57 get '/issues.xml'
58 58
59 59 assert_tag :tag => 'issues',
60 60 :attributes => {
61 61 :type => 'array',
62 62 :total_count => assigns(:issue_count),
63 63 :limit => 25,
64 64 :offset => 0
65 65 }
66 66 end
67 67
68 68 context "with offset and limit" do
69 69 should "use the params" do
70 70 get '/issues.xml?offset=2&limit=3'
71 71
72 72 assert_equal 3, assigns(:limit)
73 73 assert_equal 2, assigns(:offset)
74 74 assert_tag :tag => 'issues', :children => {:count => 3, :only => {:tag => 'issue'}}
75 75 end
76 76 end
77 77
78 78 context "with nometa param" do
79 79 should "not contain metadata" do
80 80 get '/issues.xml?nometa=1'
81 81
82 82 assert_tag :tag => 'issues',
83 83 :attributes => {
84 84 :type => 'array',
85 85 :total_count => nil,
86 86 :limit => nil,
87 87 :offset => nil
88 88 }
89 89 end
90 90 end
91 91
92 92 context "with nometa header" do
93 93 should "not contain metadata" do
94 94 get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'}
95 95
96 96 assert_tag :tag => 'issues',
97 97 :attributes => {
98 98 :type => 'array',
99 99 :total_count => nil,
100 100 :limit => nil,
101 101 :offset => nil
102 102 }
103 103 end
104 104 end
105 105
106 106 context "with relations" do
107 107 should "display relations" do
108 108 get '/issues.xml?include=relations'
109 109
110 110 assert_response :success
111 111 assert_equal 'application/xml', @response.content_type
112 112 assert_tag 'relations',
113 113 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '3'}},
114 114 :children => {:count => 1},
115 115 :child => {
116 116 :tag => 'relation',
117 117 :attributes => {:id => '2', :issue_id => '2', :issue_to_id => '3',
118 118 :relation_type => 'relates'}
119 119 }
120 120 assert_tag 'relations',
121 121 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '1'}},
122 122 :children => {:count => 0}
123 123 end
124 124 end
125 125
126 126 context "with invalid query params" do
127 127 should "return errors" do
128 128 get '/issues.xml', {:f => ['start_date'], :op => {:start_date => '='}}
129 129
130 130 assert_response :unprocessable_entity
131 131 assert_equal 'application/xml', @response.content_type
132 132 assert_tag 'errors', :child => {:tag => 'error', :content => "Start date can't be blank"}
133 133 end
134 134 end
135 135
136 136 context "with custom field filter" do
137 137 should "show only issues with the custom field value" do
138 138 get '/issues.xml',
139 139 {:set_filter => 1, :f => ['cf_1'], :op => {:cf_1 => '='},
140 140 :v => {:cf_1 => ['MySQL']}}
141 141 expected_ids = Issue.visible.
142 142 joins(:custom_values).
143 143 where(:custom_values => {:custom_field_id => 1, :value => 'MySQL'}).map(&:id)
144 144 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
145 145 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
146 146 end
147 147 end
148 148 end
149 149
150 150 context "with custom field filter (shorthand method)" do
151 151 should "show only issues with the custom field value" do
152 152 get '/issues.xml', { :cf_1 => 'MySQL' }
153 153
154 154 expected_ids = Issue.visible.
155 155 joins(:custom_values).
156 156 where(:custom_values => {:custom_field_id => 1, :value => 'MySQL'}).map(&:id)
157 157
158 158 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
159 159 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
160 160 end
161 161 end
162 162 end
163 163 end
164 164
165 def test_index_should_include_issue_attributes
166 get '/issues.xml'
167 assert_select 'issues>issue>is_private', :text => 'false'
168 end
169
165 170 def test_index_should_allow_timestamp_filtering
166 171 Issue.delete_all
167 172 Issue.generate!(:subject => '1').update_column(:updated_on, Time.parse("2014-01-02T10:25:00Z"))
168 173 Issue.generate!(:subject => '2').update_column(:updated_on, Time.parse("2014-01-02T12:13:00Z"))
169 174
170 175 get '/issues.xml',
171 176 {:set_filter => 1, :f => ['updated_on'], :op => {:updated_on => '<='},
172 177 :v => {:updated_on => ['2014-01-02T12:00:00Z']}}
173 178 assert_select 'issues>issue', :count => 1
174 179 assert_select 'issues>issue>subject', :text => '1'
175 180
176 181 get '/issues.xml',
177 182 {:set_filter => 1, :f => ['updated_on'], :op => {:updated_on => '>='},
178 183 :v => {:updated_on => ['2014-01-02T12:00:00Z']}}
179 184 assert_select 'issues>issue', :count => 1
180 185 assert_select 'issues>issue>subject', :text => '2'
181 186
182 187 get '/issues.xml',
183 188 {:set_filter => 1, :f => ['updated_on'], :op => {:updated_on => '>='},
184 189 :v => {:updated_on => ['2014-01-02T08:00:00Z']}}
185 190 assert_select 'issues>issue', :count => 2
186 191 end
187 192
188 193 context "/index.json" do
189 194 should_allow_api_authentication(:get, "/projects/private-child/issues.json")
190 195 end
191 196
192 197 context "/index.xml with filter" do
193 198 should "show only issues with the status_id" do
194 199 get '/issues.xml?status_id=5'
195 200
196 201 expected_ids = Issue.visible.where(:status_id => 5).map(&:id)
197 202
198 203 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
199 204 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
200 205 end
201 206 end
202 207 end
203 208
204 209 context "/index.json with filter" do
205 210 should "show only issues with the status_id" do
206 211 get '/issues.json?status_id=5'
207 212
208 213 json = ActiveSupport::JSON.decode(response.body)
209 214 status_ids_used = json['issues'].collect {|j| j['status']['id'] }
210 215 assert_equal 3, status_ids_used.length
211 216 assert status_ids_used.all? {|id| id == 5 }
212 217 end
213 218
214 219 end
215 220
216 221 # Issue 6 is on a private project
217 222 context "/issues/6.xml" do
218 223 should_allow_api_authentication(:get, "/issues/6.xml")
219 224 end
220 225
221 226 context "/issues/6.json" do
222 227 should_allow_api_authentication(:get, "/issues/6.json")
223 228 end
224 229
225 230 context "GET /issues/:id" do
226 231 context "with journals" do
227 232 context ".xml" do
228 233 should "display journals" do
229 234 get '/issues/1.xml?include=journals'
230 235
231 236 assert_tag :tag => 'issue',
232 237 :child => {
233 238 :tag => 'journals',
234 239 :attributes => { :type => 'array' },
235 240 :child => {
236 241 :tag => 'journal',
237 242 :attributes => { :id => '1'},
238 243 :child => {
239 244 :tag => 'details',
240 245 :attributes => { :type => 'array' },
241 246 :child => {
242 247 :tag => 'detail',
243 248 :attributes => { :name => 'status_id' },
244 249 :child => {
245 250 :tag => 'old_value',
246 251 :content => '1',
247 252 :sibling => {
248 253 :tag => 'new_value',
249 254 :content => '2'
250 255 }
251 256 }
252 257 }
253 258 }
254 259 }
255 260 }
256 261 end
257 262 end
258 263 end
259 264
260 265 context "with custom fields" do
261 266 context ".xml" do
262 267 should "display custom fields" do
263 268 get '/issues/3.xml'
264 269
265 270 assert_tag :tag => 'issue',
266 271 :child => {
267 272 :tag => 'custom_fields',
268 273 :attributes => { :type => 'array' },
269 274 :child => {
270 275 :tag => 'custom_field',
271 276 :attributes => { :id => '1'},
272 277 :child => {
273 278 :tag => 'value',
274 279 :content => 'MySQL'
275 280 }
276 281 }
277 282 }
278 283
279 284 assert_nothing_raised do
280 285 Hash.from_xml(response.body).to_xml
281 286 end
282 287 end
283 288 end
284 289 end
285 290
286 291 context "with multi custom fields" do
287 292 setup do
288 293 field = CustomField.find(1)
289 294 field.update_attribute :multiple, true
290 295 issue = Issue.find(3)
291 296 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
292 297 issue.save!
293 298 end
294 299
295 300 context ".xml" do
296 301 should "display custom fields" do
297 302 get '/issues/3.xml'
298 303 assert_response :success
299 304 assert_tag :tag => 'issue',
300 305 :child => {
301 306 :tag => 'custom_fields',
302 307 :attributes => { :type => 'array' },
303 308 :child => {
304 309 :tag => 'custom_field',
305 310 :attributes => { :id => '1'},
306 311 :child => {
307 312 :tag => 'value',
308 313 :attributes => { :type => 'array' },
309 314 :children => { :count => 2 }
310 315 }
311 316 }
312 317 }
313 318
314 319 xml = Hash.from_xml(response.body)
315 320 custom_fields = xml['issue']['custom_fields']
316 321 assert_kind_of Array, custom_fields
317 322 field = custom_fields.detect {|f| f['id'] == '1'}
318 323 assert_kind_of Hash, field
319 324 assert_equal ['MySQL', 'Oracle'], field['value'].sort
320 325 end
321 326 end
322 327
323 328 context ".json" do
324 329 should "display custom fields" do
325 330 get '/issues/3.json'
326 331 assert_response :success
327 332 json = ActiveSupport::JSON.decode(response.body)
328 333 custom_fields = json['issue']['custom_fields']
329 334 assert_kind_of Array, custom_fields
330 335 field = custom_fields.detect {|f| f['id'] == 1}
331 336 assert_kind_of Hash, field
332 337 assert_equal ['MySQL', 'Oracle'], field['value'].sort
333 338 end
334 339 end
335 340 end
336 341
337 342 context "with empty value for multi custom field" do
338 343 setup do
339 344 field = CustomField.find(1)
340 345 field.update_attribute :multiple, true
341 346 issue = Issue.find(3)
342 347 issue.custom_field_values = {1 => ['']}
343 348 issue.save!
344 349 end
345 350
346 351 context ".xml" do
347 352 should "display custom fields" do
348 353 get '/issues/3.xml'
349 354 assert_response :success
350 355 assert_tag :tag => 'issue',
351 356 :child => {
352 357 :tag => 'custom_fields',
353 358 :attributes => { :type => 'array' },
354 359 :child => {
355 360 :tag => 'custom_field',
356 361 :attributes => { :id => '1'},
357 362 :child => {
358 363 :tag => 'value',
359 364 :attributes => { :type => 'array' },
360 365 :children => { :count => 0 }
361 366 }
362 367 }
363 368 }
364 369
365 370 xml = Hash.from_xml(response.body)
366 371 custom_fields = xml['issue']['custom_fields']
367 372 assert_kind_of Array, custom_fields
368 373 field = custom_fields.detect {|f| f['id'] == '1'}
369 374 assert_kind_of Hash, field
370 375 assert_equal [], field['value']
371 376 end
372 377 end
373 378
374 379 context ".json" do
375 380 should "display custom fields" do
376 381 get '/issues/3.json'
377 382 assert_response :success
378 383 json = ActiveSupport::JSON.decode(response.body)
379 384 custom_fields = json['issue']['custom_fields']
380 385 assert_kind_of Array, custom_fields
381 386 field = custom_fields.detect {|f| f['id'] == 1}
382 387 assert_kind_of Hash, field
383 388 assert_equal [], field['value'].sort
384 389 end
385 390 end
386 391 end
387 392
388 393 context "with attachments" do
389 394 context ".xml" do
390 395 should "display attachments" do
391 396 get '/issues/3.xml?include=attachments'
392 397
393 398 assert_tag :tag => 'issue',
394 399 :child => {
395 400 :tag => 'attachments',
396 401 :children => {:count => 5},
397 402 :child => {
398 403 :tag => 'attachment',
399 404 :child => {
400 405 :tag => 'filename',
401 406 :content => 'source.rb',
402 407 :sibling => {
403 408 :tag => 'content_url',
404 409 :content => 'http://www.example.com/attachments/download/4/source.rb'
405 410 }
406 411 }
407 412 }
408 413 }
409 414 end
410 415 end
411 416 end
412 417
413 418 context "with subtasks" do
414 419 setup do
415 420 @c1 = Issue.create!(
416 421 :status_id => 1, :subject => "child c1",
417 422 :tracker_id => 1, :project_id => 1, :author_id => 1,
418 423 :parent_issue_id => 1
419 424 )
420 425 @c2 = Issue.create!(
421 426 :status_id => 1, :subject => "child c2",
422 427 :tracker_id => 1, :project_id => 1, :author_id => 1,
423 428 :parent_issue_id => 1
424 429 )
425 430 @c3 = Issue.create!(
426 431 :status_id => 1, :subject => "child c3",
427 432 :tracker_id => 1, :project_id => 1, :author_id => 1,
428 433 :parent_issue_id => @c1.id
429 434 )
430 435 end
431 436
432 437 context ".xml" do
433 438 should "display children" do
434 439 get '/issues/1.xml?include=children'
435 440
436 441 assert_tag :tag => 'issue',
437 442 :child => {
438 443 :tag => 'children',
439 444 :children => {:count => 2},
440 445 :child => {
441 446 :tag => 'issue',
442 447 :attributes => {:id => @c1.id.to_s},
443 448 :child => {
444 449 :tag => 'subject',
445 450 :content => 'child c1',
446 451 :sibling => {
447 452 :tag => 'children',
448 453 :children => {:count => 1},
449 454 :child => {
450 455 :tag => 'issue',
451 456 :attributes => {:id => @c3.id.to_s}
452 457 }
453 458 }
454 459 }
455 460 }
456 461 }
457 462 end
458 463
459 464 context ".json" do
460 465 should "display children" do
461 466 get '/issues/1.json?include=children'
462 467
463 468 json = ActiveSupport::JSON.decode(response.body)
464 469 assert_equal([
465 470 {
466 471 'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'},
467 472 'children' => [{'id' => @c3.id, 'subject' => 'child c3',
468 473 'tracker' => {'id' => 1, 'name' => 'Bug'} }]
469 474 },
470 475 { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} }
471 476 ],
472 477 json['issue']['children'])
473 478 end
474 479 end
475 480 end
476 481 end
477 482 end
478 483
484 def test_show_should_include_issue_attributes
485 get '/issues/1.xml'
486 assert_select 'issue>is_private', :text => 'false'
487 end
488
479 489 test "GET /issues/:id.xml?include=watchers should include watchers" do
480 490 Watcher.create!(:user_id => 3, :watchable => Issue.find(1))
481 491
482 492 get '/issues/1.xml?include=watchers', {}, credentials('jsmith')
483 493
484 494 assert_response :ok
485 495 assert_equal 'application/xml', response.content_type
486 496 assert_select 'issue' do
487 497 assert_select 'watchers', Issue.find(1).watchers.count
488 498 assert_select 'watchers' do
489 499 assert_select 'user[id=3]'
490 500 end
491 501 end
492 502 end
493 503
494 504 context "POST /issues.xml" do
495 505 should_allow_api_authentication(
496 506 :post,
497 507 '/issues.xml',
498 508 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
499 509 {:success_code => :created}
500 510 )
501 511 should "create an issue with the attributes" do
502 512 assert_difference('Issue.count') do
503 513 post '/issues.xml',
504 514 {:issue => {:project_id => 1, :subject => 'API test',
505 515 :tracker_id => 2, :status_id => 3}}, credentials('jsmith')
506 516 end
507 517 issue = Issue.order('id DESC').first
508 518 assert_equal 1, issue.project_id
509 519 assert_equal 2, issue.tracker_id
510 520 assert_equal 3, issue.status_id
511 521 assert_equal 'API test', issue.subject
512 522
513 523 assert_response :created
514 524 assert_equal 'application/xml', @response.content_type
515 525 assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s}
516 526 end
517 527 end
518 528
519 529 test "POST /issues.xml with watcher_user_ids should create issue with watchers" do
520 530 assert_difference('Issue.count') do
521 531 post '/issues.xml',
522 532 {:issue => {:project_id => 1, :subject => 'Watchers',
523 533 :tracker_id => 2, :status_id => 3, :watcher_user_ids => [3, 1]}}, credentials('jsmith')
524 534 assert_response :created
525 535 end
526 536 issue = Issue.order('id desc').first
527 537 assert_equal 2, issue.watchers.size
528 538 assert_equal [1, 3], issue.watcher_user_ids.sort
529 539 end
530 540
531 541 context "POST /issues.xml with failure" do
532 542 should "have an errors tag" do
533 543 assert_no_difference('Issue.count') do
534 544 post '/issues.xml', {:issue => {:project_id => 1}}, credentials('jsmith')
535 545 end
536 546
537 547 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
538 548 end
539 549 end
540 550
541 551 context "POST /issues.json" do
542 552 should_allow_api_authentication(:post,
543 553 '/issues.json',
544 554 {:issue => {:project_id => 1, :subject => 'API test',
545 555 :tracker_id => 2, :status_id => 3}},
546 556 {:success_code => :created})
547 557
548 558 should "create an issue with the attributes" do
549 559 assert_difference('Issue.count') do
550 560 post '/issues.json',
551 561 {:issue => {:project_id => 1, :subject => 'API test',
552 562 :tracker_id => 2, :status_id => 3}},
553 563 credentials('jsmith')
554 564 end
555 565
556 566 issue = Issue.order('id DESC').first
557 567 assert_equal 1, issue.project_id
558 568 assert_equal 2, issue.tracker_id
559 569 assert_equal 3, issue.status_id
560 570 assert_equal 'API test', issue.subject
561 571 end
562 572
563 573 end
564 574
565 575 context "POST /issues.json with failure" do
566 576 should "have an errors element" do
567 577 assert_no_difference('Issue.count') do
568 578 post '/issues.json', {:issue => {:project_id => 1}}, credentials('jsmith')
569 579 end
570 580
571 581 json = ActiveSupport::JSON.decode(response.body)
572 582 assert json['errors'].include?("Subject can't be blank")
573 583 end
574 584 end
575 585
576 586 # Issue 6 is on a private project
577 587 context "PUT /issues/6.xml" do
578 588 setup do
579 589 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
580 590 end
581 591
582 592 should_allow_api_authentication(:put,
583 593 '/issues/6.xml',
584 594 {:issue => {:subject => 'API update', :notes => 'A new note'}},
585 595 {:success_code => :ok})
586 596
587 597 should "not create a new issue" do
588 598 assert_no_difference('Issue.count') do
589 599 put '/issues/6.xml', @parameters, credentials('jsmith')
590 600 end
591 601 end
592 602
593 603 should "create a new journal" do
594 604 assert_difference('Journal.count') do
595 605 put '/issues/6.xml', @parameters, credentials('jsmith')
596 606 end
597 607 end
598 608
599 609 should "add the note to the journal" do
600 610 put '/issues/6.xml', @parameters, credentials('jsmith')
601 611
602 612 journal = Journal.last
603 613 assert_equal "A new note", journal.notes
604 614 end
605 615
606 616 should "update the issue" do
607 617 put '/issues/6.xml', @parameters, credentials('jsmith')
608 618
609 619 issue = Issue.find(6)
610 620 assert_equal "API update", issue.subject
611 621 end
612 622
613 623 end
614 624
615 625 context "PUT /issues/3.xml with custom fields" do
616 626 setup do
617 627 @parameters = {
618 628 :issue => {:custom_fields => [{'id' => '1', 'value' => 'PostgreSQL' },
619 629 {'id' => '2', 'value' => '150'}]}
620 630 }
621 631 end
622 632
623 633 should "update custom fields" do
624 634 assert_no_difference('Issue.count') do
625 635 put '/issues/3.xml', @parameters, credentials('jsmith')
626 636 end
627 637
628 638 issue = Issue.find(3)
629 639 assert_equal '150', issue.custom_value_for(2).value
630 640 assert_equal 'PostgreSQL', issue.custom_value_for(1).value
631 641 end
632 642 end
633 643
634 644 context "PUT /issues/3.xml with multi custom fields" do
635 645 setup do
636 646 field = CustomField.find(1)
637 647 field.update_attribute :multiple, true
638 648 @parameters = {
639 649 :issue => {:custom_fields => [{'id' => '1', 'value' => ['MySQL', 'PostgreSQL'] },
640 650 {'id' => '2', 'value' => '150'}]}
641 651 }
642 652 end
643 653
644 654 should "update custom fields" do
645 655 assert_no_difference('Issue.count') do
646 656 put '/issues/3.xml', @parameters, credentials('jsmith')
647 657 end
648 658
649 659 issue = Issue.find(3)
650 660 assert_equal '150', issue.custom_value_for(2).value
651 661 assert_equal ['MySQL', 'PostgreSQL'], issue.custom_field_value(1).sort
652 662 end
653 663 end
654 664
655 665 context "PUT /issues/3.xml with project change" do
656 666 setup do
657 667 @parameters = {:issue => {:project_id => 2, :subject => 'Project changed'}}
658 668 end
659 669
660 670 should "update project" do
661 671 assert_no_difference('Issue.count') do
662 672 put '/issues/3.xml', @parameters, credentials('jsmith')
663 673 end
664 674
665 675 issue = Issue.find(3)
666 676 assert_equal 2, issue.project_id
667 677 assert_equal 'Project changed', issue.subject
668 678 end
669 679 end
670 680
671 681 context "PUT /issues/6.xml with failed update" do
672 682 setup do
673 683 @parameters = {:issue => {:subject => ''}}
674 684 end
675 685
676 686 should "not create a new issue" do
677 687 assert_no_difference('Issue.count') do
678 688 put '/issues/6.xml', @parameters, credentials('jsmith')
679 689 end
680 690 end
681 691
682 692 should "not create a new journal" do
683 693 assert_no_difference('Journal.count') do
684 694 put '/issues/6.xml', @parameters, credentials('jsmith')
685 695 end
686 696 end
687 697
688 698 should "have an errors tag" do
689 699 put '/issues/6.xml', @parameters, credentials('jsmith')
690 700
691 701 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
692 702 end
693 703 end
694 704
695 705 context "PUT /issues/6.json" do
696 706 setup do
697 707 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
698 708 end
699 709
700 710 should_allow_api_authentication(:put,
701 711 '/issues/6.json',
702 712 {:issue => {:subject => 'API update', :notes => 'A new note'}},
703 713 {:success_code => :ok})
704 714
705 715 should "update the issue" do
706 716 assert_no_difference('Issue.count') do
707 717 assert_difference('Journal.count') do
708 718 put '/issues/6.json', @parameters, credentials('jsmith')
709 719
710 720 assert_response :ok
711 721 assert_equal '', response.body
712 722 end
713 723 end
714 724
715 725 issue = Issue.find(6)
716 726 assert_equal "API update", issue.subject
717 727 journal = Journal.last
718 728 assert_equal "A new note", journal.notes
719 729 end
720 730 end
721 731
722 732 context "PUT /issues/6.json with failed update" do
723 733 should "return errors" do
724 734 assert_no_difference('Issue.count') do
725 735 assert_no_difference('Journal.count') do
726 736 put '/issues/6.json', {:issue => {:subject => ''}}, credentials('jsmith')
727 737
728 738 assert_response :unprocessable_entity
729 739 end
730 740 end
731 741
732 742 json = ActiveSupport::JSON.decode(response.body)
733 743 assert json['errors'].include?("Subject can't be blank")
734 744 end
735 745 end
736 746
737 747 context "DELETE /issues/1.xml" do
738 748 should_allow_api_authentication(:delete,
739 749 '/issues/6.xml',
740 750 {},
741 751 {:success_code => :ok})
742 752
743 753 should "delete the issue" do
744 754 assert_difference('Issue.count', -1) do
745 755 delete '/issues/6.xml', {}, credentials('jsmith')
746 756
747 757 assert_response :ok
748 758 assert_equal '', response.body
749 759 end
750 760
751 761 assert_nil Issue.find_by_id(6)
752 762 end
753 763 end
754 764
755 765 context "DELETE /issues/1.json" do
756 766 should_allow_api_authentication(:delete,
757 767 '/issues/6.json',
758 768 {},
759 769 {:success_code => :ok})
760 770
761 771 should "delete the issue" do
762 772 assert_difference('Issue.count', -1) do
763 773 delete '/issues/6.json', {}, credentials('jsmith')
764 774
765 775 assert_response :ok
766 776 assert_equal '', response.body
767 777 end
768 778
769 779 assert_nil Issue.find_by_id(6)
770 780 end
771 781 end
772 782
773 783 test "POST /issues/:id/watchers.xml should add watcher" do
774 784 assert_difference 'Watcher.count' do
775 785 post '/issues/1/watchers.xml', {:user_id => 3}, credentials('jsmith')
776 786
777 787 assert_response :ok
778 788 assert_equal '', response.body
779 789 end
780 790 watcher = Watcher.order('id desc').first
781 791 assert_equal Issue.find(1), watcher.watchable
782 792 assert_equal User.find(3), watcher.user
783 793 end
784 794
785 795 test "DELETE /issues/:id/watchers/:user_id.xml should remove watcher" do
786 796 Watcher.create!(:user_id => 3, :watchable => Issue.find(1))
787 797
788 798 assert_difference 'Watcher.count', -1 do
789 799 delete '/issues/1/watchers/3.xml', {}, credentials('jsmith')
790 800
791 801 assert_response :ok
792 802 assert_equal '', response.body
793 803 end
794 804 assert_equal false, Issue.find(1).watched_by?(User.find(3))
795 805 end
796 806
797 807 def test_create_issue_with_uploaded_file
798 808 set_tmp_attachments_directory
799 809 # upload the file
800 810 assert_difference 'Attachment.count' do
801 811 post '/uploads.xml', 'test_create_with_upload',
802 812 {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
803 813 assert_response :created
804 814 end
805 815 xml = Hash.from_xml(response.body)
806 816 token = xml['upload']['token']
807 817 attachment = Attachment.order('id DESC').first
808 818
809 819 # create the issue with the upload's token
810 820 assert_difference 'Issue.count' do
811 821 post '/issues.xml',
812 822 {:issue => {:project_id => 1, :subject => 'Uploaded file',
813 823 :uploads => [{:token => token, :filename => 'test.txt',
814 824 :content_type => 'text/plain'}]}},
815 825 credentials('jsmith')
816 826 assert_response :created
817 827 end
818 828 issue = Issue.order('id DESC').first
819 829 assert_equal 1, issue.attachments.count
820 830 assert_equal attachment, issue.attachments.first
821 831
822 832 attachment.reload
823 833 assert_equal 'test.txt', attachment.filename
824 834 assert_equal 'text/plain', attachment.content_type
825 835 assert_equal 'test_create_with_upload'.size, attachment.filesize
826 836 assert_equal 2, attachment.author_id
827 837
828 838 # get the issue with its attachments
829 839 get "/issues/#{issue.id}.xml", :include => 'attachments'
830 840 assert_response :success
831 841 xml = Hash.from_xml(response.body)
832 842 attachments = xml['issue']['attachments']
833 843 assert_kind_of Array, attachments
834 844 assert_equal 1, attachments.size
835 845 url = attachments.first['content_url']
836 846 assert_not_nil url
837 847
838 848 # download the attachment
839 849 get url
840 850 assert_response :success
841 851 end
842 852
843 853 def test_update_issue_with_uploaded_file
844 854 set_tmp_attachments_directory
845 855 # upload the file
846 856 assert_difference 'Attachment.count' do
847 857 post '/uploads.xml', 'test_upload_with_upload',
848 858 {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
849 859 assert_response :created
850 860 end
851 861 xml = Hash.from_xml(response.body)
852 862 token = xml['upload']['token']
853 863 attachment = Attachment.order('id DESC').first
854 864
855 865 # update the issue with the upload's token
856 866 assert_difference 'Journal.count' do
857 867 put '/issues/1.xml',
858 868 {:issue => {:notes => 'Attachment added',
859 869 :uploads => [{:token => token, :filename => 'test.txt',
860 870 :content_type => 'text/plain'}]}},
861 871 credentials('jsmith')
862 872 assert_response :ok
863 873 assert_equal '', @response.body
864 874 end
865 875
866 876 issue = Issue.find(1)
867 877 assert_include attachment, issue.attachments
868 878 end
869 879 end
General Comments 0
You need to be logged in to leave comments. Login now