require 'mime/types' module Adparlor module Facebook module GraphApi class BatchObject < GraphObject attr_accessor :batch_calls def initialize(graph_object) @access_token = graph_object.access_token @batch_calls = { batch: [] } @batch_types = [] @files = {} end def delete(id, klass = nil, options = {}) top_level_access_token(options) relative_url = relative_url(id, klass, options) @batch_types << klass @batch_calls[:batch] << { method: 'DELETE', relative_url: relative_url } nil end def execute content_type_header = @files.any? ? 'multipart/form-data' : 'application/json' response = conn.post full_url('/', {}) do |request| request.headers['Content-Type'] = content_type_header request.params = { access_token: access_token } request.body = @files.any? ? @files.merge(batch: @batch_calls[:batch].to_json) : @batch_calls.to_json end initialize_response(response) end def get(id, klass = nil, options = {}) top_level_access_token(options) relative_url = relative_url(id, klass, options) @batch_types << klass @batch_calls[:batch] << { method: 'GET', relative_url: relative_url } nil end def post(id, klass, attributes = {}, options = {}) top_level_access_token(options) attached_file = attach_file(attributes) name = options.delete(:name) relative_url = relative_url(id, klass, options) body = query_string attributes @batch_types << klass @batch_calls[:batch] << { method: 'POST', relative_url: relative_url, attached_files: attached_file, name: name, body: body }.delete_if { |_, v| v.nil? } nil end private def edge_endpoint(klass) "#{klass.name.split('::').last.downcase}s" end def initialize_response(response) data = [] response.body.each_with_index.map do |result, index| if result.nil? data[index] = nil next end if result.include?('error') data[index] = result.last next end if result['code'] == 200 data[index] = [] body = JSON.parse(result['body']) case when body.key?('data') if body['data'].is_a? Hash data[index] << @batch_types[index].new(body['data']) else body['data'].each { |object| data[index] << @batch_types[index].new(object) } if body['paging'] && body['paging']['next'] data[index] += @batch_types[index].get(body['paging']['next'].delete('\\')) end end when body.key?('images') body['images'].keys.each do |key| data[index] << Adparlor::Facebook::GraphApi::AdImage.new(body['images'][key]) end if body['paging'] && body['paging']['next'] data[index] += Adparlor::Facebook::GraphApi::AdImage.get(body['paging']['next'].delete('\\')) end when body.key?('id') data[index] = @batch_types[index].new(body) else data[index] = body end else data[index] = result end end data end def path(id) return nil unless id id.to_s.include?('act_') ? id : "act_#{id}/" end def relative_url(id, klass, options) api_version = api_version(options) if %r{\A(act_)?\d+\z}.match(id.to_s) path = path(id) edge = edge_endpoint(klass) elsif id.nil? path = "#{options[:id]}" options.delete(:id) edge = '' else path = id edge = '' end query = query_string(options) "#{File.join(api_version, path, edge)}#{query.empty? ? nil : "?#{query}"}" end def top_level_access_token(options) @access_token = options[:access_token] unless @access_token || !options.key?(:access_token) end def query_string(options, depth = nil) depth = 0 unless depth options[:fields] = options[:fields].is_a?(Array) ? options[:fields].map(&:to_s).join(',') : options[:fields] if options.has_key?(:fields) mapped_data = options.map do |k, v| if depth == 0 v.respond_to?(:keys) ? "#{k}={#{query_string(v, depth + 1)}}" : "#{k}=#{v}" else "#{k}:#{v.to_json}" end end if depth == 0 mapped_data.join('&') else mapped_data.join(',') end end end end end end