##// 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 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 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 module Redmine
19 19 module Views
20 20 class ApiTemplateHandler
21 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 23 end
24 24 end
25 25 end
26 26 end
@@ -1,35 +1,35
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 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 module Redmine
19 19 module Views
20 20 module Builders
21 def self.for(format, &block)
21 def self.for(format, request, response, &block)
22 22 builder = case format
23 when 'xml', :xml; Builders::Xml.new
24 when 'json', :json; Builders::Json.new
23 when 'xml', :xml; Builders::Xml.new(request, response)
24 when 'json', :json; Builders::Json.new(request, response)
25 25 else; raise "No builder for format #{format}"
26 26 end
27 27 if block
28 28 block.call(builder)
29 29 else
30 30 builder
31 31 end
32 32 end
33 33 end
34 34 end
35 35 end
@@ -1,30 +1,42
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 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 'blankslate'
19 19
20 20 module Redmine
21 21 module Views
22 22 module Builders
23 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 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 38 end
27 39 end
28 40 end
29 41 end
30 42 end
@@ -1,79 +1,83
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 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 'blankslate'
19 19
20 20 module Redmine
21 21 module Views
22 22 module Builders
23 23 class Structure < BlankSlate
24 def initialize
24 attr_accessor :request, :response
25
26 def initialize(request, response)
25 27 @struct = [{}]
28 self.request = request
29 self.response = response
26 30 end
27 31
28 32 def array(tag, options={}, &block)
29 33 @struct << []
30 34 block.call(self)
31 35 ret = @struct.pop
32 36 @struct.last[tag] = ret
33 37 @struct.last.merge!(options) if options
34 38 end
35 39
36 40 def method_missing(sym, *args, &block)
37 41 if args.any?
38 42 if args.first.is_a?(Hash)
39 43 if @struct.last.is_a?(Array)
40 44 @struct.last << args.first unless block
41 45 else
42 46 @struct.last[sym] = args.first
43 47 end
44 48 else
45 49 if @struct.last.is_a?(Array)
46 50 if args.size == 1 && !block_given?
47 51 @struct.last << args.first
48 52 else
49 53 @struct.last << (args.last || {}).merge(:value => args.first)
50 54 end
51 55 else
52 56 @struct.last[sym] = args.first
53 57 end
54 58 end
55 59 end
56 60
57 61 if block
58 62 @struct << (args.first.is_a?(Hash) ? args.first : {})
59 63 block.call(self)
60 64 ret = @struct.pop
61 65 if @struct.last.is_a?(Array)
62 66 @struct.last << ret
63 67 else
64 68 if @struct.last.has_key?(sym) && @struct.last[sym].is_a?(Hash)
65 69 @struct.last[sym].merge! ret
66 70 else
67 71 @struct.last[sym] = ret
68 72 end
69 73 end
70 74 end
71 75 end
72 76
73 77 def output
74 78 raise "Need to implement #{self.class.name}#output"
75 79 end
76 80 end
77 81 end
78 82 end
79 83 end
@@ -1,47 +1,47
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 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 'builder'
19 19
20 20 module Redmine
21 21 module Views
22 22 module Builders
23 23 class Xml < ::Builder::XmlMarkup
24 def initialize
25 super
24 def initialize(request, response)
25 super()
26 26 instruct!
27 27 end
28 28
29 29 def output
30 30 target!
31 31 end
32 32
33 33 def method_missing(sym, *args, &block)
34 34 if args.size == 1 && args.first.is_a?(::Time)
35 35 __send__ sym, args.first.xmlschema, &block
36 36 else
37 37 super
38 38 end
39 39 end
40 40
41 41 def array(name, options={}, &block)
42 42 __send__ name, (options || {}).merge(:type => 'array'), &block
43 43 end
44 44 end
45 45 end
46 46 end
47 47 end
General Comments 0
You need to be logged in to leave comments. Login now