##// END OF EJS Templates
Adds JSONP support to the API (#11469)....
Jean-Philippe Lang -
r9905:3c3bdb8bb07e
parent child
Show More
@@ -0,0 +1,54
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 require File.expand_path('../../../test_helper', __FILE__)
19
20 class ApiTest::JsonpTest < ActionController::IntegrationTest
21 fixtures :trackers
22
23 def test_jsonp_should_accept_callback_param
24 get '/trackers.json?callback=handler'
25
26 assert_response :success
27 assert_match %r{^handler\(\{"trackers":.+\}\)$}, response.body
28 assert_equal 'application/javascript; charset=utf-8', response.headers['Content-Type']
29 end
30
31 def test_jsonp_should_accept_jsonp_param
32 get '/trackers.json?jsonp=handler'
33
34 assert_response :success
35 assert_match %r{^handler\(\{"trackers":.+\}\)$}, response.body
36 assert_equal 'application/javascript; charset=utf-8', response.headers['Content-Type']
37 end
38
39 def test_jsonp_should_strip_invalid_characters_from_callback
40 get '/trackers.json?callback=+-aA$1_'
41
42 assert_response :success
43 assert_match %r{^aA1_\(\{"trackers":.+\}\)$}, response.body
44 assert_equal 'application/javascript; charset=utf-8', response.headers['Content-Type']
45 end
46
47 def test_jsonp_without_callback_should_return_json
48 get '/trackers.json?callback='
49
50 assert_response :success
51 assert_match %r{^\{"trackers":.+\}$}, response.body
52 assert_equal 'application/json; charset=utf-8', response.headers['Content-Type']
53 end
54 end
@@ -1,26 +1,26
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 module Redmine
18 module Redmine
19 module Views
19 module Views
20 class ApiTemplateHandler
20 class ApiTemplateHandler
21 def self.call(template)
21 def self.call(template)
22 "Redmine::Views::Builders.for(params[:format]) do |api|; #{template.source}; self.output_buffer = api.output; end"
22 "Redmine::Views::Builders.for(params[:format], request, response) do |api|; #{template.source}; self.output_buffer = api.output; end"
23 end
23 end
24 end
24 end
25 end
25 end
26 end
26 end
@@ -1,35 +1,35
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 module Redmine
18 module Redmine
19 module Views
19 module Views
20 module Builders
20 module Builders
21 def self.for(format, &block)
21 def self.for(format, request, response, &block)
22 builder = case format
22 builder = case format
23 when 'xml', :xml; Builders::Xml.new
23 when 'xml', :xml; Builders::Xml.new(request, response)
24 when 'json', :json; Builders::Json.new
24 when 'json', :json; Builders::Json.new(request, response)
25 else; raise "No builder for format #{format}"
25 else; raise "No builder for format #{format}"
26 end
26 end
27 if block
27 if block
28 block.call(builder)
28 block.call(builder)
29 else
29 else
30 builder
30 builder
31 end
31 end
32 end
32 end
33 end
33 end
34 end
34 end
35 end
35 end
@@ -1,30 +1,42
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 Json < Structure
23 class Json < Structure
24 attr_accessor :jsonp
25
26 def initialize(request, response)
27 super
28 self.jsonp = (request.params[:callback] || request.params[:jsonp]).to_s.gsub(/[^a-zA-Z0-9_]/, '')
29 end
30
24 def output
31 def output
25 @struct.first.to_json
32 json = @struct.first.to_json
33 if jsonp.present?
34 json = "#{jsonp}(#{json})"
35 response.content_type = 'application/javascript'
36 end
37 json
26 end
38 end
27 end
39 end
28 end
40 end
29 end
41 end
30 end
42 end
@@ -1,79 +1,83
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 def initialize
24 attr_accessor :request, :response
25
26 def initialize(request, response)
25 @struct = [{}]
27 @struct = [{}]
28 self.request = request
29 self.response = response
26 end
30 end
27
31
28 def array(tag, options={}, &block)
32 def array(tag, options={}, &block)
29 @struct << []
33 @struct << []
30 block.call(self)
34 block.call(self)
31 ret = @struct.pop
35 ret = @struct.pop
32 @struct.last[tag] = ret
36 @struct.last[tag] = ret
33 @struct.last.merge!(options) if options
37 @struct.last.merge!(options) if options
34 end
38 end
35
39
36 def method_missing(sym, *args, &block)
40 def method_missing(sym, *args, &block)
37 if args.any?
41 if args.any?
38 if args.first.is_a?(Hash)
42 if args.first.is_a?(Hash)
39 if @struct.last.is_a?(Array)
43 if @struct.last.is_a?(Array)
40 @struct.last << args.first unless block
44 @struct.last << args.first unless block
41 else
45 else
42 @struct.last[sym] = args.first
46 @struct.last[sym] = args.first
43 end
47 end
44 else
48 else
45 if @struct.last.is_a?(Array)
49 if @struct.last.is_a?(Array)
46 if args.size == 1 && !block_given?
50 if args.size == 1 && !block_given?
47 @struct.last << args.first
51 @struct.last << args.first
48 else
52 else
49 @struct.last << (args.last || {}).merge(:value => args.first)
53 @struct.last << (args.last || {}).merge(:value => args.first)
50 end
54 end
51 else
55 else
52 @struct.last[sym] = args.first
56 @struct.last[sym] = args.first
53 end
57 end
54 end
58 end
55 end
59 end
56
60
57 if block
61 if block
58 @struct << (args.first.is_a?(Hash) ? args.first : {})
62 @struct << (args.first.is_a?(Hash) ? args.first : {})
59 block.call(self)
63 block.call(self)
60 ret = @struct.pop
64 ret = @struct.pop
61 if @struct.last.is_a?(Array)
65 if @struct.last.is_a?(Array)
62 @struct.last << ret
66 @struct.last << ret
63 else
67 else
64 if @struct.last.has_key?(sym) && @struct.last[sym].is_a?(Hash)
68 if @struct.last.has_key?(sym) && @struct.last[sym].is_a?(Hash)
65 @struct.last[sym].merge! ret
69 @struct.last[sym].merge! ret
66 else
70 else
67 @struct.last[sym] = ret
71 @struct.last[sym] = ret
68 end
72 end
69 end
73 end
70 end
74 end
71 end
75 end
72
76
73 def output
77 def output
74 raise "Need to implement #{self.class.name}#output"
78 raise "Need to implement #{self.class.name}#output"
75 end
79 end
76 end
80 end
77 end
81 end
78 end
82 end
79 end
83 end
@@ -1,47 +1,47
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 'builder'
18 require 'builder'
19
19
20 module Redmine
20 module Redmine
21 module Views
21 module Views
22 module Builders
22 module Builders
23 class Xml < ::Builder::XmlMarkup
23 class Xml < ::Builder::XmlMarkup
24 def initialize
24 def initialize(request, response)
25 super
25 super()
26 instruct!
26 instruct!
27 end
27 end
28
28
29 def output
29 def output
30 target!
30 target!
31 end
31 end
32
32
33 def method_missing(sym, *args, &block)
33 def method_missing(sym, *args, &block)
34 if args.size == 1 && args.first.is_a?(::Time)
34 if args.size == 1 && args.first.is_a?(::Time)
35 __send__ sym, args.first.xmlschema, &block
35 __send__ sym, args.first.xmlschema, &block
36 else
36 else
37 super
37 super
38 end
38 end
39 end
39 end
40
40
41 def array(name, options={}, &block)
41 def array(name, options={}, &block)
42 __send__ name, (options || {}).merge(:type => 'array'), &block
42 __send__ name, (options || {}).merge(:type => 'array'), &block
43 end
43 end
44 end
44 end
45 end
45 end
46 end
46 end
47 end
47 end
General Comments 0
You need to be logged in to leave comments. Login now