diff --git a/lib/canvas-api.rb b/lib/canvas-api.rb index fa6351b..f70ac25 100644 --- a/lib/canvas-api.rb +++ b/lib/canvas-api.rb @@ -6,7 +6,7 @@ module Canvas class API - def initialize(args={}) + def initialize(args={}) @host = args[:host] && args[:host].to_s @token = args[:token] && args[:token].to_s @client_id = args[:client_id] && args[:client_id].to_s @@ -18,28 +18,28 @@ def initialize(args={}) raise "token or client_id required" if !@token && !@client_id raise "secret required for client_id configuration" if @client_id && !@secret end - + attr_accessor :host attr_accessor :token attr_accessor :client_id - + def masquerade_as(user_id) @as_user_id = user_id && user_id.to_s end - + def stop_masquerading @as_user_id = nil end - + def self.encode_id(prefix, id) return nil unless prefix && id "hex:#{prefix}:" + id.to_s.unpack("H*")[0] end - + def encode_id(prefix, id) Canvas::API.encode_id(prefix, id) end - + def oauth_url(callback_url, scopes="") raise "client_id required for oauth flow" unless @client_id raise "secret required for oauth flow" unless @secret @@ -49,11 +49,11 @@ def oauth_url(callback_url, scopes="") scopes = scopes.length > 0 ? "&scopes=#{CGI.escape(scopes)}" : "" "#{@host}/login/oauth2/auth?client_id=#{@client_id}&response_type=code&redirect_uri=#{CGI.escape(callback_url)}#{scopes}" end - + def login_url(callback_url) oauth_url(callback_url, "/auth/userinfo") end - + def retrieve_access_token(code, callback_url) raise "client_id required for oauth flow" unless @client_id raise "secret required for oauth flow" unless @secret @@ -67,11 +67,11 @@ def retrieve_access_token(code, callback_url) end res end - + def logout !!delete("/login/oauth2/token")['logged_out'] end - + def validate_call(endpoint) raise "token required for api calls" unless @token raise "missing host" unless @host @@ -80,7 +80,7 @@ def validate_call(endpoint) raise "invalid endpoint" unless endpoint.match(/^\/api\/v\d+\//) unless @token == 'ignore' raise "invalid endpoint" unless (URI.parse(endpoint) rescue nil) end - + def generate_uri(endpoint, params=nil) validate_call(endpoint) unless @token == "ignore" @@ -102,7 +102,7 @@ def generate_uri(endpoint, params=nil) @http.use_ssl = @uri.scheme == 'https' @uri end - + def retrieve_response(request) request.options[:headers]['User-Agent'] = "CanvasAPI Ruby" if @insecure @@ -116,13 +116,18 @@ def retrieve_response(request) end raise ApiError.new("unexpected redirect to #{response.headers['Location']}") if response.code.to_s.match(/3\d\d/) json = JSON.parse(response.body) rescue {'error' => 'invalid JSON'} + + if json.is_a?(Hash) && json.size == 1 && json[json.keys[0]].is_a?(Array) + json = json[json.keys[0]].to_a + end + if !json.is_a?(Array) raise ApiError.new(json['error']) if json['error'] raise ApiError.new(json['errors']) if json['errors'] if !response.code.to_s.match(/2\d\d/) json['message'] ||= "unexpected error" json['status'] ||= response.code.to_s - raise ApiError.new("#{json['status']} #{json['message']}") + raise ApiError.new("#{json['status']} #{json['message']}") end else json = ResultSet.new(self, json) @@ -133,12 +138,12 @@ def retrieve_response(request) end json end - + # Semi-hack so I can write better specs def get_request(endpoint) Typhoeus::Request.new(@uri.to_s, method: :get) end - + def get(endpoint, params=nil) generate_uri(endpoint, params) request = get_request(endpoint) @@ -151,14 +156,14 @@ def delete(endpoint, params={}) request.options[:body] = clean_params(params) retrieve_response(request) end - + def put(endpoint, params={}) generate_uri(endpoint, params['query_parameters'] || params[:query_parameters]) request = Typhoeus::Request.new(@uri.to_s, method: :put) request.options[:body] = clean_params(params) retrieve_response(request) end - + def post(endpoint, params={}) generate_uri(endpoint, params['query_parameters'] || params[:query_parameters]) request = Typhoeus::Request.new(@uri.to_s, method: :post) @@ -194,7 +199,7 @@ def clean_params(params, prefix=nil) end res end - + def upload_file_from_local(endpoint, file, opts={}) raise "Missing File object" unless file.is_a?(File) params = { @@ -208,7 +213,7 @@ def upload_file_from_local(endpoint, file, opts={}) elsif opts[:parent_folder_path] || opts['parent_folder_path'] params[:parent_folder_path] = opts[:parent_folder_path] || opts['parent_folder_path'] end - + res = post(endpoint, params) if !res['upload_url'] raise ApiError.new("Unexpected error: #{res['message'] || 'no upload URL returned'}") @@ -218,7 +223,7 @@ def upload_file_from_local(endpoint, file, opts={}) res = get(status_path) res end - + def multipart_upload(url, upload_params, params, file) req = Typhoeus::Request.new(url, method: :post) upload_params.each do |k, v| @@ -231,7 +236,7 @@ def multipart_upload(url, upload_params, params, file) raise ApiError.new("Unexpected error: #{res.body}") if !res.headers['Location'] res.headers['Location'] end - + def upload_file_from_url(endpoint, opts) asynch = opts.delete('asynch') || opts.delete(:asynch) ['url', 'name', 'size'].each do |k| @@ -273,11 +278,11 @@ def initialize(api, arr) end attr_accessor :next_endpoint attr_accessor :link - + def more? !!next_endpoint end - + def next_page! ResultSet.new(@api, []) unless next_endpoint more = @api.get(next_endpoint) @@ -317,4 +322,4 @@ def recursively_generate_pairs(h, prefix, pairs) end end end -end \ No newline at end of file +end