##// END OF EJS Templates
Changes the representation of journal details in issue API....
Jean-Philippe Lang -
r4369:ab6a93b029b2
parent child
Show More
@@ -1,59 +1,62
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 18 api.estimated_hours @issue.estimated_hours
19 19 if User.current.allowed_to?(:view_time_entries, @project)
20 20 api.spent_hours @issue.spent_hours
21 21 end
22 22
23 23 render_api_custom_values @issue.custom_field_values, api
24 24
25 25 api.created_on @issue.created_on
26 26 api.updated_on @issue.updated_on
27 27
28 28 render_api_issue_children(@issue, api)
29 29
30 30 api.array :relations do
31 31 @issue.relations.select {|r| r.other_issue(@issue).visible? }.each do |relation|
32 32 api.relation(:id => relation.id, :issue_id => relation.other_issue(@issue).id, :relation_type => relation.relation_type_for(@issue), :delay => relation.delay)
33 33 end
34 34 end
35 35
36 36 api.array :changesets do
37 37 @issue.changesets.each do |changeset|
38 38 api.changeset :revision => changeset.revision do
39 39 api.user(:id => changeset.user_id, :name => changeset.user.name) unless changeset.user.nil?
40 40 api.comments changeset.comments
41 41 api.committed_on changeset.committed_on
42 42 end
43 43 end
44 44 end if User.current.allowed_to?(:view_changesets, @project) && @issue.changesets.any?
45 45
46 46 api.array :journals do
47 47 @issue.journals.each do |journal|
48 48 api.journal :id => journal.id do
49 49 api.user(:id => journal.user_id, :name => journal.user.name) unless journal.user.nil?
50 50 api.notes journal.notes
51 51 api.array :details do
52 52 journal.details.each do |detail|
53 api.detail :property => detail.property, :name => detail.prop_key, :old => detail.old_value, :new => detail.value
53 api.detail :property => detail.property, :name => detail.prop_key do
54 api.old_value detail.old_value
55 api.new_value detail.value
56 end
54 57 end
55 58 end
56 59 end
57 60 end
58 61 end unless @issue.journals.empty?
59 62 end
@@ -1,437 +1,471
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2010 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.dirname(__FILE__)}/../../test_helper"
19 19
20 20 class ApiTest::IssuesTest < ActionController::IntegrationTest
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 :versions,
29 29 :trackers,
30 30 :projects_trackers,
31 31 :issue_categories,
32 32 :enabled_modules,
33 33 :enumerations,
34 34 :attachments,
35 35 :workflows,
36 36 :custom_fields,
37 37 :custom_values,
38 38 :custom_fields_projects,
39 39 :custom_fields_trackers,
40 40 :time_entries,
41 41 :journals,
42 42 :journal_details,
43 43 :queries
44 44
45 45 def setup
46 46 Setting.rest_api_enabled = '1'
47 47 end
48 48
49 49 # Use a private project to make sure auth is really working and not just
50 50 # only showing public issues.
51 51 context "/index.xml" do
52 52 should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
53 53 end
54 54
55 55 context "/index.json" do
56 56 should_allow_api_authentication(:get, "/projects/private-child/issues.json")
57 57 end
58 58
59 59 context "/index.xml with filter" do
60 60 should_allow_api_authentication(:get, "/projects/private-child/issues.xml?status_id=5")
61 61
62 62 should "show only issues with the status_id" do
63 63 get '/issues.xml?status_id=5'
64 64 assert_tag :tag => 'issues',
65 65 :children => { :count => Issue.visible.count(:conditions => {:status_id => 5}),
66 66 :only => { :tag => 'issue' } }
67 67 end
68 68 end
69 69
70 70 context "/index.json with filter" do
71 71 should_allow_api_authentication(:get, "/projects/private-child/issues.json?status_id=5")
72 72
73 73 should "show only issues with the status_id" do
74 74 get '/issues.json?status_id=5'
75 75
76 76 json = ActiveSupport::JSON.decode(response.body)
77 77 status_ids_used = json['issues'].collect {|j| j['status']['id'] }
78 78 assert_equal 3, status_ids_used.length
79 79 assert status_ids_used.all? {|id| id == 5 }
80 80 end
81 81
82 82 end
83 83
84 84 # Issue 6 is on a private project
85 85 context "/issues/6.xml" do
86 86 should_allow_api_authentication(:get, "/issues/6.xml")
87 87 end
88 88
89 89 context "/issues/6.json" do
90 90 should_allow_api_authentication(:get, "/issues/6.json")
91 91 end
92 92
93 93 context "GET /issues/:id" do
94 context "with journals" do
95 context ".xml" do
96 should "display journals" do
97 get '/issues/1.xml'
98
99 assert_tag :tag => 'issue',
100 :child => {
101 :tag => 'journals',
102 :attributes => { :type => 'array' },
103 :child => {
104 :tag => 'journal',
105 :attributes => { :id => '1'},
106 :child => {
107 :tag => 'details',
108 :attributes => { :type => 'array' },
109 :child => {
110 :tag => 'detail',
111 :attributes => { :name => 'status_id' },
112 :child => {
113 :tag => 'old_value',
114 :content => '1',
115 :sibling => {
116 :tag => 'new_value',
117 :content => '2'
118 }
119 }
120 }
121 }
122 }
123 }
124 end
125 end
126 end
127
94 128 context "with custom fields" do
95 129 context ".xml" do
96 130 should "display custom fields" do
97 131 get '/issues/3.xml'
98 132
99 133 assert_tag :tag => 'issue',
100 134 :child => {
101 135 :tag => 'custom_fields',
102 136 :attributes => { :type => 'array' },
103 137 :child => {
104 138 :tag => 'custom_field',
105 139 :attributes => { :id => '1'},
106 140 :child => {
107 141 :tag => 'value',
108 142 :content => 'MySQL'
109 143 }
110 144 }
111 145 }
112 146
113 147 assert_nothing_raised do
114 148 Hash.from_xml(response.body).to_xml
115 149 end
116 150 end
117 151 end
118 152 end
119 153
120 154 context "with subtasks" do
121 155 setup do
122 156 @c1 = Issue.generate!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
123 157 @c2 = Issue.generate!(:status_id => 1, :subject => "child c2", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
124 158 @c3 = Issue.generate!(:status_id => 1, :subject => "child c3", :tracker_id => 1, :project_id => 1, :parent_issue_id => @c1.id)
125 159 end
126 160
127 161 context ".xml" do
128 162 should "display children" do
129 163 get '/issues/1.xml'
130 164
131 165 assert_tag :tag => 'issue',
132 166 :child => {
133 167 :tag => 'children',
134 168 :children => {:count => 2},
135 169 :child => {
136 170 :tag => 'issue',
137 171 :attributes => {:id => @c1.id.to_s},
138 172 :child => {
139 173 :tag => 'subject',
140 174 :content => 'child c1',
141 175 :sibling => {
142 176 :tag => 'children',
143 177 :children => {:count => 1},
144 178 :child => {
145 179 :tag => 'issue',
146 180 :attributes => {:id => @c3.id.to_s}
147 181 }
148 182 }
149 183 }
150 184 }
151 185 }
152 186 end
153 187
154 188 context ".json" do
155 189 should "display children" do
156 190 get '/issues/1.json'
157 191
158 192 json = ActiveSupport::JSON.decode(response.body)
159 193 assert_equal([
160 194 {
161 195 'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'},
162 196 'children' => [{ 'id' => @c3.id, 'subject' => 'child c3', 'tracker' => {'id' => 1, 'name' => 'Bug'} }]
163 197 },
164 198 { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} }
165 199 ],
166 200 json['issue']['children'])
167 201 end
168 202 end
169 203 end
170 204 end
171 205 end
172 206
173 207 context "POST /issues.xml" do
174 208 should_allow_api_authentication(:post,
175 209 '/issues.xml',
176 210 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
177 211 {:success_code => :created})
178 212
179 213 should "create an issue with the attributes" do
180 214 assert_difference('Issue.count') do
181 215 post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
182 216 end
183 217
184 218 issue = Issue.first(:order => 'id DESC')
185 219 assert_equal 1, issue.project_id
186 220 assert_equal 2, issue.tracker_id
187 221 assert_equal 3, issue.status_id
188 222 assert_equal 'API test', issue.subject
189 223
190 224 assert_response :created
191 225 assert_equal 'application/xml', @response.content_type
192 226 assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s}
193 227 end
194 228 end
195 229
196 230 context "POST /issues.xml with failure" do
197 231 should_allow_api_authentication(:post,
198 232 '/issues.xml',
199 233 {:issue => {:project_id => 1}},
200 234 {:success_code => :unprocessable_entity})
201 235
202 236 should "have an errors tag" do
203 237 assert_no_difference('Issue.count') do
204 238 post '/issues.xml', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
205 239 end
206 240
207 241 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
208 242 end
209 243 end
210 244
211 245 context "POST /issues.json" do
212 246 should_allow_api_authentication(:post,
213 247 '/issues.json',
214 248 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
215 249 {:success_code => :created})
216 250
217 251 should "create an issue with the attributes" do
218 252 assert_difference('Issue.count') do
219 253 post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
220 254 end
221 255
222 256 issue = Issue.first(:order => 'id DESC')
223 257 assert_equal 1, issue.project_id
224 258 assert_equal 2, issue.tracker_id
225 259 assert_equal 3, issue.status_id
226 260 assert_equal 'API test', issue.subject
227 261 end
228 262
229 263 end
230 264
231 265 context "POST /issues.json with failure" do
232 266 should_allow_api_authentication(:post,
233 267 '/issues.json',
234 268 {:issue => {:project_id => 1}},
235 269 {:success_code => :unprocessable_entity})
236 270
237 271 should "have an errors element" do
238 272 assert_no_difference('Issue.count') do
239 273 post '/issues.json', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
240 274 end
241 275
242 276 json = ActiveSupport::JSON.decode(response.body)
243 277 assert json['errors'].include?(['subject', "can't be blank"])
244 278 end
245 279 end
246 280
247 281 # Issue 6 is on a private project
248 282 context "PUT /issues/6.xml" do
249 283 setup do
250 284 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
251 285 @headers = { :authorization => credentials('jsmith') }
252 286 end
253 287
254 288 should_allow_api_authentication(:put,
255 289 '/issues/6.xml',
256 290 {:issue => {:subject => 'API update', :notes => 'A new note'}},
257 291 {:success_code => :ok})
258 292
259 293 should "not create a new issue" do
260 294 assert_no_difference('Issue.count') do
261 295 put '/issues/6.xml', @parameters, @headers
262 296 end
263 297 end
264 298
265 299 should "create a new journal" do
266 300 assert_difference('Journal.count') do
267 301 put '/issues/6.xml', @parameters, @headers
268 302 end
269 303 end
270 304
271 305 should "add the note to the journal" do
272 306 put '/issues/6.xml', @parameters, @headers
273 307
274 308 journal = Journal.last
275 309 assert_equal "A new note", journal.notes
276 310 end
277 311
278 312 should "update the issue" do
279 313 put '/issues/6.xml', @parameters, @headers
280 314
281 315 issue = Issue.find(6)
282 316 assert_equal "API update", issue.subject
283 317 end
284 318
285 319 end
286 320
287 321 context "PUT /issues/3.xml with custom fields" do
288 322 setup do
289 323 @parameters = {:issue => {:custom_fields => [{'id' => '1', 'value' => 'PostgreSQL' }, {'id' => '2', 'value' => '150'}]}}
290 324 @headers = { :authorization => credentials('jsmith') }
291 325 end
292 326
293 327 should "update custom fields" do
294 328 assert_no_difference('Issue.count') do
295 329 put '/issues/3.xml', @parameters, @headers
296 330 end
297 331
298 332 issue = Issue.find(3)
299 333 assert_equal '150', issue.custom_value_for(2).value
300 334 assert_equal 'PostgreSQL', issue.custom_value_for(1).value
301 335 end
302 336 end
303 337
304 338 context "PUT /issues/6.xml with failed update" do
305 339 setup do
306 340 @parameters = {:issue => {:subject => ''}}
307 341 @headers = { :authorization => credentials('jsmith') }
308 342 end
309 343
310 344 should_allow_api_authentication(:put,
311 345 '/issues/6.xml',
312 346 {:issue => {:subject => ''}}, # Missing subject should fail
313 347 {:success_code => :unprocessable_entity})
314 348
315 349 should "not create a new issue" do
316 350 assert_no_difference('Issue.count') do
317 351 put '/issues/6.xml', @parameters, @headers
318 352 end
319 353 end
320 354
321 355 should "not create a new journal" do
322 356 assert_no_difference('Journal.count') do
323 357 put '/issues/6.xml', @parameters, @headers
324 358 end
325 359 end
326 360
327 361 should "have an errors tag" do
328 362 put '/issues/6.xml', @parameters, @headers
329 363
330 364 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
331 365 end
332 366 end
333 367
334 368 context "PUT /issues/6.json" do
335 369 setup do
336 370 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
337 371 @headers = { :authorization => credentials('jsmith') }
338 372 end
339 373
340 374 should_allow_api_authentication(:put,
341 375 '/issues/6.json',
342 376 {:issue => {:subject => 'API update', :notes => 'A new note'}},
343 377 {:success_code => :ok})
344 378
345 379 should "not create a new issue" do
346 380 assert_no_difference('Issue.count') do
347 381 put '/issues/6.json', @parameters, @headers
348 382 end
349 383 end
350 384
351 385 should "create a new journal" do
352 386 assert_difference('Journal.count') do
353 387 put '/issues/6.json', @parameters, @headers
354 388 end
355 389 end
356 390
357 391 should "add the note to the journal" do
358 392 put '/issues/6.json', @parameters, @headers
359 393
360 394 journal = Journal.last
361 395 assert_equal "A new note", journal.notes
362 396 end
363 397
364 398 should "update the issue" do
365 399 put '/issues/6.json', @parameters, @headers
366 400
367 401 issue = Issue.find(6)
368 402 assert_equal "API update", issue.subject
369 403 end
370 404
371 405 end
372 406
373 407 context "PUT /issues/6.json with failed update" do
374 408 setup do
375 409 @parameters = {:issue => {:subject => ''}}
376 410 @headers = { :authorization => credentials('jsmith') }
377 411 end
378 412
379 413 should_allow_api_authentication(:put,
380 414 '/issues/6.json',
381 415 {:issue => {:subject => ''}}, # Missing subject should fail
382 416 {:success_code => :unprocessable_entity})
383 417
384 418 should "not create a new issue" do
385 419 assert_no_difference('Issue.count') do
386 420 put '/issues/6.json', @parameters, @headers
387 421 end
388 422 end
389 423
390 424 should "not create a new journal" do
391 425 assert_no_difference('Journal.count') do
392 426 put '/issues/6.json', @parameters, @headers
393 427 end
394 428 end
395 429
396 430 should "have an errors attribute" do
397 431 put '/issues/6.json', @parameters, @headers
398 432
399 433 json = ActiveSupport::JSON.decode(response.body)
400 434 assert json['errors'].include?(['subject', "can't be blank"])
401 435 end
402 436 end
403 437
404 438 context "DELETE /issues/1.xml" do
405 439 should_allow_api_authentication(:delete,
406 440 '/issues/6.xml',
407 441 {},
408 442 {:success_code => :ok})
409 443
410 444 should "delete the issue" do
411 445 assert_difference('Issue.count',-1) do
412 446 delete '/issues/6.xml', {}, :authorization => credentials('jsmith')
413 447 end
414 448
415 449 assert_nil Issue.find_by_id(6)
416 450 end
417 451 end
418 452
419 453 context "DELETE /issues/1.json" do
420 454 should_allow_api_authentication(:delete,
421 455 '/issues/6.json',
422 456 {},
423 457 {:success_code => :ok})
424 458
425 459 should "delete the issue" do
426 460 assert_difference('Issue.count',-1) do
427 461 delete '/issues/6.json', {}, :authorization => credentials('jsmith')
428 462 end
429 463
430 464 assert_nil Issue.find_by_id(6)
431 465 end
432 466 end
433 467
434 468 def credentials(user, password=nil)
435 469 ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
436 470 end
437 471 end
General Comments 0
You need to be logged in to leave comments. Login now