use JSON.dump so timestamps load back as Time, and Oj.load for fast loading
[arvados.git] / app / models / orvos_api_client.rb
1 class OrvosApiClient
2   class NotLoggedInException < Exception
3   end
4   def api(resources_kind, action, data=nil)
5     orvos_api_token = Thread.current[:orvos_api_token]
6     orvos_api_token = '' if orvos_api_token.nil?
7     dataargs = ['--data-urlencode',
8                 "api_token=#{orvos_api_token}",
9                 '--header',
10                 'Accept:application/json']
11     if !data.nil?
12       data.each do |k,v|
13         dataargs << '--data-urlencode'
14         if v.is_a? String or v.nil?
15           dataargs << "#{k}=#{v}"
16         elsif v == true or v == false
17           dataargs << "#{k}=#{v ? 1 : 0}"
18         else
19           dataargs << "#{k}=#{JSON.dump(v)}"
20         end
21       end
22     else
23       dataargs << '--data-urlencode' << '_method=GET'
24     end
25     json = nil
26     resources_kind = class_kind(resources_kind).pluralize if resources_kind.is_a? Class
27     url = "#{self.orvos_v1_base}/#{resources_kind}#{action}"
28     IO.popen([ENV,
29               'curl',
30               '-s',
31               *dataargs,
32               url],
33              'r') do |io|
34       json = io.read
35     end
36     resp = Oj.load(json, :symbol_keys => true)
37     if resp[:errors]
38       if resp[:errors][0] == 'Not logged in'
39         raise NotLoggedInException.new
40       else
41         errors = resp[:errors]
42         errors = errors.join("\n\n") if errors.is_a? Array
43         raise "API errors:\n\n#{errors}\n"
44       end
45     end
46     resp
47   end
48
49   def unpack_api_response(j, kind=nil)
50     if j.is_a? Hash and j[:items].is_a? Array and j[:kind].match(/(_list|List)$/)
51       j[:items].collect { |x| unpack_api_response x, j[:kind] }
52     elsif j.is_a? Hash and (kind || j[:kind])
53       oclass = self.kind_class(kind || j[:kind])
54       if oclass
55         j.keys.each do |k|
56           childkind = j["#{k.to_s}_kind".to_sym]
57           if childkind
58             j[k] = self.unpack_api_response(j[k], childkind)
59           end
60         end
61         oclass.new.private_reload(j)
62       else
63         j
64       end
65     else
66       j
67     end
68   end
69
70   def orvos_login_url(params={})
71     if Rails.configuration.respond_to? :orvos_login_base
72       uri = Rails.configuration.orvos_login_base
73     else
74       uri = self.orvos_v1_base.sub(%r{/orvos/v\d+.*}, '/login')
75     end
76     if params.size > 0
77       uri += '?' << params.collect { |k,v|
78         CGI.escape(k.to_s) + '=' + CGI.escape(v.to_s)
79       }.join('&')
80     end
81   end
82
83   def orvos_logout_url(params={})
84     orvos_login_url(params).sub('/login','/logout')
85   end
86
87   def orvos_v1_base
88     Rails.configuration.orvos_v1_base
89   end
90
91   def orvos_schema
92     @orvos_schema ||= api 'schema', ''
93   end
94
95   def kind_class(kind)
96     kind.match(/^orvos\#(.+?)(_list|List)?$/)[1].pluralize.classify.constantize rescue nil
97   end
98
99   def class_kind(resource_class)
100     resource_class.to_s.underscore
101   end
102 end