##// END OF EJS Templates
Don't include milliseconds in JSON API responses (#19354)....
Jean-Philippe Lang -
r13719:6c5e5142dffd
parent child
Show More
@@ -1,83 +1,94
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'blankslate'
18 require 'blankslate'
19
19
20 module Redmine
20 module Redmine
21 module Views
21 module Views
22 module Builders
22 module Builders
23 class Structure < BlankSlate
23 class Structure < BlankSlate
24 attr_accessor :request, :response
24 attr_accessor :request, :response
25
25
26 def initialize(request, response)
26 def initialize(request, response)
27 @struct = [{}]
27 @struct = [{}]
28 self.request = request
28 self.request = request
29 self.response = response
29 self.response = response
30 end
30 end
31
31
32 def array(tag, options={}, &block)
32 def array(tag, options={}, &block)
33 @struct << []
33 @struct << []
34 block.call(self)
34 block.call(self)
35 ret = @struct.pop
35 ret = @struct.pop
36 @struct.last[tag] = ret
36 @struct.last[tag] = ret
37 @struct.last.merge!(options) if options
37 @struct.last.merge!(options) if options
38 end
38 end
39
39
40 def encode_value(value)
41 if value.is_a?(Time)
42 # Rails uses a global setting to format JSON times
43 # Don't rely on it for the API as it could have been changed
44 value.xmlschema(0)
45 else
46 value
47 end
48 end
49
40 def method_missing(sym, *args, &block)
50 def method_missing(sym, *args, &block)
41 if args.any?
51 if args.any?
42 if args.first.is_a?(Hash)
52 if args.first.is_a?(Hash)
43 if @struct.last.is_a?(Array)
53 if @struct.last.is_a?(Array)
44 @struct.last << args.first unless block
54 @struct.last << args.first unless block
45 else
55 else
46 @struct.last[sym] = args.first
56 @struct.last[sym] = args.first
47 end
57 end
48 else
58 else
59 value = encode_value(args.first)
49 if @struct.last.is_a?(Array)
60 if @struct.last.is_a?(Array)
50 if args.size == 1 && !block_given?
61 if args.size == 1 && !block_given?
51 @struct.last << args.first
62 @struct.last << value
52 else
63 else
53 @struct.last << (args.last || {}).merge(:value => args.first)
64 @struct.last << (args.last || {}).merge(:value => value)
54 end
65 end
55 else
66 else
56 @struct.last[sym] = args.first
67 @struct.last[sym] = value
57 end
68 end
58 end
69 end
59 end
70 end
60
71
61 if block
72 if block
62 @struct << (args.first.is_a?(Hash) ? args.first : {})
73 @struct << (args.first.is_a?(Hash) ? args.first : {})
63 block.call(self)
74 block.call(self)
64 ret = @struct.pop
75 ret = @struct.pop
65 if @struct.last.is_a?(Array)
76 if @struct.last.is_a?(Array)
66 @struct.last << ret
77 @struct.last << ret
67 else
78 else
68 if @struct.last.has_key?(sym) && @struct.last[sym].is_a?(Hash)
79 if @struct.last.has_key?(sym) && @struct.last[sym].is_a?(Hash)
69 @struct.last[sym].merge! ret
80 @struct.last[sym].merge! ret
70 else
81 else
71 @struct.last[sym] = ret
82 @struct.last[sym] = ret
72 end
83 end
73 end
84 end
74 end
85 end
75 end
86 end
76
87
77 def output
88 def output
78 raise "Need to implement #{self.class.name}#output"
89 raise "Need to implement #{self.class.name}#output"
79 end
90 end
80 end
91 end
81 end
92 end
82 end
93 end
83 end
94 end
@@ -1,37 +1,47
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class Redmine::ApiTest::ApiTest < Redmine::ApiTest::Base
20 class Redmine::ApiTest::ApiTest < Redmine::ApiTest::Base
21 fixtures :users
21 fixtures :users
22
22
23 def test_api_should_work_with_protect_from_forgery
23 def test_api_should_work_with_protect_from_forgery
24 ActionController::Base.allow_forgery_protection = true
24 ActionController::Base.allow_forgery_protection = true
25 assert_difference('User.count') do
25 assert_difference('User.count') do
26 post '/users.xml', {
26 post '/users.xml', {
27 :user => {
27 :user => {
28 :login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname',
28 :login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname',
29 :mail => 'foo@example.net', :password => 'secret123'}
29 :mail => 'foo@example.net', :password => 'secret123'}
30 },
30 },
31 credentials('admin')
31 credentials('admin')
32 assert_response 201
32 assert_response 201
33 end
33 end
34 ensure
34 ensure
35 ActionController::Base.allow_forgery_protection = false
35 ActionController::Base.allow_forgery_protection = false
36 end
36 end
37 end No newline at end of file
37
38 def test_json_datetime_format
39 get '/users/1.json', {}, credentials('admin')
40 assert_include '"created_on":"2006-07-19T17:12:21Z"', response.body
41 end
42
43 def test_xml_datetime_format
44 get '/users/1.xml', {}, credentials('admin')
45 assert_include '<created_on>2006-07-19T17:12:21Z</created_on>', response.body
46 end
47 end
General Comments 0
You need to be logged in to leave comments. Login now