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